Aumente a eficiência da compactação com dicionários compartilhados

A compactação de dados é uma técnica de otimização de desempenho testada e reduz o tamanho dos recursos qualificados da página. Por algum tempo, era uma prática comum usar principalmente o gzip em servidores da Web para compactar recursos comuns de página baseados em texto, como arquivos HTML, CSS e JavaScript, e enviá-los ao cliente onde eles poderiam ser descompactados. Isso resulta em tempos de carregamento mais rápidos para recursos sem afetar o comportamento pretendido de uma página.

Embora o gzip seja altamente eficaz por si só, outras melhorias na compactação na Web foram alcançadas nos últimos anos. Em 2016, o algoritmo Brotli foi lançado no Chrome, oferecendo taxas de compactação melhores para os recursos qualificados. No fim de 2017, todos os navegadores mais recentes ofereciam suporte ao Brotli, e o suporte a servidores começou a se difundir. Mais recentemente, o Chrome lançou a compactação ZStandard.

Mas o trabalho não para por aí! A equipe do Chrome está trabalhando para tornar os dicionários compartilhados utilizáveis na Web, e eles já estão disponíveis em um teste de origem para Brotli e ZStandard. Os dicionários compartilhados podem complementar a compactação com o Brotli e o ZStandard para oferecer taxas de compactação substancialmente mais altas para sites que costumam enviar códigos atualizados e podem, em alguns casos, fornecer taxas de compactação de 90% ou mais. Esta postagem traz mais detalhes sobre como os dicionários compartilhados funcionam e como você pode se registrar nos testes de origem para usá-los no Brotli e ZStandard no seu site.

Explicação sobre dicionários compartilhados

A compactação é o processo de encontrar sequências redundantes em uma entrada e usar essas informações para criar uma saída muito menor, que pode ser revertida mais tarde. A compactação funciona bem na Web porque reduz substancialmente os tempos de carregamento de recursos. Tanto o Brotli quanto o ZStandard podem aumentar ainda mais a eficácia usando um dicionário de compactação, que é uma coleção de padrões adicionais que esses algoritmos podem usar durante a compactação. Na verdade, a alta eficiência de Brotli é alcançada até certo ponto usando um dicionário interno.

No entanto, dicionários personalizados e selecionados pelo usuário podem ser usados com o Brotli e o ZStandard, que contêm padrões específicos de recursos específicos. Na prática, um dicionário personalizado é um arquivo externo que pode ser aplicado a qualquer entrada. Os dicionários podem ser altamente específicos para o código de produção de um aplicativo ou para qualquer conteúdo. A aplicação de um determinado dicionário à sua entrada pode ter um grande impacto na eficiência geral da compressão. Dicionários muito semelhantes ao conteúdo de uma entrada produzirão saídas com taxas de compactação mais altas do que dicionários com conteúdos genéricos ou diferentes.

Confira um exemplo da eficácia de um dicionário de compactação personalizado: digamos que seu site use o framework Angular e a versão atual que você está usando é a 1.7.9. Essa versão do framework Angular tem cerca de 172 KiB não compactado. Quando compactado com as configurações padrão do Brotli, o tamanho dele se torna cerca de 53 KiB. Isso produz uma taxa de compactação de quase 70%. No entanto, digamos que você decida fazer upgrade para o Angular 1.8.3 mais tarde. Como essa versão do Angular tem aproximadamente o mesmo tamanho que a versão 1.7.9, é possível esperar praticamente a mesma taxa de compactação da versão anterior.

É nesse caso que um dicionário personalizado pode ser útil usando um processo conhecido como compressão delta , em que um dicionário de uma versão anterior de um recurso pode ser usado para compactar uma versão posterior. Usando o exemplo anterior, se você compactou a versão 1.8.3 do Angular usando a versão 1.7.9 como um dicionário, a saída seria um pouco mais de 4 KiB. Isso representa uma taxa de compactação de quase 98%. Obviamente, os dicionários de compactação podem ter um grande impacto no desempenho do carregamento, e a eficácia deles já foi percebida em aplicativos reais.

