Tutorial Cache Web: cómo gestionar el cacheo de nuestros contenidos

El concepto de cache (sin acento, a no confundir con la palabra caché que significa distinción o elegancia) es ampliamente utilizado en todos los campos de la informática. De manera general podríamos definirlo como el proceso en el que un conjunto de datos son duplicados con el fin de reducir el tiempo de acceso a la información original y optimizar el rendimiento de un sistema.

En el terreno web, el cacheo es el proceso de almacenamiento de documentos web (una página html, una imagen, una librería javascript, etc) con el objetivo de reducir el ancho de banda consumido por los visitantes, la carga de los servidores que atienden peticiones web y el retardo de una descarga. Una cache web almacena una copia de los documentos que son devueltos por un servidor de de tal forma que el mismo se encarga de atender las peticiones siguientes.

A la hora de definir una web en la que se espera un tráfico elevado cobra especial relevancia establecer una política de cacheo que permita crear un sistema escalable y evitar problemas a la hora de atender las peticiones de nuestros usuarios.

Existen tres tipos de caches que pueden actuar durante el proceso de solicitud de un documento web:

  1. Cache de Agente de Usuario (User-Agent): Está presenten en los navegadores web y lógicamente sólo funcionan para un único usuario.
  2. Cache Compartida o proxy-cachés directos: Este tipo de cache son utilizados por los proveedores de servicios de Internet y empresas para ahorrar ancho de banda. La comparten todos los usuarios que accedan.
  3. Cache pasarela o proxy-cachés inversos: Funcionan como respaldo de un servidor web de tal forma transparente para los usuarios. Es posible trabajar con varias cache pasarela de manera conjunta para implementar una Content Delivery Network (CDN) (pjem: Akami)

Tipo de Cache
Si planificamos correctamente un Site, la cache nos ayudará a mejorar el tiempo de carga y a gestionar de manera eficiente el ancho de banda de nuestro servidor. El incremento de rendimiento puede ser excepcional y la experiencia de nuestros visitantes mejorará notablemente sin necesidad de invertir ni un sólo euro.

Cómo se gestiona una petición web

Para comprender el proceso de cacheo es indispensable entender qué ocurre durante la carga de una web. El siguiente gráfico muestra como se comunican un navegador y un servidor web durante la solicitud y envío de una página no cacheada:

1. Navegador: Hola!, ¿podrías mandarme el archivo ejemplo.htm?

2. Servidor: Claro, espera un momento que lo busco en mi disco duro.

3. Servidor: Aquí esta!

4. Servidor: Te lo mando chico, cuidado que es un poco pesada 100kb y mi ancho de banda es limitado.

5. Navegador: Mucha gracias ya lo estoy descargando y mostrándoselo al usuario.

Si la página se encuentra cacheada el proceso podría ser similar el siguiente:

1. Navegador: Hola!, ¿podrías mandarme el archivo ejemplo.htm?

2. Servidor: Claro, espera un momento estoy comprobando la fecha de modificación del archivo.

3. Servidor: Aquí está!, y veo que no se ha modificado el fichero desde la última vez que lo solicitaste.

4. Servidor: Estás de suerte, la versión que tienes en tu cache es la última.

5. Navegador: Genial, entonces no hace falta que me la envíes ya estoy mostrando al usuario la página que tengo cacheada.

Qué métodos de cacheo existen.

Existen tres tipos de mecanismos que permiten gestionar el cacheo de un contenido:

1. Mecanismos por Validación (validation): En este mecanismo el servidor comprueba si la respuesta que mantiene cacheada el navegador sigue siendo válida. Existen dos variantes:

Last-Modified

Cuando el servidor devuelve un documento por primera vez a un navegador adjunta también la fecha de modificación del fichero (Last-modified):

<meta http-equiv="last-modified" content="Fri, 14 Dec 2007 12:58:00 GMT" />

La próxima vez que el navegador solicite el documento, el servidor enviará como respuesta el mensaje “Not Modified” en el caso de que el documento no haya sido modificado desde su última petición. El navegador mostrará entonces al usuario el documento que tiene almacenado en su cache.

ETag (Entity Tag)

