Back home

Nell'era della pubblicazione ad alta frequenza, la distribuzione front-end necessita di riprogettare la memorizzazione nella cache e la collaborazione di compressione

Man mano che le risorse diventano sempre più frammentate e le versioni diventano sempre più frequenti, spesso non è il tasso di compressione a sfuggire per primo al controllo, ma il ritmo di rilascio delle chiavi di cache, delle versioni del dizionario e i costi di ritorno all'origine.

Una volta che le risorse front-end entrano in un ritmo di rilascio ad alta frequenza, presto i problemi di prestazioni non saranno più semplici come “accendere Brotli”. La prima schermata rallenta, il traffico di ritorno all’origine aumenta e la CPU del nodo periferico trema. In superficie sembra che la compressione non sia abbastanza aggressiva. Guardando più in profondità, spesso sono la memorizzazione nella cache e la compressione a essere ottimizzate separatamente e alla fine a indebolirsi a vicenda nel collegamento di pubblicazione.

Questo tipo di problema generalmente non viene esposto nella prima versione. All’inizio il team avrebbe visto solo alcuni segnali sparsi: un piccolo cambiamento ha causato un crollo dell’hit rate delle risorse statiche, un aumento anomalo dell’edge compression della CPU alla vigilia di una grande promozione e il volume dei pacchetti di ritorno nella fase in scala di grigi non corrispondeva al traffico ufficiale. Se continui a controllare, gli indizi di solito convergono verso la stessa cosa: sebbene il contenuto della risorsa sia cambiato solo leggermente, la chiave della cache, la suddivisione dei blocchi e l’input compresso sono diventati un insieme diverso di cose, e il livello di trasporto è costretto a ingoiare nuovamente l’intero costo.

Fino a quando l’hash della risorsa non sarà stabile, i vantaggi della compressione saranno semplicemente insostenibili.

Dopo che i progetti front-end vengono rilasciati in parallelo con più pagine, più percorsi e più team, l’aspetto più facilmente trascurato è la stabilità del nome del file. Finché la segmentazione dei blocchi si sposta leggermente, anche se il codice aziendale modifica solo la copia di un pulsante, il prodotto finale può anche riscrivere l’hash di una serie di bundle pubblici. Ciò che vede il sistema di memorizzazione nella cache è un batch di oggetti nuovi di zecca, e ciò che vede il sistema di compressione è un batch di input che appaiono per la prima volta.

In questo momento, non importa quanto sia alto il tasso di compressione, non è possibile salvare il tasso di successo dal collasso. I vecchi file si trovano ancora nei nodi periferici e i nuovi file sono stati riprogrammati; la cache locale del browser non è completamente valida e la CDN deve estrarre nuovamente il sorgente, comprimerlo nuovamente e ridistribuirlo. Una piccola modifica aziendale viene amplificata in un lavoro ripetuto per l’intero collegamento di trasmissione.

L’azione veramente utile di solito non è continuare a regolare il livello di compressione, ma controllare prima la stabilità del prodotto rilasciato:

  • Le dipendenze pubbliche vengono suddivise in livelli separati per ridurre i cambiamenti aziendali e riunire i pacchetti di base per modificare l’hash.
  • Evita di mescolare modifiche ad alta frequenza come timestamp e creare numeri direttamente nel contenuto del prodotto
  • Lascia che il codice vicino allo stesso percorso rientri il più possibile in blocchi stabili invece di essere rimescolato ogni volta che viene compilato.

Solo quando l’identità della risorsa è stabilizzata la cache può essere riutilizzata continuamente e i risultati della compressione hanno valore cumulativo.

La conferenza stampa ad alta frequenza riscrive il problema della compressione in un problema della versione del dizionario

Poiché le risorse diventano sempre più frammentate, Brotli o gzip a file singolo sono ancora importanti, ma non sono più tutto. Il costo reale inizia a spostarsi verso pezzi duplicati: il codice runtime del framework, i modelli di stile, le dichiarazioni del tipo di interfaccia, i livelli di confezionamento generati dai creatori di pacchetti sono spesso molto simili tra lotti di versioni. Con un tempo di rilascio veloce, questi riff verranno trasferiti ancora e ancora.

