Potenzia l'efficienza di compressione con i dizionari condivisi

La compressione dei dati è una tecnica di ottimizzazione del rendimento collaudata nel tempo che riduce le dimensioni delle risorse della pagina idonee. Per un certo periodo, era prassi comune utilizzare principalmente gzip sui server web per comprimere le risorse di pagina comuni basate su testo, come i file HTML, CSS e JavaScript, e inviarli al client dove potevano essere decompressi. Il risultato è un tempo di caricamento più rapido delle risorse senza influire sul comportamento previsto di una pagina.

Sebbene gzip sia molto efficace di per sé, negli ultimi anni sono stati realizzati ulteriori miglioramenti alla compressione sul web. Nel 2016, l'algoritmo Brotli è stato implementato in Chrome, offrendo rapporti di compressione complessivi migliori per le risorse idonee. Entro la fine del 2017, tutti i browser moderni supportavano Brotli e il supporto del server per questo formato ha iniziato a diffondersi. Di recente, Chrome ha implementato la compressione ZStandard.

Il lavoro non finisce qui. Il team di Chrome si sta adoperando per rendere utilizzabili sul web i dizionari condivisi, che ora sono disponibili in una prova di origine sia per Brotli che per ZStandard. I dizionari condivisi possono integrare la compressione Brotli e ZStandard per offrire rapporti di compressione notevolmente superiori per i siti web che pubblicano spesso codice aggiornato e, in alcuni casi, possono offrire rapporti di compressione pari o superiori al 90%. Questo post illustra più nel dettaglio il funzionamento dei dizionari condivisi e come registrarsi per le prove dell'origine per utilizzarli per Brotli e ZStandard sul tuo sito web.

Informazioni sui dizionari condivisi

La compressione è un processo che consente di trovare sequenze ridondanti in un input e di utilizzare queste informazioni per creare un output molto più piccolo, che può essere invertito in un secondo momento. La compressione funziona bene sul web perché riduce notevolmente i tempi di caricamento delle risorse. Sia Brotli che ZStandard possono aumentare ulteriormente la loro efficacia utilizzando un dizionario di compressione, ovvero una raccolta di pattern aggiuntivi che questi algoritmi possono utilizzare durante la compressione. In effetti, l'elevata efficienza di Brotli viene raggiunta in qualche misura utilizzando un dizionario interno.

Tuttavia, con Brotli e ZStandard è possibile utilizzare dizionari personalizzati selezionati dagli utenti che contengono pattern specifici per determinate risorse. In pratica, un dizionario personalizzato è un file esterno che può essere applicato a qualsiasi input. I dizionari possono essere molto specifici per il codice di produzione di un'applicazione o per qualsiasi contenuto. Il grado di applicabilità di un determinato dizionario all'input può avere un grande impatto sull'efficienza complessiva della compressione. I dizionari molto simili ai contenuti di un input produrranno output con rapporti di compressione più elevati rispetto ai dizionari con contenuti generici o diversi.

Ecco un esempio di quanto può essere efficace un dizionario di compressione personalizzato: supponiamo che il tuo sito web utilizzi il framework Angular e che la versione corrente in uso sia la 1.7.9. Questa versione del framework Angular occupa circa 172 KB non compressi. Se viene compresso con le impostazioni predefinite di Brotli, le dimensioni diventano circa 53 KiB. Ciò consente di ottenere un rapporto di compressione di quasi il 70%. Tuttavia, supponiamo che tu decida di eseguire l'upgrade ad Angular 1.8.3 in un secondo momento. Poiché questa versione di Angular ha all'incirca le stesse dimensioni della versione 1.7.9, puoi aspettarti praticamente lo stesso rapporto di compressione della versione precedente.

È qui che può essere utile un dizionario personalizzato, utilizzando un processo noto come compressione delta, ovvero quando un dizionario di una versione precedente di una risorsa può essere utilizzato per comprimere una versione successiva. Utilizzando l'esempio precedente, se comprimevi la versione 1.8.3 di Angular utilizzando la versione 1.7.9 come dizionario, l'output sarebbe poco più di 4 KiB. Ciò rappresenta un rapporto di compressione di quasi il 98%. È chiaro che i dizionari di compressione possono avere un grande impatto sulle prestazioni di caricamento e la loro efficacia è già stata applicata in applicazioni reali.

