Puro Cacheo

En el #juevesdeblog de hoy daremos una pequeña introducción teórica al funcionamiento general de una CDN pull y pequeños consejos para intentar optimizar su funcionamiento.

¿Cómo funciona todo esto?

La CDN no es más que lo que se conoce como un proxy inverso. Esto quiere decir que las peticiones a una web www.ejemplo.com, en vez de ir directamente contra los servidores que alojan esta, se dirigen a otra dirección IP (la de la CDN), que a su vez dirige la petición a los servidores que la alojan. Este paso intermedio haría que la web fuese más lenta en lugar de más rápida si no fuera por el cacheo. Cachear un recurso web (una página, una imagen, un vídeo) significa hacer una copia estática de ese recurso, una especie de “fotocopia”, que se queda almacenada en el servidor de la CDN. Esta copia se sirve a todas las peticiones que llegan a partir de ese momento y se hace durante un lapso de tiempo configurable (más sobre esto en la siguiente sección). De esta manera, el servidor de origen está libre de volver a generar la misma página hasta que ‘caduque’ la copia en el servidor de la CDN y ninguna petición a la misma URL alcanzará el servidor de origen.

Transparent CDN da la posibilidad de forzar la caducidad de una URL en la CDN mediante la funcionalidad de invalidación, ya sea mediante API o en el panel.

Cabecera Cache-Control

Según la RFC-7234, que es el documento que define cómo realizar el cacheo de un recurso web, la principal herramienta que puede utilizar un servidor para controlar cómo se cachea ese recurso es la cabecera http Cache-Control. A pesar de existir muchas opciones y directivas para esta cabecera, en este documento nos vamos a centrar en las más simples: max-age y s-maxage.

La primera de ella es la más utilizada de las dos y define el tiempo general que puede vivir ese recurso en una caché, sea esta el navegador del usuario o una caché intermedia como una CDN o un proxy corporativo de acceso a internet.

La segunda se refiere específicamente a cachés compartidas como una CDN y excluye cachés privadas, como es el caso del navegador. En caso de existir ambas, s-maxage se aplica a la CDN y max-age, al navegador.

Ambas se definen en segundos. Por ejemplo, Cache-Control: max-age=3600s marcaría que tanto el navegador como las CDN que pudieran servir el recurso guarden una copia del contenido durante una hora (3600 segundos).

La Mozilla Developer Network tiene un documento fantástico sobre todas las opciones que proporciona la cabecera.

Páginas dinámicas

El cacheo tiene un inconveniente: por la propia naturaleza dinámica de muchas webs, a veces queremos que a cada usuario se le muestre un recurso distinto para la misma URL. Esto significa que a priori no podemos cachear estas peticiones, que contienen información distinta para cada usuario en función de determinados parámetros, como cookies, cabeceras de autenticación, etc. Los casos más comunes que las CDN tienen contemplados como “nunca cachear” para evitar filtrar por accidente información sensible son:

  • Recursos pedidos por POST:
    Las peticiones habituales a recursos, como cuando escribimos una URL en nuestro navegador, se realizan mediante el método GET. Los formularios, y en general todas aquellas peticiones que modifican el estado del servidor o base de datos, como logins, compras en e-commerce, altas en una web, se realizan mediante el método POST y, por ello, nunca se almacenan en la CDN.
  • Recursos que establecen una cookie:
    Las cookies son uno de los mecanismos preferidos por las webs para establecer información específica y persistente para el usuario. Cuando una web manda una cabecera Set-cookie, está especificando que ese navegador debe incluir esa cookie en llamadas subsiguientes a ese dominio para poder identificar a ese usuario y tener una trazabilidad, debido a la naturaleza state-less del protocolo HTTP. Por este motivo, y dado que la cookie es única para cada usuario, recursos en los que el servidor fije esta cabecera no pueden ser cacheados por los proxys intermedios, ya que entonces darían la misma “cookie” a todas las visitas para esa página.
  • Recursos que exigen autorización:
    Todas las peticiones que incluyan una cabecera Authorization serán pasadas al origen, puesto que son peticiones que llevan información que autoriza al usuario y, como tal, es sensible y no debe ser cacheada por proxies intermedios.

