Estrategias de caché
1) Por qué cachear y dónde hacerlo
El caché es una capa de memoria rápida que reduce la latencia y la carga de recursos costosos (CPU/DB/API externas). Objetivos importantes:- Velocidad (p95/p99 más bajo), costo (menos egresos/CPU), estabilidad (menos dependencias bajo pico).
- Suavizar los picos y aislarse de los «vecinos ruidosos».
1. Cliente (navegador/móvil) - caché HTTP, IndexedDB, almacenamiento local.
2. Edge/CDN - Los nodos POP están más cerca del usuario, acumulan la estática y parte de la API.
3. Puerta de enlace L7/Reverse-proxy - Nginx/Envoy/Varnish (Microcash, SWR).
4. Caché de servicio - Redis/Memcached dentro del clúster.
5. Intraprocesamiento - in-memory (Caffeine/Guava/LRU-map).
6. Caché en DB - Representaciones materiales, índices secundarios.
Regla: cachear lo más cerca posible del consumidor, pero guardar la verdad una vez.
2) Patrones de caché
2. 1 Cache-aside (“lazy loading”)
La aplicación lee primero desde la caché; en caso de error - de la fuente, a continuación, escribe a la caché.
Pros: simplicidad, control. Contras: inicios fríos, ventanas de desacuerdo.
2. 2 Read-through
Leer siempre a través de la memoria caché que se dirige a la fuente en caso de error (biblioteca/capa de proxy).
Es conveniente centralizar las políticas de serilización/TTL.
2. 3 Write-through / Write-back (write-behind)
Write-through: escritura en caché y fuente sincronizada → consistencia más alta, latencia más alta.
Write-back: escritura en caché, escritura flash asíncrona en origen → rápido, pero los riesgos de pérdidas y conflictos.
2. 4 Refresh-ahead (proactive)
Predice que «la TTL caducará pronto» y actualiza la clave en el fondo, impidiendo el stampede.
2. 5 Negative caching
El caché «sin datos/404/vacío» en un TTL corto reduce la carga de la fuente.
2. 6 Micro-caching
TTL muy corto (0. 5-5 s) en L7 para la «casi dinámica» (listas, principal) - reduce drásticamente las colas.
3) caché HTTP: encabezados y controles
3. 1 Encabezados básicos
`Cache-Control`: `max-age`, `s-maxage` (для shared кэшей), `public/private`, `no-store`, `stale-while-revalidate`, `stale-if-error`.
Validadores: 'ETag' (hash de contenido), 'Last-Modified'.
Consultas con condiciones: 'If-None-Match', 'If-Modified-Since' → 304 Not Modified.
3. 2 Vary y llaves
'Vary: Accept-Encoding, Authorization, Cookie, Accept-Language' - forma diferentes opciones de caché. Minimiza 'Vary' para no «reventar» la cardinalidad.
3. 3 Ejemplo de respuesta HTTP
Cache-Control: public, max-age=60, s-maxage=300, stale-while-revalidate=60
ETag: "a1b2c3"
Vary: Accept-Encoding
4) Diseño de llaves y TTL
4. 1 Claves
Estructure: 'tenant: user: {id}: profile: v3' (incluya la versión del esquema).
Evite la PII en la clave.
Para colecciones, clave + opciones de consulta (normalizadas y ordenadas).
4. 2 TTL y coherencia
El TTL corto reduce la descoordinación, pero aumenta las faltas.
Para los datos críticos, los validadores ('ETag') y SWR (stale-while-revalidate).
Para los raramente cambiantes, el largo TTL + «bombas» de discapacidad.
4. 3 Versioning/basting
Si hay cambios incompatibles, cambie el prefijo/versión de la clave ('v2 → v3').
Para recursos estáticos, content hash en el nombre del archivo.
5) Discapacidad: estrategias y prácticas
5. 1 Eliminación directa
'DEL key '/' PURGE' en el proxy. Peligro: carreras entre la eliminación y los lectores múltiples.
5. 2 Etiquetas/Surrogate keys
Asocie el documento a un conjunto de etiquetas (categoría/autor). Discapacidad - por etiqueta.
В Varnish/Edge — `Surrogate-Key: article:42 tag:author:7` + `BAN tag:author:7`.
5. 3 Event-driven discapacidad
Pub/Sub (Kafka/NATS): si cambia la fuente, publicaremos el evento «invalidate».
Los consumidores de caché escuchan y eliminan/actualizan las claves.
5. 4 Bifásico
Primero marcamos la llave obsoleta (soft TTL), servimos stale, en el fondo actualizamos y reemplazamos atomicamente.
6) Lucha contra stampede/dogpile y llaves calientes
6. 1 Request coalescing (singleflight)
Un productor actualiza la clave, el resto está esperando el resultado (el mutex/sello «se actualiza»).
6. 2 Jitter к TTL
Agregue aleatoriedad (± 10-20%) a la TTL para evitar la perforación sincrónica.
6. 3 Soft-TTL + hard-TTL
Hasta soft-TTL servimos desde la memoria caché, paralelamente al disparador refresh; hard-TTL - Creemos que es un error.
6. 4 Llaves calientes
Cachés locales encima de los compartidos (dos-tier).
Replica la clave de acceso directo en varios shards y selecciona aleatoriamente (sólo read-only).
Rate limit para actualizar una clave específica.
6. 5 Ejemplo Redis + Lua (esbozo único)
lua
-- SETNX lock with TTL to avoid deadlocks local ok = redis. call("SET", KEYS[1], "1", "NX", "EX", ARGV[1])
if ok then return "LOCKED"
else return "WAIT"
end
7) Políticas de desplazamiento y recepción en caché
7. 1 Eviction
LRU: simple y bueno para la localización.
LFU: mejor con llaves calientes «de larga vida».
ARC/TinyLFU: balance recency/frequency.
7. 2 Admission (admisión)
No permita objetos raros gigantes (filtros TinyLFU/Bloom).
Compresión de valores grandes (LZ4/Zstd) en el límite «tamaño/latencia».
8) Charding y topologías
8. 1 Consistent hashing
Distribuye las claves de forma estable a través de los nodos, reduce los movimientos cuando el clúster crece/se comprime.
8. 2 Topologías Redis/Memcached
Redis Cluster (ranuras/bufandas), Sentinel (Feilover), replicación read-only.
Memcached es un cliente side sharding (ketama hashing), sin replicación a nivel de servidor.
8. 3 Local + distribuido
Cascada: in-proc (micro-TTL/LRU) → Redis (TTL más largo) → fuente.
Tenga cuidado con los TTL de dos puntos y los validadores de caché.
9) Edge, CDN y L7-caché
9. 1 Micro-cache на Nginx
nginx proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=api:100m inactive=10m;
map $request_method $skip_cache { default 0; POST 1; PUT 1; DELETE 1; }
server {
location /api/list {
if ($skip_cache) { add_header Cache-Control "no-store"; }
proxy_cache api;
proxy_cache_valid 200 2s; # micro-cache proxy_cache_use_stale error timeout updating;
proxy_cache_background_update on; # SWR add_header X-Cache $upstream_cache_status;
proxy_pass http://upstream;
}
}
9. 2 Envoy (SWR y condiciones)
yaml http_filters:
- name: envoy. filters. http. cache typed_config:
"@type": type. googleapis. com/envoy. extensions. filters. http. cache. v3. CacheConfig typed_config:
"@type": type. googleapis. com/envoy. extensions. http. cache. file_system_http_cache. v3. FileSystemHttpCacheConfig cache_path: "/var/cache/envoy"
9. 3 Varnish (Surrogate keys)
Utilice 'Surrogate-Key' y 'ban' por etiquetas para la discapacidad por lotes.
10) Caché y consistencia de datos
10. 1 Read-your-writes
Para perfiles/carritos personalizados, proporcione TTL cortos o escritura a través de la caché (write-through) o etiquetado de cliente (bypass en N segundos después de la grabación).
10. 2 Eventual vs Strong
Para recomendaciones/análisis - eventual + TTL largo.
Para el dinero/el estado de los pedidos - TTL corto, validación, a veces sin caché en las rutas críticas.
10. 3 Invariantes
No cachee campos que afecten a la seguridad/ACL sin TTLs estrictas y revalidación.
11) Observabilidad, SLO y gestión
11. 1 Métricas
hit_ratio (общий и per-route), byte_hit_ratio, miss_rate.
stampede_prevented_total, refresh_ahead_total, ban/purge_total.
Latencia: p50/p95/p99 de la memoria caché vs de la fuente.
hot_keys_topN y sus QPS/bytes.
11. 2 Registros y rastreos
Lógica 'X-Cache: HIT/MISS/STALE/UPDATING'.
En las pistas, marque el origen de la respuesta ('cache = true', 'tier = edge' service 'local').
11. 3 Enfoque SLO
Ejemplo: "para API/catalog p99 ≤ 250 ms, cache hit ≥ 85%, stampede ≤ 0. 1% de consultas".
11. 4 Runbooks
«Las faltas crecen» → comprobar TTL, calentamiento/discapacidad, hot-keys, tamaño de caché y política de aceptación.
12) Seguridad y multi-tenencia
Incrusta tenant-id en las claves (y en 'Vary' con HTTP).
No cachee las respuestas privadas como 'public'.
Cifre la caché con datos sensibles o almacene sólo los datos no PII/ID.
13) Recetas típicas
13. 1 Catálogo/cinta (casi altavoz)
Edge-microcash 1-3 con + SWR, en el interior - Redis a 15-60 s, invalidez por eventos de actualización.
13. 2 Perfil de usuario
Cache-aside con TTL 30-120 s, bypass 5-10 s después de actualizar el perfil (cookie/header), o write-through.
13. 3 Tipos de cambio/manuales
TTL largos (minutos-horas) + discapacidad objetivo cuando se publican nuevos datos; 'ETag' para GET condicionales.
13. 4 Emisión de búsqueda
Edge-microcash 1-2 s, dentro - refresh-ahead y coalescing, normalizando los parámetros de query en clave.
14) Anti-patrones
Caché sin discapacidad: la esperanza sólo en TTL → largas ventanas de irrelevancia.
Gigantesco 'Vary': la «explosión» de las variantes → bajo hit-rate.
Caché único para prod/experiments → contaminación.
No hay protección contra stampede → pico en la fuente cuando el TTL caduca.
Caché de dinero/derechos/ACL sin garantías estrictas.
Compresión «todo en fila» - CPU extra, deterioro de p99 en objetos pequeños.
15) Lista de verificación de implementación
- Identificar los niveles de caché y sus objetivos (edge/service/local).
- Diseñar claves (versionar, tenant, normalizar parámetros).
- Seleccione un patrón (cache-aside/read-through/refresh-ahead).
- Configure TTL/soft-TTL/jitter, active SWR.
- Implemente coalescing/singleflight, protección contra stampede.
- Organice la discapacidad (eventos, etiquetas, purge/ban).
- Introduzca las métricas hit-ratio/latencia y los dashboards 'X-Cache'.
- Realice pruebas de carga con llaves calientes.
- Propaga SLO y runbooks.
- Comprobar el aislamiento de seguridad/tenant y 'Vary'.
16) FAQ
P: ¿Qué elegir - cache-aside o read-through?
R: Para servicios simples - cache-aside. Lo que se necesita es centralización y una política unificada - read-through.
P: ¿Cómo puedo entender el TTL óptimo?
R: Repulse de la obsolescencia permitida, la frecuencia de las actualizaciones y la tasa de éxito objetivo; añadir jitter y observar p95/p99/costo.
P: ¿Cuándo es apropiado escribir-volver?
R: Para los flujos altamente cargados, donde la consistencia eventual es aceptable y hay una cola/registro confiable para «preescribir».
P: ¿Se pueden cachear las respuestas autorizadas?
R: Sí, pero marque 'private' y/o incluya tenant/user en la clave/' Vary '. Para truly-private, caché del cliente.
P: ¿Cómo calentar la caché?
R: Listas de claves populares, fondo de la página, Replay de registros, calentamiento antes del lanzamiento/pico (Black Friday, etc.).
17) Resultados
El caché efectivo es un diseño de llaves + un patrón TTL + razonable y bien escogido, reforzado por la discapacidad por eventos, SWR/refresh-ahead y protección contra stampede. Extienda la caché por niveles (cliente/edge/servicio), agregue observabilidad y SLO, y obtenga colas estables de latencia, costo predecible y resistencia a cargas máximas.