Tuttavia, c'è un problema nel far funzionare questo flusso sul web. Il problema è che, se utilizzi un dizionario per comprimere una risorsa, devi utilizzare lo stesso dizionario per decomprimerla. Questo flusso è stato tentato in precedenza sul web, ovvero con SDCH, ma è stato difficile implementarlo in sicurezza. Questa ultima proposta per la compressione del dizionario condiviso risolve questi problemi, offrendo al contempo un vantaggio sostanziale sia per le risorse statiche che per quelle dinamiche.

In che modo Chrome pubblicizza il supporto dei dizionari condivisi

Tutti i browser pubblicizzano gli algoritmi di compressione supportati tramite l'intestazione della richiesta Accept-Encoding. I contenuti dell'intestazione sono un elenco separato da virgole delle codifiche supportate:

Accept-Encoding: gzip, br, zstd

Questa intestazione Accept-Encoding specifica che il browser che richiede la risorsa supporta gli algoritmi di compressione gzip, Brotli e ZStandard. Un server web che risponde alla richiesta può quindi decidere quale algoritmo utilizzare per rispondere alla richiesta.

Quando il supporto del dizionario condiviso è attivo e per una risorsa è disponibile un dizionario pertinente, all'intestazione Accept-Encoding vengono aggiunti token aggiuntivi. Questi token sono br-d per Brotli e zstd-d per Zstandard. Chrome includerà anche l'hash di un dizionario disponibile, di cui parleremo di seguito.

Accept-Encoding: gzip, br, zstd, br-d, zstd-d
Available-Dictionary: :pZGm1Av0IEBKARczz7exkNYsZb8LzaMrV7J32a2fFG4=:

Se un server web è configurato per riconoscere questo token e il dizionario, può rispondere alla richiesta con una risorsa compressa utilizzando il dizionario per la codifica applicabile. Il modo in cui questo viene ottenuto in pratica dipende dal fatto che la richiesta riguardi una risorsa statica o dinamica.

Compressione del dizionario condiviso per le risorse statiche

Una risorsa pagina statica è una risorsa che produce sempre la stessa risposta per un URL richiesto. Esempi comuni di risorse di pagine statiche comprimibili sono i file JavaScript e CSS. Queste risorse vengono in genere versionate per scopi di memorizzazione nella cache in qualche modo, a volte con un hash dei contenuti del file nel nome del file (ad esempio styles.abcd1234.css) o con un altro metodo per creare l'impronta della risorsa. Questi tipi di risorse sono ottimi candidati per la compressione delta fornita dai dizionari condivisi, in quanto le risorse statiche vengono spesso memorizzate nella cache per lunghi periodi di tempo e tendono ad essere aggiornate con una certa frequenza.

È possibile specificare un dizionario per una risorsa statica impostando l'intestazione di risposta Use-As-Dictionary. L'intestazione accetta una delle poche coppie chiave/valore, ma l'unica obbligatoria è match, che accetta la sintassi URLPattern che specifica il percorso della risorsa in cui deve essere utilizzato il dizionario:

Use-As-Dictionary: match="/dist/styles.*.css"

Pensa all'intestazione Use-As-Dictionary come a un meccanismo che si applica alle versioni future di una risorsa che corrispondono al pattern specificato al suo interno. Supponiamo che il tuo sito web includa tutti gli stili in un unico file CSS. Per semplicità, supponiamo che la prima versione della risorsa si trovi all'indirizzo /dist/styles.v1.css e venga inviata con un'intestazione di risposta Use-As-Dictionary contenente un valore match di /dist/styles.*.css.

Dopo un po' di tempo, aggiorni il CSS del tuo sito web e ne invii una nuova versione all'indirizzo /dist/styles.v2.css. Poiché il valore match utilizzato nell'intestazione di risposta Use-As-Dictionary della versione precedente si applica a questa richiesta, il browser invierà un'intestazione Available-Dictionary contenente un hash del dizionario codificato come sequenza di byte di campo strutturato:

Accept-Encoding: gzip, br, zstd, br-d, zstd-d
Available-Dictionary: :pZGm1Av0IEBKARczz7exkNYsZb8LzaMrV7J32a2fFG4=:

A questo punto, sta al server configurare la compressione per assicurarsi che venga utilizzato il dizionario di corrispondenza. La risorsa compressa con il dizionario verrà quindi inviata e il dizionario disponibile nella cache del browser dell'utente verrà utilizzato per decomprimerla.

Se pubblichi spesso nuovo codice per il tuo sito web, la compressione delta può fare molto. Tuttavia, la procedura è flessibile. Se il browser non rileva che un dizionario è disponibile nella cache del browser dell'utente, non specificherà i token br-d o zstd-d aggiuntivi nell'intestazione Accept-Encoding. In questo caso, si applica il flusso di compressione standard.

