Referencia Detallada de Estrategia de Caching CDN
Disenar caching CDN para aplicaciones web y APIs. Cubre edge caching, cache keys, cache headers, estrategias de invalidacion, surrogate keys y setups multi-CDN para rendimiento global.
Nota para desarrolladores hispanohablantes: Esta guía incluye ejemplos y convenciones de nomenclatura adaptadas a equipos que trabajan en español. Cuando existen diferencias significativas en terminología técnica entre el inglés y el español, se indican explícitamente para facilitar la comunicación en equipos multiculturales.
Introducción
Un Content Delivery Network (CDN) cachea tu contenido en edge locations cercanas a los usuarios. Cuando un usuario en Tokyo solicita una pagina servida desde un data center en Virginia, el CDN la sirve desde un edge node en Tokyo. Esto reduce la latencia de 200ms a 20ms. Pero el caching CDN solo funciona si lo configuras correctamente. Un mal diseno de cache keys, headers faltantes, o invalidacion agresiva pueden hacer el CDN inutil. A continuacion se cubre todo lo que necesitas para disenar una estrategia de caching CDN que funcione.
Cómo Funciona el Caching CDN
Usuario (Tokyo) → CDN Edge (Tokyo) → Origin (Virginia)
↓
Cache HIT → Retorna respuesta cacheada (20ms)
Cache MISS → Fetchea de origin, cachea, retorna (200ms)
- El usuario solicita una URL (ej.,
https://example.com/image.jpg) - El CDN checkea si la respuesta esta cacheada en el edge node mas cercano
- Si esta cacheada (HIT): retorna la respuesta cacheada inmediatamente
- Si no esta cacheada (MISS): fetchea de origin, almacena en edge, retorna al usuario
- Requests subsiguientes para la misma URL se sirven desde cache hasta que el TTL expira
Cache Headers
Los CDNs usan HTTP cache headers para determinar que cachear y por cuanto tiempo.
Cache-Control
El header Cache-Control es la directiva principal para caching CDN.
Cache-Control: public, max-age=3600
public: Cualquier cache (CDN, browser) puede almacenar la respuestaprivate: Solo el browser puede almacenar la respuesta (no el CDN)max-age=N: Cachear por N segundoss-maxage=N: Cachear por N segundos en shared caches (CDN) solono-cache: Debe revalidar con origin antes de usar la copia cacheadano-store: No cachear en absolutomust-revalidate: No servir respuesta stale despues de expirarstale-while-revalidate=N: Servir stale mientras revalida en background
Setear Headers por Tipo de Contenido
# configuracion nginx
# Assets estaticos: cache largo, immutable
location ~* \.(css|js|png|jpg|jpeg|gif|svg|woff2?)$ {
add_header Cache-Control "public, max-age=31536000, immutable";
}
# Paginas HTML: cache corto, must revalidate
location ~* \.html$ {
add_header Cache-Control "public, max-age=60, must-revalidate";
}
# Respuestas API: no cachear por defecto
location /api/ {
add_header Cache-Control "no-store";
}
# Respuestas API publicas: cache corto
location /api/public/ {
add_header Cache-Control "public, max-age=60";
}
ETag y Last-Modified
ETag y Last-Modified habilitan conditional requests. Cuando la copia cacheada del CDN expira, envia una conditional request al origin con If-None-Match o If-Modified-Since. Si el contenido no ha cambiado, el origin retorna 304 Not Modified (sin body), y el CDN refresca el TTL de la copia cacheada.
# Primera request
HTTP/1.1 200 OK
ETag: "abc123"
Last-Modified: Wed, 04 Jul 2026 12:00:00 GMT
Cache-Control: public, max-age=3600
Content: <html>...</html>
# Request subsiguiente (despues de que TTL expira)
GET /page
If-None-Match: "abc123"
If-Modified-Since: Wed, 04 Jul 2026 12:00:00 GMT
# Respuesta del origin
HTTP/1.1 304 Not Modified
Cache-Control: public, max-age=3600
# Sin body — el CDN mantiene la copia cacheada
Cache Keys
La cache key determina si dos requests hittean la misma respuesta cacheada. Por defecto, la cache key es la URL completa incluyendo query string. Pero puedes customizarla.
Cache Key por Defecto
Cache key: https://example.com/page?utm_source=email&utm_campaign=summer
Dos requests con diferentes valores de utm_source producen diferentes cache keys, aunque el contenido sea identico. Esto desperdicia espacio de cache.
Normalizar Cache Keys
Remueve parametros de tracking que no afectan el contenido:
// Cloudflare Worker: normalizar cache key
addEventListener("fetch", (event) => {
const url = new URL(event.request.url);
// Remover parametros de tracking
const trackingParams = ["utm_source", "utm_medium", "utm_campaign", "utm_term", "utm_content", "fbclid", "gclid"];
for (const param of trackingParams) {
url.searchParams.delete(param);
}
// Usar URL normalizada como cache key
event.respondWith(fetch(url.toString()));
});
Vary Header
El header Vary le dice al CDN que incluya headers de request adicionales en la cache key. Esto es necesario cuando la respuesta difiere basandose en headers de request.
Vary: Accept-Encoding, Accept-Language
Esto crea entradas de cache separadas para diferentes encodings (gzip, br) e idiomas (en, es). Sin Vary, un usuario pidiendo Espanol podria obtener la respuesta cacheada en Ingles.
Composición de Cache Key
Cache key completa = URL + Vary headers + Custom keys
Disena tu cache key para incluir todo lo que afecta la respuesta y nada que no afecte.
Estrategias de Invalidación
Expiración Basada en TTL
Setea un TTL en contenido cacheado. Despues de que el TTL expira, el CDN revalida con el origin. Simple pero sirve contenido stale por la duracion del TTL.
Cache-Control: public, max-age=300
Purge por URL
Remueve explicitamente una URL del cache del CDN. Usa esto cuando el contenido cambia antes de que el TTL expire.
# Cloudflare purge por URL
curl -X POST "https://api.cloudflare.com/client/v4/zones/{zone_id}/purge_cache" \
-H "Authorization: Bearer {api_token}" \
-H "Content-Type: application/json" \
-d '{"files": ["https://example.com/page1", "https://example.com/page2"]}'
# Fastly purge por URL
curl -X POST "https://api.fastly.com/purge/{service_id}" \
-H "Fastly-Key: {api_key}" \
-d "https://example.com/page1"
Purge por Surrogate Key
Etiqueta respuestas cacheadas con surrogate keys. Purga por key para remover todas las respuestas etiquetadas en una llamada. Esto es mas eficiente que purgar URLs individuales.
# Headers de respuesta
Surrogate-Key: product-42 products category-5
Cache-Control: public, max-age=3600
# Fastly purge por surrogate key
curl -X POST "https://api.fastly.com/purge/{service_id}" \
-H "Fastly-Key: {api_key}" \
-H "Surrogate-Key: product-42"
Esto purga todas las respuestas etiquetadas con product-42 across todo el CDN.
Purge All
Purga todo del CDN. Usa con moderacion: causa un spike en trafico de origin ya que todas las requests se vuelven cache misses.
# Cloudflare purge everything
curl -X POST "https://api.cloudflare.com/client/v4/zones/{zone_id}/purge_cache" \
-H "Authorization: Bearer {api_token}" \
-H "Content-Type: application/json" \
-d '{"purge_everything": true}'
Invalidación Event-Driven
Triggera purge del CDN cuando los datos cambian en tu backend.
import requests
def update_product(product_id: int, data: dict):
product = db.products.update(product_id, data)
# Purgar cache CDN para este producto
requests.post(
"https://api.fastly.com/purge/{service_id}",
headers={"Fastly-Key": API_KEY},
data={"surrogate_keys": [f"product-{product_id}", "products"]}
)
return product
Estrategias de Contenido Stale
stale-while-revalidate
Sirve contenido stale mientras fetchea una copia fresca en background. Los usuarios obtienen respuestas instantaneas; el cache se actualiza asincronamente.
Cache-Control: public, max-age=300, stale-while-revalidate=60
Por 300 segundos, sirve desde cache. De 300-360 segundos, sirve stale mientras revalida. Despues de 360 segundos, fetchea de origin sincronamente.
stale-if-error
Sirve contenido stale si el origin no esta disponible. Esto proporciona resiliencia durante outages del origin.
Cache-Control: public, max-age=300, stale-if-error=86400
Si el origin retorna un error (5xx) despues de que el cache expira, sirve el contenido stale cacheado por hasta 86400 segundos (1 dia).
Caching por Tipo de Contenido
Assets Estaticos (CSS, JS, Imagenes)
Cachear por mucho tiempo con filenames basados en contenido. Usa fingerprinting (hash en filename) para que nuevas versiones obtengan nuevas URLs.
Cache-Control: public, max-age=31536000, immutable
<!-- URLs versionadas -->
<link rel="stylesheet" href="/css/main.a1b2c3d4.css">
<script src="/js/app.e5f6g7h8.js"></script>
Paginas HTML
Cachear por poco tiempo con revalidacion. El contenido cambia frecuentemente pero deberia estar fresco.
Cache-Control: public, max-age=60, must-revalidate
ETag: "abc123"
Respuestas API
Cachear respuestas API publicas con TTLs cortos. No cachear respuestas autenticadas o especificas de usuario.
# Lista de productos publica
Cache-Control: public, max-age=60
# Datos especificos de usuario
Cache-Control: private, no-cache
# Datos en tiempo real
Cache-Control: no-store
Autenticación y Caching CDN
Las respuestas autenticadas no deben ser cacheadas por el CDN. Usa private o no-store para cualquier respuesta que incluye datos especificos de usuario.
# Perfil de usuario (private)
Cache-Control: private, no-cache
Set-Cookie: session=abc123; HttpOnly; Secure
# Producto publico (cacheable)
Cache-Control: public, max-age=3600
Estrategia Multi-CDN
Para aplicaciones globales, usa multiples CDNs para optimizar costo, rendimiento, y disponibilidad.
Selección de CDN por Geografía
Rutea usuarios al CDN con el mejor rendimiento en su region.
// Ruteo CDN basado en DNS (usando un DNS provider como NS1 o Route 53)
const cdnRoutes = {
"asia": "cdn-asia.example.com", // Cloudflare (fuerte en Asia)
"europe": "cdn-europe.example.com", // Fastly (fuerte en Europa)
"default": "cdn-global.example.com", // Cloudfront (global)
};
Selección de CDN por Tipo de Contenido
Rutea assets estaticos a un CDN y contenido dinamico a otro.
Assets estaticos (CSS, JS, imagenes) → CDN A (mas barato, TTL mas largo)
Contenido dinamico (API, HTML) → CDN B (origin mas rapido, TTL mas corto)
Failover
Si un CDN se cae, rutea el trafico al CDN de backup.
# Script de health check
if ! curl -s --max-time 5 https://cdn-a.example.com/health; then
# Actualizar DNS para rutar a CDN B
aws route53 change-resource-record-sets \
--hosted-zone-id Z123 \
--change-batch '{"Changes":[{"Action":"UPSERT","ResourceRecordSet":{"Name":"cdn.example.com","Type":"CNAME","TTL":60,"ResourceRecords":[{"Value":"cdn-b.example.com"}]}}]}'
fi
Monitoreo de Rendimiento CDN
Métricas Clave
- Cache hit ratio:
hits / (hits + misses)— deberia estar sobre 90% para contenido estatico - Origin shield ratio: porcentaje de requests servidas desde origin shield sin hittear origin
- Edge response time: p50, p95, p99 para respuestas servidas desde edge
- Origin response time: p50, p95, p99 para fetches de origin
- Purge latency: tiempo desde purge request hasta invalidacion de cache
- Bandwidth: ancho de banda servido por CDN vs servido por origin
Cálculo de Cache Hit Ratio
Cache Hit Ratio = Cache Hits / (Cache Hits + Cache Misses) * 100
Un 95% de hit ratio significa que 95 de cada 100 requests se sirven desde cache. Las 5 restantes van al origin. Trackea esto por tipo de contenido:
| Tipo de Contenido | Hit Ratio Objetivo | TTL Tipico |
|---|---|---|
| Assets estaticos | 99%+ | 1 ano |
| Paginas HTML | 80-90% | 1-5 minutos |
| API publica | 60-80% | 30-60 segundos |
| API privada | 0% (sin cache) | N/A |
Checklist de Producción
- Headers Cache-Control seteados para todos los tipos de contenido
- Headers ETag o Last-Modified para conditional requests
- Cache keys normalizadas (parametros de tracking removidos)
- Header Vary seteado para content negotiation (encoding, idioma)
- Surrogate keys para purging dirigido
- Purge event-driven en cambios de datos
- stale-while-revalidate para staleness graceful
- stale-if-error para resiliencia de outage de origin
- Assets estaticos usan filenames fingerprinted
- Respuestas autenticadas marcadas private o no-store
- Cache hit ratio monitoreado por tipo de contenido
- Purge latency monitoreado
- Origin shield configurado para reducir carga de origin
- Plan de failover para outage de CDN
Preguntas Frecuentes
¿Cuál es la diferencia entre browser cache y CDN cache?
Browser cache se almacena en el dispositivo del usuario. Reduce requests al CDN. CDN cache se almacena en edge servers. Reduce requests al origin. Ambas capas trabajan juntas: browser cache sirve visitas repetidas, CDN cache sirve primeras visitas de cualquier usuario en la misma region.
¿Debería cachear paginas HTML en el CDN?
Si, con un TTL corto (1-5 minutos). Las paginas HTML son costosas de generar server-side. Cachearlas por solo 1 minuto reduce la carga de origin considerablemente. Usa must-revalidate y ETags para que el CDN revalide eficientemente.
¿Cómo manejo contenido especifico de usuario con un CDN?
No caches contenido especifico de usuario en el CDN. Marcalo private o no-store. Para paginas con una mezcla de contenido publico y privado, usa Edge Side Includes (ESI) o client-side rendering para las partes personalizadas, y cachea las partes publicas en el CDN.
¿Qué es un origin shield?
Un origin shield es una capa de cache CDN entre los edge nodes y tu origin. Todos los edge nodes fetchean desde el shield, y el shield fetchea desde el origin. Esto reduce la carga de origin: si 100 edge nodes solicitan el mismo contenido, solo 1 request llega al origin (desde el shield).
¿Por cuánto tiempo debería cachear assets estaticos?
Cachea assets estaticos por 1 ano (max-age=31536000). Usa filenames fingerprinted (hash en filename) para que nuevas versiones obtengan nuevas URLs. Cuando deployas una nueva version, la URL cambia, y el CDN fetchea el archivo nuevo. Las URLs viejas permanecen cacheadas para usuarios que no han actualizado.
¿Cuál es el mejor CDN para mi caso de uso?
Depende de tus prioridades. Cloudflare tiene la red de edge mas amplia y un free tier generoso. Fastly ofrece purge instantaneo y surrogate keys. CloudFront se integra bien con AWS. Akamai es fuerte para enterprise y entrega a gran escala. Testea multiples CDNs con usuarios reales para encontrar el mejor fit.
See Also
Recursos Relacionados
Complete Guide to Redis Caching Strategies
Master Redis caching with cache-aside, read-through, write-through, write-behind, and refresh-ahead patterns. Covers eviction policies, TTL tuning, serialization, and production operations.
GuideComplete Guide to GraphQL Caching
Cache GraphQL responses at every layer: CDN, gateway, DataLoader, persisted queries, and client-side. Covers cache keys, invalidation, HTTP caching directives, and Apollo Client cache.
PatternCircuit Breaker Pattern
Prevent cascading failures by stopping requests to failing services. An architectural pattern for resilient distributed systems.
GuideComplete Guide to Cache Invalidation
Master cache invalidation strategies: TTL expiration, event-driven invalidation, versioned keys, tag-based purging, and write-through invalidation. Covers multi-tier invalidation, race conditions, and consistency patterns.
GuideComplete Guide to Application-Level Caching
Implement in-memory, distributed, and hybrid caches at the application layer. Covers LRU caches, TTL caches, multi-tier strategies, cache sizing, thread safety, and production patterns for Python, Java, and Node.js.