Necesito cachear y también tener sesiones, ¿hay algo que pueda hacer?

 

Sí, aunque exige tener en cuenta ciertas directrices a la hora de desarrollar la web. La idea es maximizar el número de recursos cacheables, aislando y acotando la información que varía en función del usuario. El ejemplo más habitual es la información del carrito de la compra en un e-commerce: en una página web de un listado de productos, será todo igual para todos los usuarios salvo esa información de carrito y, opcionalmente, alguna otra como el nombre de usuario o datos de la cuenta. Si todos estos elementos diferenciadores no están “empotrados” en el HTML, se puede cachear el HTML de la página y pedir via AJAX estos elementos distintos, sustituyéndolos en el DOM de la página con Javascript.

Lo mismo ocurre con las cookies: si programamos para centralizar el establecimiento de la cookie de usuario en una URL ligera que se llame mediante Javascript en todas las páginas, nos aseguramos de que el recurso principal (la página en sí) sea HTML cacheable, pero mantenemos la funcionalidad de que cada visitante de nuestra página tenga su sesión. Esta la utilizaremos en los puntos cruciales como el pago o el carrito (que por su naturaleza suelen ser llamadas POST y, por tanto, no se cachean) sin perjudicar a la eficiencia de la caché.

Es importante distinguir entre las cookies en sí y su establecimiento. Una vez establecidas, no hay ningún problema con las cookies. El único punto de atención está en los recursos que las establecen mediante la cabecera set-cookie. Se debe intentar que sean lo más puntuales posibles y centrados en URLs accedidas por POST o que sean ligeros, ya que irán siempre hasta el origen “saltando” la CDN.

Vary y las diferentes variantes del mismo recurso

Hasta ahora hemos dicho que las webs dinámicas no son “cacheables” en una CDN porque tienen información privada de usuario y, al estar bajo la misma URL, cachearlas implicaría mostrar siempre lo mismo a todos los usuarios, ¿no?

No necesariamente. Aquí entra en juego la cabecera Vary, que se usa para indicar que una URL en concreto tiene “variantes”. En esa cabecera se puede detallar en función de qué varían las representaciones de esa URL. Puede ser cualquier cabecera de la request y, gracias a la funcionalidad de Transparent CDN, cualquier aspecto de la petición se puede modelar como una cabecera.

Ejemplos de esto sería que guardásemos una versión de la página por cada usuario conectado, o una versión para los visitantes de España y otra para el resto del mundo. Las posibilidades que brinda VCL a tal efecto son muy extensas. Un snippet de código para hacer tests A/B según país podría ser el que sigue:

sub vcl_recv {

if  (req.http.geo_country_code ~  «^/ES»){

   set req.http.abtesting = «A»;

else {

    set req.http.abtesting = «B»;

}

set req.http.X-Vary-TCDN = req.http.X-Vary-TCDN + «,abtest:»+ req.http.abtesting;   

}

Con este trozo de código nos aseguraríamos de guardar una versión distinta para España y el resto del mundo, ya que la cabecera sintética que hemos definido “abtesting” tendrá diferente valor. Algo parecido podríamos hacer si tenemos identificado al usuario en una cookie “user”:

sub vcl_recv {

   set req.http.myuser = cookie.get(«user»);

   set req.http.X-Vary-TCDN = req.http.X-Vary-TCDN + «,usuario:»+ req.http.myuser;   

}

Resumen

Como hemos visto en esta entrada, existen multitud de maneras de hacer que nuestra web saque todo el rendimiento posible a la CDN, y estas son solo unas pocas. Si tienes dudas o sugerencias, recuerda que nuestro soporte está ahí para ayudarte.