El método Last-Modified no es infalible y puede presentar problemas si existen desajustes en el reloj interno del servidor Web.

ETag es un identificador único (un hash MD5) que se identifíca de manera única cada fichero cada vez que se crea o modifica. De esta manera, en vez de comprobar la fecha de modificación se chequea su ETag para conocer si ha cambiado respecto a la versión cacheada:

ETag: h3110g00g13

Contenido del fichero solicitado.

Más adelante podrá ver como realizar se puede realizar esta comprobación en el servidor.

2. Mecanismos por Frescura (freshness): Tanto el método Last-Modified como ETag requieren que el navegador se comunique con el servidor para comprobar la versión del fichero. En los mecanismos por frescura en cambio cada repuesta lleva asociada una fecha de caducidad (como un yogurt) y puede ser utilizada sin necesidad de que el servidor compruebe su validez. Existen dos formas de implementar este mecanismo:

Expires.

El Método Expires consiste en asignar una fecha de caducidad al fichero, el navegador no solicita al servidor una versión nueva hasta que no se traspasa la fecha de expiración del archivo.

<meta http-equiv="Expires" content="Mon, 14 Dec 2007 12:58:00 GMT">

De esta forma la comunicación se reduce a un monólogo entre el navegador que no solicita una nueva versión al servidor mientras no se exceda el periodo de expiración del fichero.

Max-age

Es un método similar a Expires con la particularidad de que la fecha de caducidad del documento se establece de manera relativa, es decir, “Este documento expirara dentro de x segundos a partir de hoy”.

<meta http-equiv="Cache-Control" content="max-age=3600“>

Recuerde que el tiempo se debe establecer en segundos, un año por ejemplo serían 31.536.000 de segundos.

3. Mecanismo por Invalidación: Este mecanismo se deriva de otra petición que pasa por la caché. Por ejemplo, si la url asociada con una respuesta cacheada es solicitada más tarde a través de una petición POST, PUT o DELETE, la respuesta que se encontraba cacheada quedará invalidada. Esto es lo que ocurre por ejemplo cuando intenta navegar hacia atrás en su historial tras haber enviado los datos de un formulario.

