CDN frente a caché
Una red de distribución de contenidos (CDN) es un sistema de servidores distribuidos que distribuyen contenidos y páginas web a los usuarios en función de su ubicación geográfica, con el fin de mejorar el rendimiento y reducir la latencia. Una CDN se encarga del almacenamiento en caché, que es una de sus funciones principales. Almacena en caché los archivos esenciales de tu sitio web, como páginas HTML, archivos JavaScript, archivos CSS, imágenes y vídeos, en servidores de borde, lo que se traduce en tiempos de carga más cortos.
¿Qué es la caché de una CDN?
En el contexto de las CDN, el almacenamiento en caché reduce la latencia al permitir la entrega de contenido desde una ubicación más cercana al usuario, lo que mejora significativamente los tiempos de carga. Funciona almacenando copias del contenido en servidores de borde distribuidos por todo el mundo. Cuando un usuario realiza una petición de contenido, la CDN lo distribuye desde el servidor de borde más cercano en lugar de esperar a que el servidor de origen responda. Así, se reduce la carga de trabajo del servidor de origen y se puede gestionar un mayor volumen de tráfico al distribuir las peticiones entre varios servidores.
Dado que una CDN es, en esencia, una caché, quizá sientas la tentación de evitar la complejidad y prescindir de la caché del navegador. Sin embargo, cada caché tiene ventajas que la otra no ofrece. En este artículo, se explicarán las ventajas de cada una y cómo combinarlas para obtener el máximo rendimiento del sitio web y la mejor experiencia para los usuarios finales.
¿Qué es el cache busting?
El cache busting consiste en subir un nuevo archivo para sustituir a otro que ya existe y está almacenado en la caché. Esta técnica es útil porque evita que el navegador recupere el archivo antiguo que se está sustituyendo.
Razones para navegar con la caché de una CDN
Aunque las CDN hacen un buen trabajo a la hora de entregar los activos con mucha rapidez, no pueden hacer mucho por los usuarios que se encuentran en zonas remotas y apenas tienen una barra de recepción en su teléfono móvil. De hecho, en Estados Unidos, el percentil 95 del tiempo de ida y vuelta (RTT) a todas las CDN supera con creces los 200 milisegundos, según los informes de Cedexis. Esto significa que, como mínimo, el 5 % de tus usuarios, si no más, probablemente experimenten lentitud al acceder a tu sitio web o aplicación. A modo de referencia, el percentil 50 o mediana del RTT es de alrededor de 45 milisegundos.
Entonces, ¿por qué molestarse en usar una CDN? ¿No basta con la caché del navegador?
Control. La mayoría de las CDN te permiten purgar tus activos de la caché, lo que resulta muy útil cuando realizas cambios. Esta opción no está disponible para la caché del navegador.
Las primeras impresiones importan. La caché del navegador no ayuda en absoluto la primera vez que un usuario visita tu sitio, ya que está fría (vacía de objetos útiles). Las CDN hacen que la experiencia de uso con una caché fría sea lo más rápida posible y, si está caliente, las páginas consecutivas serán aún más rápidas.
Las CDN todavía tienen una ventaja geográfica. Incluso si un usuario se encuentra en el percentil 95, un RTT de 250 milisegundos es mejor que uno de 350 milisegundos. Sobre todo, si se tiene en cuenta que cada activo realizará al menos un trayecto de ida y vuelta en una conexión abierta, pero se necesita un trayecto de ida y vuelta adicional para abrir dicha conexión. La seguridad de la capa de transporte (TLS, anteriormente conocida como SSL) añade al menos un trayecto de ida y vuelta más por conexión, y a veces dos. Todos estos trayectos de ida y vuelta adicionales se acumulan rápidamente.
Las CDN son mucho más eficientes, ya que su caché se comparte entre todos los usuarios. Esto reduce la carga de los servidores de origen y elimina la necesidad de una capa de almacenamiento en caché en la plataforma.
Uso simultáneo de la CDN y la caché del navegador
Ahora que hemos determinado que una CDN sigue siendo importante y que la caché del navegador también lo es, aquí hay dos enfoques para combinarlas:
Un tiempo de vida (TTL) corto para la caché del navegador, combinado con TTL largos y purga en el lado de la CDN.
Un TTL largo para la CDN y la caché del navegador, con cache busters basados en versiones.
A continuación, analizaré cada enfoque en detalle y explicaré cómo se pueden combinar.
TTLs cortos y largos
Lo ideal sería utilizar un TTL para la caché del navegador que abarcara toda una visita, pero no mucho más. Así, los usuarios disfrutarán de una carga rápida de las páginas durante toda su visita y no se encontrarán con recursos obsoletos si vuelven más tarde. Tus herramientas de análisis deberían poder indicarte cuál es la duración media de las visitas a tu sitio web; no obstante, entre 5 y 10 minutos es una buena estimación.
Por parte de Fastly, recomendaría utilizar un TTL de un mes o un año, por ejemplo, y configurar la purga como parte del pipeline de despliegue para que Fastly pueda distribuir las nuevas versiones lo antes posible. Para obtener más información sobre las purgas, consulta https://docs.fastly.com/guides/purging/.
Ten en cuenta lo siguiente: no envíes el comando de purga hasta que tengas la certeza de que las nuevas versiones de los activos que estás actualizando serán servidas por el origen. He sido testigo de casos en los que alguien ha enviado una purga a Fastly y Fastly ha recuperado inmediatamente el archivo antes de que se completara la sincronización con los servidores de origen, lo que ha provocado mucha confusión.
Para configurar el TTL de la caché del navegador, debes utilizar un encabezado Cache-Control en la respuesta del origen. A continuación, utiliza el encabezado Surrogate-Control o una anulación en la configuración de Fastly para configurar el TTL.
Aquí tienes un ejemplo:
Cache-Control: max-age=600
Surrogate-Control: max-age=31536000En el ejemplo anterior, el encabezado Cache-Control dará instrucciones al navegador para almacenar en caché durante 10 minutos; y a Fastly para hacerlo durante un año. El encabezado Surrogate-Control se elimina antes de que la respuesta se envíe al cliente, ocultando este detalle de implementación a los usuarios. Si te interesa, puedes consultar nuestra documentación para obtener más información sobre cuáles son los encabezados que te pueden servir para controlar los TTL con Fastly.
Cache busters basados en versiones
A pesar de su nombre, los cache busters pueden mejorar el almacenamiento en caché si se utilizan con prudencia. Básicamente, un cache buster es un nuevo parámetro de cadena de consulta que se añade a la URL. Mientras que los servidores web y la mayoría de los servidores de aplicaciones ignoran los parámetros de la cadena de consulta que no les interesan, las cachés deben asumir que cualquier diferencia en dicha cadena influirá en el resultado. Esto incluye la caché del navegador. Los navegadores deben tratar cada uno de los siguientes elementos como objetos únicos, incluso si el servidor devuelve la misma respuesta para todos ellos:
https://www.example.com/css/main.css, https://www.example.com/css/main.css?cb=foo, y https://www.example.com/css/main.css?foo=bar
Supongamos que tu aplicación está en la versión 133. En lugar de enlazar a https://www.example.com/css/main.css tu app enlazaría a https://www.example.com/css/main.css?v=133. Cuando creas la versión 134, enlazarás a https://www.example.com/css/main.css?v=134. Ahora, el navegador tiene que recuperar esta nueva versión de main.css, aunque todavía tenga una copia sin caducar.
Las prácticas habituales consisten en utilizar un hash (corto) del contenido del archivo, un número de compilación o un hash de confirmación.
Mi preferencia personal es utilizar un hash del contenido del archivo. De esta manera, el cache buster solo cambia cuando se modifica el contenido. Con los números de compilación o los hashes de confirmación, el caché buster cambia cada vez que se modifica algo. Sin embargo, dado que todas las URL de los activos de tu sitio deben incluir el cache buster, puede resultar más fácil utilizar el número de compilación o el hash de confirmación.
El inconveniente de este enfoque es que hay que actualizar todas las URL de los activos cada vez que se produce un cambio. La ventaja es que puedes almacenar tus activos en la caché del navegador con unos TTL largos y seguir haciendo que el navegador recupere los activos actualizados cuando la caché esté desactualizada.
Mezcla y combina
Dado que la CDN de Fastly te permite purgar contenido obsoleto en 150 ms, también deberías considerar almacenar en caché todas tus páginas HTML. Sin embargo, aunque puedas rediseñar tu sitio para utilizar cache busters en activos como imágenes, hojas de estilo y JavaScript, nunca debes utilizarlos en las URL de las páginas propiamente dichas, ya que los motores de búsqueda como Google te penalizarán por tener cadenas de consulta en las URL de las páginas.
Por lo tanto, al almacenar páginas en caché, considera utilizar la técnica TTL corta y larga para tus páginas y caché busters para los activos utilizados por dichas páginas.
Aspectos avanzados: la revalidación
Un efecto secundario muy interesante del uso de la caché del navegador es que este conserva los objetos aunque hayan caducado y envía encabezados de revalidación adicionales con sus solicitudes. Si el objeto solicitado no ha cambiado, la CDN puede responder con un estado 304 No modificado, que no tiene cuerpo, indicando al navegador que puede utilizar el objeto caducado y, opcionalmente, proporcionar un nuevo TTL.
Aunque cada solicitud que recibe una respuesta 304 sigue necesitando un trayecto de ida y vuelta para completarse, el hecho de que no se envíe el cuerpo de la respuesta supone un ahorro considerable de ancho de banda. Esto no solo beneficia a los usuarios con conexiones lentas, sino que también puede ayudarles a reducir sus pagos mensuales por CDN.
Para que la revalidación funcione, solo tienes que asegurarte de que tu origen incluya un encabezado Last-Modifiedo un encabezado ETag en sus respuestas. La buena noticia es que la mayoría de los servidores web ya incluyen Last-Modified y ETag como encabezados para cualquier archivo estático que distribuyen desde el disco. El valor del encabezado Last-Modified se basa en el tiempo de modificación del archivo. El valor del encabezado ETag se basa (en Apache) en el tiempo de modificación, el número de inodo y el tamaño.
Cuando un navegador detecte uno de estos dos encabezados, o ambos, en objetos caducados de su caché, añadirá un encabezado If-Modified-Since con el valor de Last-Modified y añadirá un encabezado If-None-Match con el valor de ETag. Se considera que un objeto no ha cambiado si los valores de If-None-Match y ETag son iguales, y si el valor de If-Modified-Since coincide o es posterior al valor de Last-Modified.
Si cuentas con un único servidor web para tus activos estáticos, es probable que la revalidación ya funcione perfectamente gracias a los valores predeterminados comunes.
Sin embargo, si utilizas varios servidores web para garantizar la redundancia y cada uno de ellos tiene almacenamiento local en lugar de almacenamiento compartido, es posible que la revalidación falle aleatoriamente. Dado que no se puede garantizar que a un archivo específico se le asigne el mismo número de inodo en cada servidor web, el encabezado ETag generado para dicho archivo será diferente en cada servidor. Además, la mayoría de los scripts de despliegue no conservan la hora de modificación al copiar archivos, por lo que el encabezado Last-Modified también será diferente.
Esto es negativo por dos razones. En primer lugar, cuando Fastly se comunica con tu origen, se podría desperdiciar mucho ancho de banda innecesario en respuestas completas en lugar de respuestas 304. En segundo lugar, Fastly podría terminar teniendo valores diferentes de ETag y Last-Modified en diferentes servidores. Dado que no se garantiza que los navegadores se comuniquen con el mismo servidor para cada petición, también podrían obtener respuestas completas innecesarias debido a una discrepancia en los valores.
Para aprovechar al máximo la revalidación, si tienes varios servidores web con almacenamiento local, te recomiendo que desactives ETag y utilices exclusivamente Last-Modified, además de asegurarte de que tu script de implementación conserve la hora de modificación al copiar archivos.
Si utilizas un proveedor de almacenamiento en la nube, como Google Cloud Storage o Amazon S3, el encabezado ETag ya debería estar configurado automáticamente con un hash del contenido. Esto convierte al almacenamiento en la nube en uno de los orígenes más óptimos para Fastly, ya que volver a cargar el mismo archivo no modifica su ETag.