No entanto, há um desafio em fazer esse fluxo funcionar na Web. O problema é que, se você usar um dicionário para compactar um recurso, vai precisar do mesmo dicionário para descompactá-lo. Já tentamos usar esse fluxo na Web, especificamente no SDCH, mas foi difícil implementá-lo com segurança. A proposta mais recente de compactação de dicionário compartilhado aborda essas questões e oferece um benefício significativo para recursos estáticos e dinâmicos.

Como o Chrome anuncia a compatibilidade com dicionários compartilhados

Todos os navegadores anunciam os algoritmos de compactação compatíveis usando o cabeçalho de solicitação Accept-Encoding. O conteúdo do cabeçalho é uma lista separada por vírgulas de codificações compatíveis:

Accept-Encoding: gzip, br, zstd

Esse cabeçalho Accept-Encoding específico informa que o navegador que solicita o recurso é compatível com os algoritmos de compactação gzip, Brotli e ZStandard. Um servidor da Web que responde à solicitação pode decidir qual algoritmo usar para responder a ela.

Quando o suporte a dicionário compartilhado está ativado e um dicionário relevante está disponível para um recurso, tokens extras são adicionados ao cabeçalho Accept-Encoding. Esses tokens são br-d para o Brotli e zstd-d para o Zstandard. O Chrome também inclui o hash de um dicionário disponível, que será abordado a seguir.

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

Se um servidor da Web estiver configurado para reconhecer esse token e reconhecer o dicionário, ele poderá responder a essa solicitação com um recurso que foi compactado usando o dicionário da codificação aplicável. A forma como isso é alcançado na prática depende da solicitação ser de um recurso estático ou dinâmico.

Compactação do dicionário compartilhado para recursos estáticos

Um recurso de página estática é aquele que sempre produz a mesma resposta para um URL solicitado. Exemplos comuns de recursos de página estática compactáveis são arquivos JavaScript e CSS. Esses recursos geralmente têm controle de versões para fins de armazenamento em cache de alguma forma. Às vezes, com um hash do conteúdo do arquivo no nome do arquivo (por exemplo, styles.abcd1234.css) ou algum outro método de impressão digital do recurso. Esses tipos de recurso são ótimos candidatos à compactação delta que os dicionários compartilhados oferecem, uma vez que os recursos estáticos geralmente são armazenados em cache por longos períodos e tendem a ser atualizados com certa frequência.

Um dicionário pode ser especificado para um recurso estático definindo o cabeçalho de resposta Use-As-Dictionary para ele. O cabeçalho usa um dos poucos pares de chave-valor, mas o único obrigatório é match, que aceita a sintaxe URLPattern (link em inglês) especificando o caminho do recurso em que o dicionário será usado:

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

Pense no cabeçalho Use-As-Dictionary como um mecanismo que se aplica a versões futuras de um recurso que corresponde ao padrão especificado nele. Digamos que seu site envia todos os seus estilos em um único arquivo CSS. Para simplificar, digamos que a primeira versão desse recurso esteja localizada em /dist/styles.v1.css e seja enviada com um cabeçalho de resposta Use-As-Dictionary contendo um valor match de /dist/styles.*.css.

Depois de um tempo, você atualiza o CSS do seu site e envia uma nova versão dele localizada em /dist/styles.v2.css. Como o valor match usado no cabeçalho de resposta Use-As-Dictionary da versão anterior se aplica a essa solicitação, o navegador enviará um cabeçalho Available-Dictionary contendo um hash do dicionário codificado como uma sequência de bytes de campo estruturado:

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

Nesse ponto, cabe ao servidor configurar a compactação do seu lado para garantir que o dicionário correspondente seja usado. O recurso compactado com esse dicionário será enviado e o dicionário disponível no cache do navegador do usuário será usado para descompactá-lo.

Se você envia novos códigos com frequência para seu site, a compressão delta pode ajudar muito. No entanto, o processo é flexível. Se o navegador não determinar que há um dicionário disponível no cache do usuário, ele não especificará os tokens br-d ou zstd-d adicionais no cabeçalho Accept-Encoding. Nesse caso, o fluxo de compactação padrão se aplica.

Compactação do dicionário compartilhado para recursos dinâmicos