Además tenga en cuenta que existen una serie de reglas que también aplican al cacheo de contenidos y deben tenerse en cuenta:

  • Bajo determinadas circunstancias, como por ejemplo, cuando un equipo se desconecta de la red, la cache puede servir páginas sin consultar con el servidor de origen.
  • Un documento nunca se cachea si la cabecera del documento indica de manera explicita que no es cachee.
  • Si se utiliza un protocolo seguro ((HTTPS) la página nunca será cacheada.

Cómo evitar el cacheo de nuestros contenidos

En ocasiones el cacheo de contenidos puede interferir con el correcto funcionamiento de la web y por tanto debemos evitarlo. El funcionamiento de la cache se puede controlar con las siguientes directivas:

  • Cache-control: max-age – Especifica el número máximos de segundos en los que el contenido sera considerado como fresco
  • Cache-control: s-maxage – Similar a la directiva max-age, pero aplicable solo para caches compartidas (pejm: un proxy).
  • Cache-control: public – indica que la versión cacheada puede ser guardada por proxies y otros servidores intermedios para que todo el mundo tenga acceso a ella..
  • Cache-control: private – indica que el archivo no es el mismo para usuarios diferentes. De esta manera el archivo puede ser cacheado por el navegador del usuario pero no debe ser cacheado por proxies intermedios.
  • Cache-control: no-cache – Significa que el archivo no debe ser cacheado, esto puede ser necesario en casos en los que una misma url pueda devolver diferentes contenidos.
  • Cache-control: no-store – Indica al navegador que sólo guarde el documento el tiempo necesario para mostrarlo. Le recomiendo la lectura del siguiente artículo dónde se alerta sobre el peligro de utilizar la directiva no-store en situaciones no adecuadas.
  • Cache-control: must-revalidate – Indica a la cache que deben hacer caso a cualquier directiva de cacheo que le indiquemos. Tenga en cuenta que la especificación HTTP permite a las caches atender de manera automática a las peticiones bajo determinadas circustancias. ¨La directiva must-revalidete obliga a la cache a seguir nuestras directivas de manera estricta. La forma de utilizarla es la siguiente:

    <meta http-equiv="Cache-Control" content="max-age=3600, must-revalidate“>

  • Cache-control: proxy-revalidate – Similar a must-revalidate pero sólo aplicable a proxy caches.

Como ve no existe una única forma que indicar que una página no sea cacehada por un navegador. Generalmente se utiliza la siguiente cabecera:

<meta http-equiv="Cache-Control" content="max-age=0, no-cache, no-store, private">

<meta http-equiv="Pragma" content="nocache">

La directiva Pragma tiene el mismo significado que Cache-control: no-cache y se suele incluir para asegurarnos la compatibilidad con versiones anteriores a HTTP/1.0. ( Debe tener en cuenta que alguna de estas directivas sólo funcionan con las navegadores modernos.)

En lugar de utilizar el tag meta también puede crear las cabeceras HTTP para sus documentos con cualquier lenguajes de scripting de servidor: PHP, ASP, .NET, etc. Recuerde que cualquier directivas de cacheo deben incluirse al principio del documento, incluso antes del tag html. Aquí le muestro algunos códigos de ejemplo:

php:

header("Cache-Control:...");

header("Pragma:...");

Cold Fusion

<CFHEADER NAME="Expires" VALUE="...">

ASP

<% Response.CacheControl="..." %>

ASP. net

Response.Cache.SetExpires (... )

Tipo de páginas en función de su cacheabilidad

Una web puede ofrecer tres tipos de contenidos en función de su cacheabilidad.

  1. Contenidos estáticos: Son aquellos contenidos que ya existen físicamente en el servidor, tienen un tamaño fijo y una fecha determinada. Una página html, una imagen o un documento pdf son ejemplos de contenidos estáticos. Este tipo de contenidos son firmes candidatos a ser cacheados.
  2. Contenidos dinámicos: Son contenidos que se crean en el momento en el que se solicitan accediendo, por ejemplo, a una base de datos. Este tipo de páginas son independientes del perfil del usuario que las visita y por tanto son potencialmente cacheables.
  3. Contenidos personalizados: Este tipo de contenidos se crean a medida en base a las características de la petición y pueden ser diferentes en función de quién, cuándo, o cómo es solicitada. Por este motivo este tipo de contenidos no son buenos candidatos a ser cacheados, aunque como veremos más adelante hay técnicas que permiten cachearlos de manera parcial o total. El área privada de la web de un banco, o un carrito de la compra son dos ejemplos de páginas personalizadas.

Es muy importante que entendamos qué contenidos pueden y deben cachearse y cuales no. Si no gestionamos eficientemente el cacheo corremos el riesgo de servir a nuestros usuarios un contenido que no está actualizado o por otro lado saturar nuestro servidor con peticiones innecesarias.

Estrategias de cacheo

Para optimizar la eficiencia del cacheo de contenidos tanto en el navegador como en los servidores proxy existen una serie de estrategias que podemos tener en cuenta:

1. Evite utilizar Query String

Utilizar Friendly URLs en lugar de query strings facilita el cacheo de los contenidos. Algunos navegadores y muchos proxies cache no cachean contidos que lleven una query string en la URL.

Recuerde que puede utilizar mod_rewrite en Apache Web Server para implementar friendly urls.

2. Organice eficientemente sus contenidos

Puede organizar sus contenidos en cacheables y no cacheables, ubicándolos en diferentes rutas dentro del servidor.

Por ejemplo es una práctica habitual ubicar los contenidos no cacheables de una web en /cgi-bin/ y configurar el servidor para que informe a los navegadores con las cabeceras HTTP necesarias de que este contenido no sea cacheado.

3. Envíe la cabecera Last-Modified

Incluya en sus documentos la información Last-Modified. De esta manera los navegadores podrán hacer peticiones condicionales del tipo if-Modified-Since (IMS) para que el servidor le entregue el contenido sólo en el caso de que su cache haya caducado.

Para las páginas estáticas no existen ningún problema ya que existen físicamente el el servidor y tienen un time stamp asociado, pero en el caso una página dinámica donde el contenido no existe fisicamente, es la propia aplicación la que debe preguntar si el contenido ha cambiado.

Una gestión eficiente de las solicitudes condicionales tiene una repercusión muy positiva en el ahorro de ancho de banda del servidor web.

Estratégias de cacheo para páginas personalizadas

Aquellas contenidos que se deben mostrar de manera personalizada para cada usuario también pueden ser objeto de cacheo si tenemos en cuenta las siguientesconsideraciones:

1. Evite incluir fragmentos dependientes de la sesión HTTP del usuario

Cuando un documento web se crea dinámicamente en el servidor web, evite que alguno de los elementos que componen la página dependa de la sesión HTTP del usuario. De esta manera conseguirá optimizar el cacheo de cada elemento y se podrá integrar más fácilmente en sistemas externos como Akamai que proporcionan gran escalabilidad.

2.Gestione eficiente la información en Cookies en el navegador

Las cookies permiten almacenar de manera local la información personalizable de casa usuario de tal manera que el resto de contenidos de la página pueden ser objeto de cacheo.

Por ejemplo, si queremos mostrar un mensaje de bienvenida personalizado podríamos almacenar este mensaje un una cookie local de tal manera que el resto del contenido pudiera cachearse.

3. Muestre el perfil del usuario en la URL

Podemos recurrir a técnicas de URL rewriting para mostrar en la url elementos que indiquen el país o el tipo de usuario. Por ejemplo:

http://www.hellogoogle.com/es/home-user/welcome/

Luego por técnicas de url rewriting podrían convertirse en una url dinámica del tipo:

http://www.hellogoogle.com/welcome/?country=es&usertype=home-user

Como ya vimos este tipo de friendly urls pueden ser cacheadas por los navegadores de los usuarios.

4. Gestione de manera independiente la información personalizada

Técnicas como AJAX o Adobe Flex nos permiten mostrar al usuario información personalizada mediante peticiones GET o POST una vez cargada la página. Esto nos abre la posibilidad de cachear el documento html sin que ello interfiera con la información que se muestra de manera personalizada a cada usuario.

5. Utilice la cabecera ETAG para gestionar el cacheo de contenidos dinámicos

Como ya vimos anteriormente ETAG (Entity Tag) es un sistema que permite identificar a un contenido de manera unívoca, Los servidores Web pueden realizar validaciones de contenido basándose en esta información al igual que hacen con la información Last-Modified.

Obtener un ETAG a partir del contenido dinámico es sencillo y pemite minimizar el tiempo de respuesta en las revalidaciones de estos contenidos.

Dentro del ciclo de vida de la petición dentro del servidor, tras la generación del contenido, la aplicación puede obtener una hash MD5. La MD5 sería el ETAG que representa a esa petición. Si es igual a la ETAG enviada por el navegador, se indica al usuario final que el contenido no ha cambiado para que la cargue de su cache local (HTTP/1.x 304)::

var contenido = response.buffer

var path = request.header("PATH")

var ETAG = funcion-MD5 (path, contenido) //Obtenemos el ETAG de la petición

var request-ETAG = request.header("if-none-match") //Obtenemos el ETAG del navegador

Si ETAG = request-ETAG Entonces //Comparamos ambos ETAG

response.status = 304 //Si son iguales el contenido no ha variado.

response.buffer = ''

return

Si No

response.addheader("ETAG", ETAG)

Fin Si

Utilizar ETAG junto con las directrices de Cache Cache-Control o Expires, permite ahorrar peticiones innecesarias y ancho de banda de nuestro servidor.

La cache universal: la solución a todos nuestros males

Como hemos podido ver en este artículo de hellogoogle.com la gestión eficiente de la cache es fundamental en el desarrollo y mantenimiento de un Site. Si puliéramos trabajar con una cache nuestra vida sería mucho más sencilla: Por ejemplo, no  haría falta pedir cita con el  médico, éste quedaría cacheado tras la primera visita del día y cada ciudadano tendríamos un médico en cache a nuestra disposición las 24h del día. Tampoco tendríamos que hacer cola en el autobús o en el cine: una vez que hubiera accedido el primer usuario el resto tendría un autobús y un cine cacheado al instante.

Me temo que aún queda mucho tiempo para que la ciencia ponga a nuestra disposición un mundo cacheado en el que todos los seres humanos podamos vivir en paz sin necesidad de competir por un puesto de trabajo, una mujer o un trozo de pastel de chocolate. Mientras tanto seguiremos enfrentándonos a la cruda realidad de un mundo con recursos limitados, guerras, muerte y enfermedad.

¿Quien sabe?, después de todo quiza no sea tan malo tener que esperar un ratito en la cola del dentista, yo al menos, no tengo ninguna prisa.

28 comentarios en “Tutorial Cache Web: cómo gestionar el cacheo de nuestros contenidos”

  1. Iñaki, en la linea que pone: “Como ve no existe una única forma que indicar que una página no sea cacehada” es cacheada.
    Agur

  2. Leyendo el articulo que me indicas, te digo que sí tengo el Mod_rewrite activo en el dominio, que está alojado en 1and1.es, en un Pack Inicial con 250 MB de espacio y 1 BD MySQL. Pero como es un host un tanto especial, lo de hacer el dominio canonico funciona, funcionan los 301 de varias url antiguas hacia las nuevas pero no sé si tiene todas las opciones activas de dicho modulo, por lo que quizás vaya por ahi el tema.

  3. Creo que el error debe estar en la expresión regular con la que estás realizando la redirección. En el artículo que te he comentado tienes varios ejemplos que te pueden ser de ayuda.

  4. Mira, aqui te pongo todo el htaccess:

    ….

    Como veras estan comentadas las lineas que no funcionan.
    Los correspondientes scripts php estan subidos al servidor y estan tal cual se mostraban en el articulo de http://lpdp.familyguest.com/php/optimizar-velocidad-respuesta-blog-gzip-php-htaccess/
    No sé si el problema esta en el orden de las instrucciones o en su interacccion con las lineas que gobiernan el cacheo. Tampoco sé si se le puede añadir de alguna forma las instrucciones que dabas en estas que yo tengo aqui, las del FilesMatch. Esa es mi pregunta.

  5. Hola Aguado.

    He echado un ojo al artículo que comentas. Mi recomendación es que consultes con tu hosting si tiene instalado los módulos mod_gzip y mod_deflate, que son necesarios para realizar la compresión y descompresión automática de la páginas. Utilizar la función ob_gzhandler te obliga a controlar la compresión por scripting y a tocar todas las páginas de tu Site.

    Un saludo.

  6. Hola Ignacio, soy Héctor te saludo desde Colombia.

    Te cuento que estuve leyendo tu sitio en el contenido de Cache http://www.hellogoogle.com/tutorial-cache-web/ el cual me ha servido de mucho para entender esta forma de hacer la web y me pareció muy interesante, pero déjame decirte que quede con muchas dudas técnicas, más no de concepto y acudo a ti porque veo que tienes el conocimiento y de pronto puedes ayudarme.

    Tengo este sitio web http://www.viajesdestinoantioquia.com, es un sitio de turismo y recibimos muchas visitas, alrededor de unas 2000 diarias y casi las 10.000 diarias cuando esta la Semana de la Feria de las Flores en Mi ciudad y el servidor de Hosting me dijo que está consumiendo muchos recursos del servidor y mucho ancho de banda y tenía que ver cómo arreglar para que se cacheara la pagina. Busque y busque y llegue a tu sitio y vi la información, pero por falta de conocimiento en ese tema y apuros por no dejar fuera del aire el sitio web ya que estábamos en la feria que te comento, decidí pasar la página a un servidor dedicado, pero quiero solucionar el problema para que quede bien de una vez y no consumir tantos recursos.

    El sitio esta hecho en PHP con Bd MYsql y lo que pido me ayudes es a entender que código debo ponerle en php a las paginas para que queden guardadas en la cache del ISP y se solucione el problema.

    Si puedes ayudarme estare muy agradecido contigo, si tiene algún costo por tu servicio, házmelo saber y cuadramos Pero realmente necesito tu ayuda.

    Héctor Álvarez C

  7. Hola Hector.

    Disculpa no te haya respondido antes.

    Mira, puedes seguir muchas estrategias de cacheo de información. Tu ISP posiblemente cache tus páginas dinámicas de manera automática, a no ser que trabajes con URL con querystrings, o indiques de manera explícita en el código fuente que no deben ser cacheadas.

    Mi primera recomendación por tanto es que analices si tu ISP está pudiendo cachear tus contenidos.

    Por otro lado, puedes crear tu mismo una cache en tu servidor apache para aligerar la cargar. Para ello puedes seguir estos pasos:

    1.
    En el raiz de nuestra web crearemos los siguientes archivos: .htaccess, start_cache.php, end_cache.php, y create una carpeta llamada “cache_files”.

    2.
    Cambiar los permisos a la carpeta “cache_files” a 777.

    3.
    Dentro de nuestro archivo .htaccess, insertaremos estas dos líneas de código:

    php_value auto_prepend_file /home/pepito/public_html/start_cache.php
    php_value auto_append_file /home/pepito/public_html/end_cache.php

    Deberás cambiar “/home/pepito/public_html/” por la ruta física donde esta albergado tu sitio.

    4.
    Introduciremos el siguiente código en el archivo “start_cache.php”. De nuevo cambiaremos “/home/pepito/public_html/” por la ruta física de tu sitio.

    <?
    //Algunos parametros de configuracion
    $settings_cachedir = ‘/home/pepito/public_html/cache_files/’;
    $settings_cachetime = 3600; //keep cache files for 3600 seconds (1 hour)
    //Pagina php
    $thispage = ‘http://’ . $_SERVER[‘HTTP_HOST’] . $_SERVER[‘REQUEST_URI’];
    $cachelink = $settings_cachedir.md5($thispage).”.html”;
    if (@file_exists($cachelink)) {
    $cachelink_time = @filemtime($cachelink);
    if ((time() – $settings_cachetime)

    5.
    Por último introducir este código en el archivo“end_cache.php”.

    Todas tus páginas incluidas las estáticas HTML seran cacheadas durante 1 hora, transcurrido este tiempo se volverán a generar. Las páginas cacheadas serán guardadas en la carpeta “cache_files” si tienes algún problema deja un comentario que alguien te echará una mano.

    Un saludo y suerte.

  8. Excelente guía, espero poder experimentar con esto proximamente. Soy estudiante de Ingeniería en Computación y me tocó investigar para una exposición al respecto, y la verdad de, a pesar de que esta tecnología no es precisamente nueva, es al parecer uno de esos temas esotéricos relacionados con la computación de los cuales nadie parece saber mucho.

    De cualquier manera, felicitaciones por tu trabajo.

  9. q pasa si elimino cookis, cache y el historial despues de navevar por internet y como puedo sabber q paginas se visitaron despues de haber eliminado

  10. creo q es el cache….tengo un problema, puse borrar el historial en el mozilla y en las opciones estaba el cahce seleccionado y no me di cuenta…a partir de ahi no puedo entrar en la web de google… en todas las otras paginas si pero en esa no!!! alguien me puede ayudar?

  11. Muy interesante el tutorial, mas bien una pregunta: ¿Cual seria tu estrategia para aplicar cache a un sitio con carga de miles de usuarios al dia, miles de busquedas por hora, con cientos de miles de registros en una base de datos? Saludos

  12. Ignacio, me parece interesante el tutorial con el archivo htaccess y los dos de php. ¿Se puede implementar en cualquier tipo de sitio o solo para sitios dinámicos?

  13. este programa m parece fantastico pero lo que quisiera saber es si ya han fabricado micro mas abansado que 32 a 64 kb

  14. Hola:

    Esta muy interesante el articulo pero, caundo pongo por ejemplo este codigo en google pagespeed:

    Header set Cache-Control “max-age=4838400, private”
    Header set Expires “Wed, 19 Dic 2012 20:00:00 GMT”

    Header set Cache-Control “max-age=2419200, private, must-revalidate”

    Header set Cache-Control “max-age=7200, private, must-revalidate”

    Me pide especificar Especificar un validador de caché Last-Modified or ETag header

    Eso como lo agrego?

    Gracias por la ayuda

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *