Publicado el 6 de marzo de 2024
La compresión de datos es una técnica de optimización del rendimiento probada que reduce el tamaño de los recursos de página aptos. Durante un tiempo, era una práctica común usar principalmente gzip en servidores web para comprimir recursos de página comunes basados en texto, como archivos HTML, CSS y JavaScript, y enviarlos al cliente, donde se podían descomprimir. El resultado son tiempos de carga más rápidos para los recursos sin afectar el comportamiento previsto de una página.
Si bien gzip es muy eficaz por sí solo, en los últimos años se lograron más mejoras en la compresión en la Web. En 2016, se lanzó el algoritmo Brotli en Chrome, que ofrece mejores índices de compresión generales para los recursos aptos. A fines de 2017, todos los navegadores modernos admitían Brotli, y la compatibilidad con el servidor comenzó a generalizarse. Más recientemente, Chrome lanzó la compresión ZStandard.
Pero el trabajo no termina ahí. El equipo de Chrome ha estado trabajando para que los diccionarios compartidos se puedan usar en la Web, que ahora están disponibles en una prueba de origen para Brotli y ZStandard. Los diccionarios compartidos pueden complementar la compresión Brotli y ZStandard para ofrecer índices de compresión mucho más altos para los sitios web que suelen enviar código actualizado y, en algunos casos, pueden ofrecer índices de compresión del 90% o más. En esta entrada, se explica con más detalle cómo funcionan los diccionarios compartidos y cómo puedes registrarte en las pruebas de origen para usarlos en Brotli y ZStandard en tu sitio web. También puedes mirar este video:
Explicación de los diccionarios compartidos
La compresión es un proceso que consiste en encontrar secuencias redundantes en una entrada y usar esa información para crear una salida mucho más pequeña, que se puede revertir más adelante. La compresión funciona bien en la Web porque reduce considerablemente los tiempos de carga de los recursos. Tanto Brotli como ZStandard pueden aumentar aún más su eficacia mediante el uso de un diccionario de compresión, que es una colección de patrones adicionales que estos algoritmos pueden usar durante la compresión. De hecho, la alta eficiencia de Brotli se logra en cierta medida mediante el uso de un diccionario interno.
Sin embargo, se pueden usar diccionarios personalizados seleccionados por el usuario con Brotli y ZStandard que contengan patrones específicos para recursos particulares. En la práctica, un diccionario personalizado es un archivo externo que se puede aplicar a cualquier entrada. Los diccionarios pueden ser muy específicos para el código de producción de una aplicación o para cualquier contenido. La aplicabilidad de un diccionario determinado a su entrada puede tener un gran impacto en la eficiencia general de la compresión. Los diccionarios que son muy similares al contenido de una entrada producirán salidas con índices de compresión más altos que los diccionarios con contenido genérico o diferente.
Este es un ejemplo de la eficacia de un diccionario de compresión personalizado: supongamos que tu sitio web usa el framework de Angular y que la versión actual que usas es la 1.7.9. Esta versión del framework de Angular es de aproximadamente 172 KiB sin comprimir. Cuando se comprime con la configuración predeterminada de Brotli, su tamaño se convierte en aproximadamente 53 KiB. Esto produce casi un 70% de índice de compresión. Sin embargo, supongamos que decides actualizar a Angular 1.8.3 más adelante. Dado que esta versión de Angular tiene aproximadamente el mismo tamaño que la versión 1.7.9, puedes esperar prácticamente el mismo índice de compresión que la versión anterior.
Aquí es donde un diccionario personalizado puede ser útil mediante un proceso conocido como compresión delta , que es cuando se puede usar un diccionario de una versión anterior de un recurso para comprimir una versión posterior. Si usas el ejemplo anterior, si comprimiste la versión 1.8.3 de Angular con la versión 1.7.9 como diccionario, el resultado sería de poco más de 4 KiB. Esto representa un índice de compresión de casi el 98%. Claramente, los diccionarios de compresión pueden tener un gran impacto en el rendimiento de carga, y su eficacia ya se ha logrado en aplicaciones del mundo real.
Sin embargo, existe un desafío para que este flujo funcione en la Web. El problema es que, si usas un diccionario para comprimir un recurso, necesitas el mismo diccionario para descomprimirlo. Este flujo ya se intentó en la Web, específicamente SDCH, pero fue difícil de implementar de forma segura. Esta última propuesta para la compresión de diccionarios compartidos aborda esas inquietudes y, al mismo tiempo, proporciona un beneficio sustancial para los recursos estáticos y dinámicos.
Cómo Chrome anuncia la compatibilidad con diccionarios compartidos
Todos los navegadores anuncian los algoritmos de compresión que admiten a través del Accept-Encoding encabezado de la solicitud. El contenido del encabezado es una lista separada por comas de codificaciones compatibles:
Accept-Encoding: gzip, br, zstd
Este encabezado Accept-Encoding en particular indica que el navegador que solicita el recurso admite los algoritmos de compresión gzip, Brotli y ZStandard. Un servidor web que responde a la solicitud puede decidir qué algoritmo usar cuando responde a la solicitud.
Cuando se habilita la compatibilidad con diccionarios compartidos y hay un diccionario relevante disponible para un recurso, se agregan tokens adicionales al encabezado Accept-Encoding. Estos tokens son br-d para Brotli y zstd-d para Zstandard. Chrome también incluirá el hash de un diccionario disponible, que se explica a continuación.
Accept-Encoding: gzip, br, zstd, br-d, zstd-d
Available-Dictionary: :pZGm1Av0IEBKARczz7exkNYsZb8LzaMrV7J32a2fFG4=:
Si un servidor web está configurado para reconocer este token y reconoce el diccionario, puede responder a esa solicitud con un recurso que se comprimió con el diccionario para la codificación aplicable. La forma en que se logra esto en la práctica depende de si la solicitud es para un recurso estático o dinámico.
Compresión de diccionarios compartidos para recursos estáticos
Un recurso de página estático es aquel que siempre produce la misma respuesta para una URL solicitada. Los ejemplos comunes de recursos de página estáticos comprimibles son los archivos JavaScript y CSS. Por lo general, estos recursos tienen versiones para fines de almacenamiento en caché de alguna manera, a veces con un hash del contenido del archivo en el nombre de archivo (por ejemplo, styles.abcd1234.css) o algún otro método de huella digital del recurso. Estos tipos de recursos son un excelente candidato para la compresión delta que proporcionan los diccionarios compartidos, ya que los recursos estáticos suelen almacenarse en caché durante períodos prolongados y tienden a actualizarse con cierta frecuencia.
Para especificar un diccionario para un recurso estático, configura el encabezado de respuesta Use-As-Dictionary. El encabezado toma uno de los pares clave-valor, pero el único obligatorio es match, que acepta la sintaxis URLPattern que especifica la ruta del recurso en la que se debe usar el diccionario:
Use-As-Dictionary: match="/dist/styles.*.css"
Piensa en el encabezado Use-As-Dictionary como un mecanismo que se aplica a las versiones futuras de un recurso que coinciden con el patrón especificado en él. Por ejemplo, supongamos que tu sitio web envía todos sus estilos en un solo archivo CSS. Para simplificar, supongamos que la primera versión de ese recurso se encuentra en /dist/styles.v1.css y se envía con un encabezado de respuesta Use-As-Dictionary que contiene un valor match de /dist/styles.*.css.
Después de un tiempo, actualizas el CSS de tu sitio web y envías una versión nueva ubicada en /dist/styles.v2.css. Debido a que el valor match que se usa en el encabezado de respuesta Use-As-Dictionary de la versión anterior se aplica a esta solicitud, el navegador enviará un encabezado Available-Dictionary que contiene un hash del diccionario codificado como una secuencia de bytes de campo estructurada:
Accept-Encoding: gzip, br, zstd, br-d, zstd-d
Available-Dictionary: :pZGm1Av0IEBKARczz7exkNYsZb8LzaMrV7J32a2fFG4=:
En este punto, depende del servidor configurar la compresión en su extremo para garantizar que se use el diccionario coincidente. Luego, se enviará el recurso comprimido con ese diccionario, y se usará el diccionario disponible en la caché del navegador del usuario para descomprimirlo.
Si envías código nuevo con frecuencia para tu sitio web, la compresión delta puede ser muy útil. Sin embargo, el proceso es flexible. Si el navegador no determina que hay un diccionario disponible en la caché del navegador del usuario, no especificará los tokens br-d o zstd-d adicionales en el encabezado Accept-Encoding. En ese caso, se aplica el flujo de compresión estándar.
Compresión de diccionarios compartidos para recursos dinámicos
Los recursos dinámicos también pueden beneficiarse de la compresión de diccionarios compartidos. Los recursos dinámicos son aquellos que cambian según un contexto, como un sitio web de noticias en el que la página principal se actualiza con frecuencia a medida que se publican noticias, por ejemplo. Los documentos HTML suelen ser recursos dinámicos. En esos casos, el diccionario puede contener la mayor parte de la estructura HTML común del sitio y el código de plantilla que lleva a páginas comprimidas en las que solo se envían las partes únicas de cada página.
Debido a la naturaleza de los recursos generados de forma dinámica, se debe cargar un diccionario en el cliente para su uso posterior. Cargar un diccionario con anticipación significa que aplicar la compresión de diccionarios compartidos a recursos dinámicos es especulativo. En esos casos, se espera que tu sitio web reciba suficiente tráfico para que el costo del diccionario se pueda amortizar en una gran cantidad de navegaciones. Si decides probarlo, el primer paso es especificar la ubicación del diccionario mediante un elemento <link> en el HTML de tu página:
<link rel="dictionary" href="/dictionary.dat">
Cuando Chrome encuentra este elemento <link>, puede recuperar el diccionario una vez que la página esté inactiva y con baja prioridad para evitar la contención de ancho de banda. La respuesta para el diccionario en sí debe especificar un encabezado Use-As-Dictionary y especificar a qué ruta de recurso dinámico se aplica:
Use-As-Dictionary: match="/product/*"
A partir de aquí, el flujo es en gran medida el mismo que para los recursos estáticos. El navegador verá que el diccionario en sí se aplica a los recursos coincidentes y adjuntará un encabezado Available-Dictionary a la solicitud con un hash del contenido del diccionario, de nuevo, similar al flujo de recursos estáticos explicado anteriormente.
Comprime recursos estáticos en el momento de la compilación
Si estás familiarizado con los empaquetadores, es posible que conozcas varios complementos para ellos que pueden comprimir recursos en el tiempo de compilación y, luego, publicar esos recursos comprimidos. Por ejemplo, Apache te permite usar directivas para publicar esos recursos precomprimidos en el momento de la solicitud.
La mayoría de los empaquetadores basados en Node.js que admiten la compresión usan la biblioteca Zlib integrada de Node. Zlib ofrece compatibilidad con Brotli y los empaquetadores que lo usan suelen ofrecer una interfaz para pasar opciones directamente a Zlib, que admite la compresión asistida por diccionario. Estos son algunos empaquetadores que admiten el uso de diccionarios:
CompressionWebpackPluginde webpack, a través de su interfazcompressionOptions.rollup-plugin-brotliofrece una configuraciónoptionsque pasa directamente a Zlib en Node.js, donde se pueden especificar diccionarios.- El complemento de terceros
esbuild-plugin-compresspara esbuild también ofrece acceso a las opciones de Zlib en Node.js.
Ten en cuenta que los diccionarios disponibles para cualquier versión determinada de un recurso pueden usar una de las versiones anteriores de un recurso. Esto significa que deberás analizar el tráfico de usuarios y planificar en consecuencia. Busca un equilibrio y genera recursos que beneficien a la mayor cantidad de usuarios recurrentes de la mejor manera posible. Los proveedores de CDN están experimentando con la compresión de diccionarios compartidos. Aún no hay implementaciones disponibles para el uso público, pero esperamos que eso cambie.
¡Pruébalo!
La integración de la compresión de diccionarios compartidos con las capacidades de compresión existentes del navegador tiene el potencial de mejorar considerablemente el rendimiento de carga de los sitios web que suelen enviar código de producción actualizado y reciben tráfico significativo de visitantes recurrentes. Si te interesa probar la compresión de diccionarios compartidos, tienes dos opciones:
- Si solo quieres experimentar con la compresión de diccionarios compartidos por tu cuenta para comprender cómo funciona, puedes habilitar la función experimental Transporte de diccionarios de compresión en la página
chrome://flags. - Si te interesa probar esto en tu sitio web de producción y ver cómo la compresión de diccionarios compartidos podría beneficiar a los usuarios reales, regístrate en la prueba de origen para obtener un token y lee sobre cómo funcionan las pruebas de origen.
Conclusión
Estamos muy entusiasmados con este gran avance en la tecnología de compresión en la Web y con la rapidez con la que podría hacer que las aplicaciones existentes que las personas usan todos los días sean más rápidas. Te recomendamos que lo pruebes y, lo que es más importante, queremos conocer tu opinión si lo haces. Si encuentras un error, infórmalo en crbug.com. Para obtener recursos y herramientas adicionales, consulta use-as-dictionary.com. Por último, si te interesa obtener más información sobre cómo funciona todo, la explicación es un buen paso siguiente.