Os recursos dinâmicos também podem se beneficiar da compactação do dicionário compartilhado. Os recursos dinâmicos são aqueles que mudam com base em um contexto, como um site de notícias em que a página principal é atualizada com frequência quando há notícias. Os documentos HTML geralmente são recursos dinâmicos. Nesses casos, o dicionário pode conter a maior parte da estrutura HTML comum do site e do código do modelo, levando a páginas compactadas, em que apenas as partes exclusivas de cada página são enviadas.

Devido à natureza dos recursos gerados dinamicamente, é preciso carregar um dicionário no cliente para uso posterior. Carregar um dicionário com antecedência significa que a aplicação da compactação de dicionário compartilhado a recursos dinâmicos é especulativa. A esperança, nesses casos, é que seu site receba tráfego suficiente para que o custo do dicionário possa ser amortizado em um grande número de navegações. Se você quiser testar esse recurso, a primeira etapa é especificar o local do dicionário usando um elemento <link> no HTML da sua página:

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

Quando o Chrome encontra esse elemento <link>, ele pode buscar o dicionário quando a página está inativa e com prioridade baixa para evitar a contenção da largura de banda. A resposta do dicionário precisa especificar um cabeçalho Use-As-Dictionary e especificar a qual caminho de recurso dinâmico ele se aplica:

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

A partir daqui, o fluxo é basicamente o mesmo dos recursos estáticos. O navegador verá que o dicionário se aplica a recursos correspondentes e anexará um cabeçalho Available-Dictionary à solicitação com um hash do conteúdo do dicionário, novamente, semelhante ao fluxo de recursos estáticos explicado anteriormente.

Compactar recursos estáticos no tempo de compilação

Se você já conhece os bundlers, deve conhecer vários plug-ins para eles que podem compactar recursos em tempo de compilação e, posteriormente, disponibilizar esses recursos compactados. Por exemplo, o Apache permite usar diretivas para disponibilizar esses recursos pré-compactados no momento da solicitação.

A maioria dos bundlers baseados em Node.js compatíveis com compactação usa a biblioteca Zlib integrada do Node. O Zlib oferece suporte para Brotli, e bundlers que o usam normalmente oferecem uma interface para transmitir opções diretamente para o Zlib, que oferece suporte à compactação assistida por dicionário (link em inglês). Confira alguns bundlers compatíveis com o uso de dicionários:

Os dicionários disponíveis para qualquer versão de um recurso podem usar uma das versões anteriores dele. Isso significa que você precisará analisar o tráfego de usuários e planejar adequadamente. Busque um equilíbrio e gere recursos que beneficiem o máximo possível de usuários recorrentes. Os provedores de CDN estão testando a compactação de dicionário compartilhado. Ainda não há implementações disponíveis para uso público, mas esperamos que isso mude.

Não deixe de conferir!

A integração da compactação de dicionário compartilhado com os recursos de compactação do navegador tem o potencial de melhorar substancialmente o desempenho de carregamento de sites que frequentemente enviam códigos de produção atualizados e recebem tráfego significativo de visitantes recorrentes. Se tiver interesse em testar a compactação do dicionário compartilhado, você tem duas opções:

  1. Se você quiser testar a compactação do dicionário compartilhado por conta própria para ter uma ideia de como ela funciona, ative o recurso experimental Transporte do dicionário por compactação na página chrome://flags.
  2. Se você quiser testar esse recurso no seu site de produção e saber como a compactação de dicionário compartilhado pode beneficiar usuários reais, faça o registro no teste de origem (link em inglês) para receber um token e leia sobre como os testes de origem funcionam.

Conclusão

Estamos muito entusiasmados com esse grande avanço na tecnologia de compressão na web e com a rapidez com que ele pode tornar os aplicativos existentes que as pessoas usam todos os dias. Incentivamos você a testá-la e, o mais importante, gostamos de saber sua opinião. Se você encontrar um bug, registre-o em crbug.com. Para acessar recursos e ferramentas adicionais, confira use-as-dictionary.com. Por fim, se você tiver interesse em saber mais sobre como tudo isso funciona, a explicação é uma boa próxima etapa.