Il problema è che il dizionario di compressione può facilmente trasformarsi da ottimizzazione a stravolgimento se non viene gestito insieme alla cadenza di rilascio. Se il dizionario viene cambiato in anticipo, il nuovo dizionario a cui fa riferimento la vecchia pagina non corrisponderà; il dizionario è tagliato in troppi pezzi e il numero di versioni che devono essere mantenute dai nodi marginali aumenta notevolmente; l’aggiornamento del dizionario non è sincronizzato con la risorsa online e gli oggetti che avrebbero dovuto essere colpiti vengono riportati in piena trasmissione.

Questo è anche un cambiamento molto pratico nella recente distribuzione front-end: le strategie di caching e i protocolli di compressione non possono più essere gestiti da team diversi. Le versioni delle risorse, le versioni del dizionario e gli spazi delle chiavi della cache sono essenzialmente lo stesso problema di pubblicazione.

Un approccio gerarchico come il seguente è solitamente più stabile della “compressione forte unificata per l’intero sito”:

const policy = {
  immutableAssets: 'public, max-age=31536000, immutable',
  releaseManifest: 'public, max-age=60, stale-while-revalidate=30',
  sharedDictionary: 'versioned-by-release-train'
}

La chiave non è la configurazione stessa di queste tre linee, ma i vincoli che esprime: le risorse del ciclo di vita lungo, l’elenco del ciclo di vita breve e la versione compressa del dizionario devono evolversi insieme secondo lo stesso ritmo di rilascio.

La pressione nel ritornare alla fonte spesso non è dovuta al fatto che il file è troppo grande, ma che il metodo di errore è troppo approssimativo.

Un altro errore di valutazione molto comune è quello di attribuire l’aumento della larghezza di banda direttamente al peso della pagina. Le pagine stanno sicuramente diventando più pesanti, ma gli amplificatori più pericolosi online sono solitamente la strada da percorrere.

Se elimini la directory, il prefisso o anche l’intero sito ogni volta che pubblichi, il livello della cache perderà immediatamente la memoria. In questo momento, anche se la dimensione del file non continua a crescere, il valore di picco del ritorno all’origine verrà aumentato da solo. Non appena viene restituita la fonte, i bordi vengono ricompressi, gli oggetti vengono riscaldati e il browser viene scaricato nuovamente. La finestra di pubblicazione cambierà da una piccola modifica graduale a un trasferimento completo del sito.

In questo tipo di scenario, la cosa più importante è il raggio di guasto controllabile:

  • Invalidare solo le risorse manifest, HTML e modificabili che sono effettivamente cambiate
  • Cerca di non eliminare i file statici con hash e di consegnarli a nuovi riferimenti per il passaggio naturale.
  • Suddividere il rilascio nell’ordine “prima carica nuove risorse, poi taglia i riferimenti, quindi ricicla le vecchie risorse” invece di cancellarle tutte in una volta

Ciò che è veramente importante riguardo al costo di trasferimento non è solo la dimensione del file, ma anche il modo in cui il sistema decide quale contenuto deve essere recuperato.

Il limite applicabile viene determinato insieme alla scala delle risorse e alla frequenza di rilascio.

Questo insieme di co-progettazione non è richiesto per tutti i siti. Per progetti con un numero limitato di pagine statiche, un piccolo pacchetto di risorse e una frequenza di rilascio settimanale o addirittura mensile, l’utilizzo dei tradizionali nomi di file hash più la precompressione Brotli è solitamente sufficientemente stabile.

Il caching e la compressione insieme diventano rapidamente un’infrastruttura di distribuzione una volta implementate queste caratteristiche:

  • Rilasciato più volte al giorno, con scala di grigi, rollback o lanci regionali
  • Il prodotto front-end è di grandi dimensioni, ha molte dipendenze pubbliche e ha relazioni complesse tra blocchi.
  • CDN, Object Storage, Edge Compression e Caching del browser partecipano contemporaneamente al collegamento di trasmissione
  • Il traffico è così elevato che il tasso di riscontro della cache e il valore di picco del ritorno all’origine rifletteranno direttamente il costo e la stabilità.

Dopo che la distribuzione front-end è entrata in questa fase, la compressione non significa più semplicemente “rimpicciolire i file” e la memorizzazione nella cache non significa più semplicemente “memorizzare più copie di contenuto”. Ciò che i due decidono insieme è: per un piccolo cambiamento aziendale, se si tratta solo di inviare un pezzo in più o se l’intero collegamento di trasmissione deve essere eseguito di nuovo. Quanto più frequentemente pubblichi, tanto più costosa diventa questa differenza.