Compressione del dizionario condiviso per le risorse dinamiche

Anche le risorse dinamiche possono trarre vantaggio dalla compressione del dizionario condiviso. Le risorse dinamiche sono quelle che cambiano in base a un contesto, ad esempio un sito web di notizie in cui la pagina principale viene aggiornata di frequente man mano che vengono pubblicate le notizie. I documenti HTML sono spesso risorse dinamiche. In questi casi, il dizionario può contenere la maggior parte della struttura HTML e del codice del modello comuni del sito, il che porta a pagine compresse in cui vengono inviate solo le parti univoche di ogni pagina.

A causa della natura delle risorse generate dinamicamente, è necessario caricare un dizionario sul client per utilizzarlo in un secondo momento. Se carichi un dizionario in anticipo, l'applicazione della compressione del dizionario condiviso alle risorse dinamiche è speculativa. In questi casi, si spera che il tuo sito web riceva abbastanza traffico da consentire l'ammortamento del costo del dizionario su un numero elevato di navigazioni. Se decidi di provarlo, il primo passaggio consiste nello specificare la posizione del dizionario tramite un elemento <link> nella pagina HTML:

<link rel="dictionary" href="/dictionary.dat">

Quando Chrome rileva questo elemento <link>, potrebbe recuperare il dizionario quando la pagina è inattiva e con priorità bassa per evitare contese sulla larghezza di banda. La risposta per il dizionario stesso deve specificare un'intestazione Use-As-Dictionary e il percorso della risorsa dinamica a cui si applica:

Use-As-Dictionary: match="/product/*"

Da qui, il flusso è in gran parte uguale a quello delle risorse statiche. Il browser vedrà che il dizionario stesso si applica alle risorse corrispondenti e allegherà un'intestazione Available-Dictionary alla richiesta con un hash dei contenuti del dizionario, in modo simile al flusso delle risorse statiche spiegato in precedenza.

Comprimi le risorse statiche in fase di compilazione

Se hai dimestichezza con i bundler, potresti conoscere vari plug-in che possono comprimere le risorse in fase di compilazione e successivamente pubblicarle. Ad esempio, Apache ti consente di utilizzare direttive per pubblicare le risorse precompresse al momento della richiesta.

La maggior parte dei bundler basati su Node.js che supportano la compressione utilizza la libreria Zlib integrata di Node. Zlib offre il supporto di Brotli e i bundler che lo utilizzano in genere offrono un'interfaccia per passare le opzioni direttamente a Zlib, che supporta la compressione con l'aiuto di un dizionario. Ecco alcuni pacchetti che supportano l'utilizzo di dizionari:

Tieni presente che i dizionari disponibili per una determinata versione di una risorsa possono utilizzare una delle versioni precedenti della risorsa. Ciò significa che dovrai analizzare il traffico degli utenti e pianificare di conseguenza. Cerca di trovare un equilibrio e genera risorse che siano utili al maggior numero possibile di utenti di ritorno. I fornitori di CDN stanno attualmente sperimentando la compressione del dizionario condiviso. Non sono ancora disponibili implementazioni per uso pubblico, ma ci aspettiamo che la situazione cambi.

Prova

L'integrazione della compressione del dizionario condiviso con le funzionalità di compressione esistenti del browser ha il potenziale di migliorare notevolmente le prestazioni di caricamento dei siti web che inviano spesso codice di produzione aggiornato e ricevono traffico significativo dai visitatori di ritorno. Se vuoi provare la compressione del dizionario condiviso, hai due opzioni:

  1. Se vuoi solo provare la compressione con dizionario condiviso per capire come funziona, puoi attivare la funzionalità sperimentale Trasporto del dizionario di compressione nella pagina chrome://flags.
  2. Se vuoi provare questa funzionalità sul tuo sito web di produzione e scoprire in che modo la compressione del dizionario condiviso può essere utile per gli utenti reali, registrati per la prova dell'origine per ottenere un token e leggi come funzionano le prove dell'origine.

Conclusione

Siamo molto entusiasti di questo importante progresso nella tecnologia di compressione sul web e di quanto potrebbe velocizzare le applicazioni esistenti che le persone usano ogni giorno. Ti invitiamo a provarlo e, soprattutto, ci farebbe piacere conoscere la tua opinione. Se trovi un bug, segnalacelo su crbug.com. Per risorse e strumenti aggiuntivi, visita il sito use-as-dictionary.com. Infine, se vuoi approfondire il funzionamento di questa funzionalità, consulta la spiegazione.