El caching efectivo es la piedra angular de un sistema CDN optimizado. Sin embargo, encontrar el equilibrio perfecto entre rendimiento y frescura de contenido representa uno de los mayores desafíos para arquitectos y desarrolladores. Este artículo explora las estrategias avanzadas de caché e invalidación que utilizamos en Yhhhdttt para maximizar el rendimiento de servicios en la nube sin comprometer la actualidad de los datos.
Fundamentos de las políticas de caché
Antes de sumergirnos en estrategias avanzadas, es fundamental comprender los mecanismos básicos que controlan el comportamiento del caché en una infraestructura CDN y cloud:
Cabeceras HTTP de control de caché
Las cabeceras HTTP son el método principal para comunicar políticas de caché entre servidores y clientes:
- Cache-Control: Es la cabecera más versátil y potente. Algunos de sus valores más útiles son:
max-age=<seconds>: Tiempo máximo que un recurso puede permanecer en caché antes de revalidarses-maxage=<seconds>: Similar a max-age pero específico para cachés compartidos (como CDNs)public: Indica que el recurso puede ser cacheado por cualquier cachéprivate: Restringe el caching a navegadores (evitando almacenamiento en CDNs)no-cache: Requiere revalidación antes de usar la versión cacheadano-store: Prohibe cualquier tipo de cachingstale-while-revalidate=<seconds>: Permite usar contenido obsoleto mientras se revalida en segundo plano
- Expires: Cabecera más antigua que especifica una fecha y hora exacta de expiración. Menos flexible que Cache-Control.
- ETag: "Entity Tag" único que cambia cuando el contenido cambia, permitiendo revalidación eficiente.
- Last-Modified: Timestamp de la última modificación del recurso, útil para revalidación basada en tiempo.
- Vary: Especifica qué cabeceras de petición influyen en la respuesta, permitiendo cachear múltiples variantes.
Cabeceras de control específicas para CDN
Además de las estándar, existen cabeceras específicas que ofrecen mayor control sobre el comportamiento del CDN:
- CDN-Cache-Control: Similar a Cache-Control pero con precedencia específica para CDNs.
- Surrogate-Control: Cabecera definida por Edge Architecture que permite controlar el caching en el edge sin afectar a los clientes.
- Edge-Control: Similar a Surrogate-Control, utilizada en algunos CDNs específicos.
Estrategias de caché por tipo de contenido
No todos los recursos deben tratarse igual. Estas son las estrategias óptimas según el tipo de contenido:
1. Contenido estático inmutable
Para recursos que nunca cambian (imágenes con nombre de archivo versionado, CSS/JS con hash en el nombre, etc.):
Cache-Control: public, max-age=31536000, immutable
Esta configuración permite el almacenamiento en caché durante un año y comunica que el recurso nunca cambiará, evitando incluso la revalidación condicional.
2. Contenido estático que puede actualizarse
Para recursos como logos, imágenes sin versión en el nombre, o archivos de configuración:
Cache-Control: public, max-age=86400, stale-while-revalidate=43200
Esto permite el caching durante 24 horas, pero si el contenido tiene más de un día pero menos de 12 horas adicionales, se servirá la versión "obsoleta" mientras se actualiza en segundo plano.
3. Páginas HTML y respuestas de API dinámicas pero cacheables
Cache-Control: public, max-age=300, s-maxage=3600, stale-if-error=86400
Esta configuración cachea la página durante 5 minutos en el navegador y 1 hora en el CDN. Además, si el origen experimenta errores, se puede seguir sirviendo la versión cacheada hasta por 24 horas.
4. Contenido personalizado pero parcialmente cacheable
Para páginas que contienen elementos comunes y personalizados:
Cache-Control: private, max-age=0, must-revalidate
Vary: Cookie, Accept-Language
La cabecera Vary indica que diferentes versiones deben cachearse según el idioma y las cookies del usuario. Para este escenario, técnicas como Edge Side Includes (ESI) son especialmente útiles, permitiendo cachear fragmentos de la página de forma independiente.
5. Contenido dinámico de tiempo real
Cache-Control: no-store, no-cache, must-revalidate
Pragma: no-cache
Esta configuración evita cualquier tipo de caching para datos que deben ser siempre actualizados (como información de cuenta o datos de transacciones).
Invalidación de caché: estrategias y patrones
Incluso con TTLs (Time To Live) bien definidos, es esencial contar con mecanismos para invalidar explícitamente el contenido cacheado cuando hay actualizaciones:
1. Purga por URL
El método más directo es enviar una petición de purga para URLs específicas cuando su contenido cambia. Por ejemplo, utilizando una API REST:
POST /purge HTTP/1.1
Host: api.cdn.ejemplo.com
Content-Type: application/json
Authorization: Bearer {token}
{
"urls": [
"https://ejemplo.com/articulo/123",
"https://ejemplo.com/listado/categoria"
]
}
Esta técnica es ideal para actualizaciones puntuales pero puede ser ineficiente para grandes volúmenes de contenido relacionado.
2. Invalidación por tag o clave de caché
Una técnica más avanzada consiste en asignar etiquetas o claves a grupos de contenido relacionado:
Cache-Control: public, max-age=3600
Surrogate-Key: articulo-123 categoria-viajes autor-5
Posteriormente, se puede invalidar todo el contenido asociado a una etiqueta específica:
POST /purge HTTP/1.1
Host: api.cdn.ejemplo.com
Content-Type: application/json
Authorization: Bearer {token}
{
"surrogate-keys": ["autor-5"]
}
Esta operación invalida instantáneamente todos los recursos (artículos, imágenes, etc.) asociados con ese autor, sin necesidad de conocer cada URL individual.
3. Invalidación por comodín o expresión regular
Para casos donde el contenido sigue patrones predecibles:
POST /purge HTTP/1.1
Host: api.cdn.ejemplo.com
Content-Type: application/json
Authorization: Bearer {token}
{
"patterns": [
"https://ejemplo.com/productos/*",
"https://ejemplo.com/api/v1/precios/*"
]
}
Esta técnica es especialmente útil para secciones completas o APIs.
4. Invalidación proactiva mediante webhooks
En lugar de esperar a que un administrador o proceso programado invalide el caché, se pueden configurar webhooks que automáticamente desencadenen invalidaciones cuando ocurren eventos específicos en el backend:
- Un CMS como WordPress o Drupal envía un webhook cuando se actualiza un artículo
- El webhook contiene información sobre el contenido modificado (IDs, categorías, etc.)
- Un microservicio recibe el webhook y traduce esa información en peticiones de purga específicas
- El CDN procesa las peticiones de purga y actualiza su caché
Este enfoque minimiza el tiempo entre una actualización y su propagación a todos los usuarios.
5. Soft Purge
A diferencia de la purga convencional que elimina completamente el objeto del caché, el "soft purge" marca el contenido como caducado pero lo mantiene disponible para su uso mientras se obtiene la versión actualizada del origen:
POST /purge HTTP/1.1
Host: api.cdn.ejemplo.com
Content-Type: application/json
Authorization: Bearer {token}
{
"urls": ["https://ejemplo.com/pagina-popular"],
"soft": true
}
Esta técnica es ideal para contenido de alto tráfico, ya que evita el "dogpile effect" (sobrecarga del origen cuando caducan múltiples cachés simultáneamente).
Patrones avanzados de caching
Más allá de las estrategias básicas, estos patrones avanzados pueden optimizar significativamente el rendimiento:
1. Cache Warming
En lugar de esperar a que los usuarios soliciten contenido para poblarlo en caché (causando "cache misses" iniciales), el cache warming precarga proactivamente el contenido más importante:
- Warming programado: Scripts que periódicamente solicitan las URLs más importantes
- Warming predictivo: Análisis de patrones de tráfico para anticipar qué contenido será solicitado
- Warming post-deploy: Tras una actualización, precalentar automáticamente las páginas afectadas
2. Stale-While-Revalidate y Stale-If-Error
Estos patrones mejoran significativamente la resiliencia y experiencia de usuario:
- stale-while-revalidate: Permite servir contenido técnicamente caducado mientras se actualiza en segundo plano, eliminando la latencia percibida
- stale-if-error: Utiliza contenido caducado cuando el origen experimenta errores, mejorando la disponibilidad
Cache-Control: max-age=600, stale-while-revalidate=1200, stale-if-error=86400
3. Edge Side Includes (ESI)
ESI permite componer páginas dinámicamente en el edge, combinando fragmentos con diferentes políticas de caché:
<!-- Fragmento principal cacheado por 1 hora -->
<html>
<head>...</head>
<body>
<header>...</header>
<!-- Contenido principal cacheado por 1 hora -->
<main>...</main>
<!-- Widget personalizado no cacheado -->
<esi:include src="/widgets/recommendations?user_id=123" />
<!-- Fragmento cacheado por 5 minutos -->
<esi:include src="/fragments/trending-now" />
<footer>...</footer>
</body>
</html>
Esta técnica permite máxima cacheabilidad incluso en páginas con elementos personalizados o de alta frecuencia de actualización.
4. Cache Key Customization
Personalizar la clave de caché permite un control granular sobre qué factores determinan una "cache hit":
- Incluir o excluir ciertos query parameters (
?sort=priceafecta al contenido pero?utm_source=newsletterno) - Considerar cabeceras específicas como parte de la clave (User-Agent simplificado, Accept-Language)
- Normalizar cookies relevantes mientras se ignoran las no esenciales para el contenido
Este enfoque maximiza la tasa de aciertos de caché mientras mantiene la relevancia del contenido.
Recomendaciones TTL por tipo de recurso
Basándonos en nuestra experiencia optimizando miles de sitios, estas son nuestras recomendaciones de TTL (Time To Live) por tipo de contenido:
Contenido estático
- Imágenes: 30 días a 1 año (dependiendo de la frecuencia de actualización)
- CSS/JavaScript versionados: 1 año con
immutable - CSS/JavaScript sin versión: 1-7 días con
stale-while-revalidate - Webfonts: 1 año
- Archivos descargables (PDF, ZIP): 1-7 días
- Favicon, robots.txt: 1 día
Contenido dinámico
- Páginas de producto: 1-4 horas en CDN, 5 minutos en navegador
- Páginas de categoría: 30 minutos a 2 horas
- Homepage: 15 minutos a 1 hora
- Blog/artículos: 1-12 horas
- API de información pública: 5-30 minutos (dependiendo de la frecuencia de actualización)
- API de precios/stock: 30 segundos a 5 minutos
- Respuestas de búsqueda: 5-15 minutos con
Vary: X-Search-Query
Contenido personalizado
- Recomendaciones personalizadas: No cachear o cachear con
Vary: Cookiepor 5 minutos - Páginas de perfil de usuario:
private, max-age=60(caché solo en navegador) - Carritos de compra:
no-store(sin caché) - Información de cuenta:
no-store(sin caché)
Implementación y monitorización
La implementación de estas estrategias debe acompañarse de un sistema robusto de monitorización para verificar su efectividad:
Métricas clave a monitorizar
- Cache Hit Ratio: Porcentaje de peticiones servidas desde caché (objetivo: >85%)
- Origin Traffic: Volumen de tráfico que alcanza el origen
- Cache Efficiency: Ratio entre bytes transferidos desde origen vs. desde caché
- Age Distribution: Distribución de la "edad" del contenido servido desde caché
- Purge Success Rate: Porcentaje de operaciones de purga completadas correctamente
- Stale Ratio: Porcentaje de respuestas servidas en estado "stale" mientras se revalidan
Auditoría periódica de headers
Es crucial auditar regularmente las cabeceras HTTP para detectar:
- Recursos incorrectamente marcados como no cacheables
- TTLs excesivamente cortos o largos
- Duplicación de contenido por claves de caché incorrectas
- Oportunidades de optimización mediante stale-while-revalidate
Conclusiones
Una estrategia de caché bien implementada debe equilibrar tres factores fundamentales:
- Rendimiento: Maximizar la tasa de aciertos de caché para reducir latencia y carga del origen
- Frescura: Asegurar que los usuarios reciben contenido actualizado en tiempos razonables
- Resiliencia: Mantener el servicio disponible y rápido incluso cuando hay problemas con el origen
Las técnicas presentadas en este artículo permiten lograr este equilibrio, pero cada implementación debe adaptarse a los requisitos específicos del servicio. No existe una configuración universal óptima; el arte del caching consiste en personalizar estas estrategias para cada tipo de contenido y caso de uso.
En Yhhhdttt, aplicamos estas técnicas de forma personalizada para cada cliente, analizando sus patrones de tráfico, arquitectura de aplicación y requisitos de negocio para diseñar una estrategia de caché que maximice el rendimiento sin comprometer la frescura del contenido.