Potenzia l'efficienza di compressione con i dizionari condivisi

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

Sebbene gzip sia di per sé molto efficace, negli ultimi anni sono stati apportati ulteriori miglioramenti alla compressione sul web. Nel 2016, l'algoritmo di Brotli è stato introdotto 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 dei server per questo ha iniziato a diventare più diffuso. Più di recente, Chrome ha distribuito la compressione ZStandard.

Il lavoro però non si ferma qui! Il team di Chrome sta lavorando per rendere utilizzabili sul web dizionari condivisi, che ora sono disponibili in una prova dell'origine sia per Brotli che per ZStandard. I dizionari condivisi possono integrare la compressione Brotli e ZStandard per fornire rapporti di compressione notevolmente più elevati per i siti web che inviano spesso codice aggiornato e possono, in alcuni casi, fornire proporzioni di compressione pari o superiori al 90%. Questo post fornisce maggiori dettagli su come funzionano i dizionari condivisi e su come puoi registrarti alle prove dell'origine per utilizzarli per Brotli e ZStandard sul tuo sito web.

Spiegazione dei dizionari condivisi

La compressione è un processo che consente di individuare sequenze ridondanti in un input e di utilizzare quelle informazioni per creare un output molto più ridotto, 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 propria 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 si ottiene in una certa misura utilizzando un dizionario interno.

Tuttavia, è possibile utilizzare dizionari personalizzati curati dall'utente con Brotli e ZStandard 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. L'applicabilità di un determinato dizionario al suo 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 attualmente in uso sia la 1.7.9. Questa versione del framework Angular occupa circa 172 KiB in formato non compresso. Quando viene compressa con le impostazioni predefinite di Brotli, le sue dimensioni diventano di circa 53 KiB. Questo produce un rapporto di compressione quasi del 70%. Tuttavia, supponiamo che tu decida di eseguire l'upgrade ad Angular 1.8.3 in un secondo momento. Dato che questa versione di Angular ha all'incirca le stesse dimensioni della versione 1.7.9, ci si può aspettare praticamente lo stesso rapporto di compressione della versione precedente.

È qui che può tornare 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 hai compresso la versione 1.8.3 di Angular utilizzando la versione 1.7.9 come dizionario, l'output sarà di poco superiore a 4 KiB. Questo rappresenta un rapporto di compressione di quasi il 98%. È evidente che i dizionari di compressione possono avere un grande impatto sulle prestazioni di caricamento e la loro efficacia è già realizzata nelle applicazioni reali.

Tuttavia, il funzionamento di questo flusso sul web è complicato. Il problema è che, se utilizzi un dizionario per comprimere una risorsa, hai bisogno dello stesso dizionario per decomprimerlo. Questo flusso è già stato tentato sul web in passato, ovvero SDCH, ma era difficile da implementare in sicurezza. L'ultima proposta di compressione dei dizionari condivisi risponde a questi problemi fornendo al contempo un sostanziale vantaggio per le risorse statiche e dinamiche.

In che modo Chrome pubblicizza il supporto per i dizionari condivisi

Tutti i browser pubblicizzano gli algoritmi di compressione supportati tramite l'intestazione della richiesta Accept-Encoding. Il contenuto dell'intestazione è costituito da un elenco separato da virgole di codifiche supportate:

Accept-Encoding: gzip, br, zstd

Questa particolare intestazione Accept-Encoding indica 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 dei dizionari condivisi è abilitato e un dizionario pertinente è disponibile per una risorsa, vengono aggiunti ulteriori token all'intestazione Accept-Encoding. Questi token sono br-d per Brotli e zstd-d per Zstandard. Chrome includerà anche l'hash di un dizionario disponibile di cui parleremo più avanti.

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

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

Compressione del dizionario condiviso per le risorse statiche

Una risorsa di 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 in genere utilizzano il controllo delle versioni per scopi di memorizzazione nella cache, in qualche modo, a volte con un hash dei contenuti del file nel nome file (ad esempio styles.abcd1234.css) o con qualche altro metodo di fingerprinting della risorsa. Questi tipi di risorse sono ideali per la compressione delta fornita dai dizionari condivisi, poiché le risorse statiche vengono spesso memorizzate nella cache per lunghi periodi di tempo e tendono a essere aggiornate con una certa frequenza.

È possibile specificare un dizionario per una risorsa statica impostando la relativa intestazione della 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 corrisponde al pattern specificato al suo interno. Quindi, supponiamo che il tuo sito web spedisca tutti gli stili in un unico file CSS. Per semplicità, supponiamo che la prima versione della risorsa si trovi in /dist/styles.v1.css e venga inviata con un'intestazione di risposta Use-As-Dictionary contenente un valore match pari a /dist/styles.*.css.

Trascorso un po' di tempo, aggiorni il CSS del tuo sito web e spedisci una nuova versione del CSS all'indirizzo /dist/styles.v2.css. Poiché il valore match utilizzato nell'intestazione della 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 in campo strutturato:

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

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

Se invii spesso nuovo codice per il tuo sito web, la compressione delta può essere molto utile. Tuttavia, la procedura è flessibile. Se il browser non determina la disponibilità di un dizionario nella cache del browser dell'utente, non specifichi i token aggiuntivi br-d o zstd-d nell'intestazione Accept-Encoding. In questo caso viene applicato il flusso di compressione standard.

Compressione del dizionario condiviso per risorse dinamiche

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

A causa della natura delle risorse generate dinamicamente, un dizionario deve essere caricato sul client per utilizzarlo in un secondo momento. Caricare in anticipo un dizionario significa che l'applicazione della compressione del dizionario condiviso alle risorse dinamiche è speculativa. La speranza in questi casi è che il tuo sito web riceva abbastanza traffico da ammortizzare il costo del dizionario in un numero elevato di navigazioni. Se decidi di provare, il primo passaggio consiste nello specificare la posizione del dizionario tramite un elemento <link> nel codice HTML della pagina:

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

Quando Chrome rileva questo elemento <link>, potrebbe recuperare il dizionario quando la pagina è inattiva e a bassa priorità, per evitare il conflitto di larghezza di banda. La risposta per il dizionario stesso deve specificare un'intestazione Use-As-Dictionary e indicare a quale percorso di risorsa dinamico 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 il browser collegherà un'intestazione Available-Dictionary alla richiesta con un hash dei contenuti del dizionario, sempre in modo simile al flusso di risorse statiche spiegato in precedenza.

Comprimi le risorse statiche al momento della creazione

Se hai familiarità con i bundler, potresti avere familiarità con vari plug-in in grado di comprimere le risorse al momento della creazione per poi distribuire le risorse compresse. Ad esempio, Apache consente di utilizzare istruzioni per pubblicare le risorse precompresse al momento della richiesta.

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

Tieni presente che i dizionari disponibili per qualsiasi versione specifica di una risorsa possono utilizzare una qualsiasi versione precedente di una risorsa. Ciò significa che dovrai analizzare il traffico degli utenti e pianificare di conseguenza. Cerca di raggiungere un equilibrio e genera risorse che possano essere utili per il maggior numero possibile di utenti di ritorno. I provider CDN stanno sperimentando la compressione dei dizionari condivisi. Al momento non è disponibile alcuna implementazione di pubblico utilizzo, ma prevediamo che la situazione cambi.

Corri a provarla!

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

  1. Se vuoi solo provare autonomamente la compressione dei dizionari condivisi per avere un'idea di come funziona, puoi attivare la funzionalità sperimentale Trasporto del dizionario di compressione nella pagina chrome://flags.
  2. Se ti interessa provare questa funzionalità sul tuo sito web di produzione e scoprire in che modo la compressione dei dizionari condivisi potrebbe aiutare gli utenti reali, registrati alla prova dell'origine per ricevere un token e scopri come funzionano le prove dell'origine.

Conclusione

Siamo entusiasti di questi importanti progressi nella tecnologia di compressione sul web e di quanto più veloce potrebbe rendere le applicazioni esistenti utilizzate ogni giorno. Ti invitiamo a provarla e, soprattutto, ci piacerebbe conoscere la tua opinione se la conosci. Se trovi un bug, invia una segnalazione all'indirizzo crbug.com. Per ulteriori risorse e strumenti, visita il sito use-as-dictionary.com. Infine, se vuoi approfondire il funzionamento, la spiegazione è un buon passaggio successivo.