Arquitectura de caché: Redis, Memcached
Arquitectura de caché: Redis, Memcached
1) Cuándo y por qué el caché
Objetivos: reducir la latencia, descargar la DAB/PSP/API externa y suavizar los picos.
Las capas de caché son a menudo en niveles: in-process (L1) → service-level (Redis/Memcached L2) → edge/CDN. El caché interno acelera las lecturas «calientes», L2 - común a los servicios, edge - para el contenido público.
2) Redis vs Memcached - breve
Regla: si necesita estructuras de datos complejas, persistencia, pub/sub/streams/scripts - tome Redis. Si la capa de caché KV es súper simple, rápida y barata sin durabilidad - Memcached.
3) Patrones de caché
3. 1 Cache-aside (lazy)
La aplicación lee desde el kash → error → lee desde el DB → lo pone en caché con TTL.
Control simple de TTL, independencia del kash − Es posible una «tormenta» en caso de averías.
3. 2 Read-through
El propio cliente/proxy saca del origin cuando falta y lo pone en caché.
Lógica centralizada: − Más compleja es la infraestructura.
3. 3 Write-through / Write-behind
Write-through: grabar primero en caché, luego en CD.
Write-behind: escritura en cola, flash asíncrono en la DB (pérdida potencial por colapso - necesita registro).
3. 4 Two-tier (L1+L2)
L1 (in-process) con TTL corta y TTL suave, L2 (Redis/Memcached) es la «verdad del kash». Discapacidad a través de pub/sub.
4) TTL, tormentas y consistencia
TTL: establecer cerca de la frecuencia de cambio de datos. Para las claves calientes, utilice la aleatorización TTL (jitter): 'ttl = base ± rand (0.. base0. 1) '- quita las expiraciones sincrónicas.
Dogpile (thundering herd): proteja los errores:- Singleflight: sólo un proceso vuelve a generar un valor (vea el ejemplo de Lua).
- Soft-TTL + background refresh: después de 'soft _ ttl', regala lo obsoleto (stale) y actualiza con el fondo.
- Semaphore/lock: `SET key:lock value NX PX=2000`.
- Near-stale: 'stale-while-revalidate' para las respuestas API (ver sección 8).
5) Llaves, neymspaces, serialización
5. 1 Nombres de claves
Plantilla: '{domain}: {entity}: {id}: {field}'
Ejemplos:- `user:profile:42` `catalog:product:1001:v2` `psp:rates:2025-11-03`
Agregue una versión del esquema (': v2') - esto facilita la discapacidad masiva.
5. 2 Neymspaces a través de la «versión del espacio»
Mantenga la clave 'ns: catalog = 17'. Claves reales: 'catalog: 17: product: 1001'. Para la discapacidad global del catálogo, basta con incorporar 'ns: catalog'.
5. 3 Serialización/compresión
JSON - cómodo, pero pesado. Utilice MessagePack/CBOR.
Encienda la compresión (LZ4/ZSTD) para grandes payload (> 1-2 KB). En Redis, en el lado del cliente.
6) Llaves calientes y charding
Hot-keys: Monitor top-N por hit/miss/byte. Para llaves extremadamente calientes:- Replicated read pattern: duplique el valor en varias claves shard 'hot: k: 1.. N', seleccione aleatorio al leer.
- Local L1: mantener en la memoria del proceso con una suscripción de discapacidad.
- Redis Cluster es nativo (16384 ranuras hash).
- Memcached es un hash de consistencia cliente.
- Hash-tag en Redis '{...}' fija la ranura para el conjunto de claves: 'user: {42}: profile' y 'user: {42}: limits' terminarán en la misma charda.
7) Políticas de desplazamiento y dimensiones
Redis `maxmemory-policy`: `allkeys-lru`, `volatile-lru`, `allkeys-lfu`, `noeviction` и т. д. Para el kash, normalmente 'allkeys-lru '/' allkeys-lfu'.
Memcached — LRU на item-slab.
Tamaño de la clave y valor: siga el tamaño máximo del item (Memcached por defecto de 1 MB, ajuste slab).
El exceso de memoria debe degradarse previsiblemente: no 'noeviction' en la ruta activa.
maxmemory 32gb maxmemory-policy allkeys-lfu hz 50 tcp-keepalive 60
8) Patrones de protección contra tormentas - código
8. 1 Redis Lua singleflight (pseudo)
lua
-- KEYS[1] = data_key, KEYS[2] = lock_key
-- ARGV[1] = now_ms, ARGV[2] = soft_ttl_ms, ARGV[3] = hard_ttl_ms, ARGV[4] = lock_ttl_ms local payload = redis. call("GET", KEYS[1])
if payload then local meta = redis. call("HGETALL", KEYS[1].. ":meta")
local last = tonumber(meta[2] or "0")
if tonumber(ARGV[1]) - last < tonumber(ARGV[2]) then return { "HIT", payload }
end if redis. call ("SET," KEYS [2], "1," "NX," "PX," ARGV [4]) then return {"REFRESH," payload} - one worker updates, the rest give stale end return {"STALE," payload}
end if redis. call("SET", KEYS[2], "1", "NX", "PX", ARGV[4]) then return { "MISS", nil }
end return { "BUSY", nil }
8. 2 Node. js cache-aside (simplificado)
js const v = await redis. get(key);
if (v) return decode(v);
const lock = await redis. setNX(key+":lock", "1", { PX: 1500 });
if (lock) {
const fresh = await loadFromDB(id);
await redis. set(key, encode(fresh), { EX: ttl, NX: false });
await redis. del(key+":lock");
return fresh;
} else {
await sleep(60); // short backoff const retry = await redis. get (key) ;//give someone's already filled return decode (retry);
}
9) Discapacidad y coherencia
Por evento: si cambia en la DB, publique 'pub/sub' evento 'invalidate: {ns}: {id}' → los suscriptores eliminan las claves.
Por temporizador: TTL corto para datos que cambian con frecuencia.
Versionar: consulte 'ns:' claves.
Outbox: garantía de entrega de discapacidad (evento en el registro/topic, retrai).
Idempotencia de las operaciones de caché: utilice 'SETXX/SETNX', versiones ('etag') y campos hash para el incremento.
10) Replicación, clúster, failover
10. 1 Redis
Sentinel: failover automático master-replica (stateFUL IP/name).
Cluster: charding + failover automático; los clientes deben admitir redirecciones 'MOVED/ASK'.
AOF/RDB: para el kash generalmente 'appendfsync everysec', se puede sin persistencia (como caché puro).
10. 2 Memcached
No hay replicación fuera de la caja. Fiabilidad: a través de un shard de varios servidores + repetición 'n' (lado cliente).
Cuando el nodo cae, el crecimiento de las faltas y la «re-enseñanza» del kash.
10. 3 aspectos K8s y de red
A Redis/Memcached no les gusta el reacomodo frecuente de pod's; use StatefulSet + antípodas por AZ, IP de PVC/POD fijo.
Ponga PodDisruptionBudget y TopologySpreadConstraints.
11) Transacciones, scripts y atomicidad (Redis)
INCR/DECR, HINCRBY - contadores, cuotas, ratios-límites (sólo tenga en cuenta el persista).
MULTI/EXEC es un paquete de comandos atómicos.
Lua (EVAL) - read-modify-write sin carreras.
Pipeline: reduce el RTT (especialmente en el hop de red).
lua
-- KEYS[1]=bucket, ARGV[1]=capacity, ARGV[2]=refill_rate_per_sec, ARGV[3]=now_ms
-- Returns 1 if the token is issued, otherwise 0
12) Colas, pub/sub y Streams (Redis)
Pub/Sub: discapacidad, señales. Sin guardar, sólo los oyentes en línea.
Streams: colas de eventos de confirmación (ACK), grupos de consumidores, retrayas - conveniente para write-behind/fan outs.
Lists ('BRPOP'): colas simples.
No utilice Redis como un «bus único de todo» sin un respaldo - es un bus rápido/caché, no Kafka.
13) Seguridad y acceso
Aislamiento de redes/VPC, mTLS a nivel ingress, ACL/contraseñas ('requirepass '/ACL en Redis 6 +).
Comandos dangerous deshabilitables en Redis ('CONFIG', 'FLUSHALL', 'KEYS') a través de la ACL.
Para Memcached, no escuchar interfaces públicas, '-U 0' (sin UDP), sólo redes privadas.
PII no almacenar; si es necesario - cifrado TTL + corto a nivel de aplicación.
14) Observabilidad y mantenimiento
Métricas clave:- Hit ratio/Miss ratio (por namespace/ruta).
- Latency p95/p99 comandos 'GET/SET/MGET', timeouts.
- Evictions и OOM errors.
- Replication lag (Redis), cluster state, migrate/rehash events.
- Llaves Top-N por tráfico/bytes (sampling).
- Logs: comandos lentos ('slowlog'), errores de red.
- Dashboards: general (CPU/RAM/connections), comandos, ranuras de clúster, sentinels, pasando a través de los exportadores Prometheus.
15) Configuraciones e implementaciones - ejemplos
15. 1 Redis Sentinel (fragmento)
port 6379 protected-mode yes appendonly yes appendfsync everysec maxmemory-policy allkeys-lfu
`sentinel. conf`:
sentinel monitor m1 10. 0. 0. 11 6379 2 sentinel auth-pass m1 sentinel down-after-milliseconds m1 5000 sentinel failover-timeout m1 60000
15. 2 Redis Cluster (helm valores, simplificado)
yaml cluster:
enabled: true nodes: 6 # 3 masters + 3 replicas persistence:
size: 100Gi resources:
requests: { cpu: "500m", memory: "2Gi" }
15. 3 Memcached (deployment)
yaml containers:
- image: memcached:1. 6 args: ["-m", "32768", "-I", "2m", "-v", "-t", "8", "-o", "modern"]
ports: [{ containerPort: 11211 }]
15. 4 NGINX como proxy read-through (esquema API)
nginx proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=api:100m max_size=10g inactive=10m;
map $request_uri $cache_key { default "api:$request_uri"; }
location /api/ {
proxy_cache api;
proxy_cache_valid 200 1m;
proxy_cache_use_stale updating error timeout http_500 http_502 http_503 http_504;
proxy_cache_lock on; # singleflight на уровне NGINX proxy_cache_key $cache_key;
proxy_pass http://backend;
}
16) Pruebas y Gates
Perfiles de carga «caché frío/caliente/caliente».
Inyección de extravíos (purge en masa) - origin debe soportar la «re-enseñanza».
Alertas: fuerte caída de hit-ratio, crecimiento de miss latency, avalancha de evictions, crecimiento de timeouts.
17) Anti-patrones
Almacenar la «verdad» en Redis sin AOF/RDB y sin redundancia.
TTL = 0 (indefinidamente) para los datos volátiles → la inconsistencia eterna.
Masivo 'KEYS' en venta.
Sin jitter/soft-TTL → caducidades sincrónicas y tormenta.
Una instancia para todos los equipos sin charding/réplicas.
Utilizar Memcached para tareas que requieran atomicidad/scripts.
18) Lista de verificación de implementación (0-45 días)
0-10 días
Seleccione una plantilla (cache-aside + L1/L2), describa las claves, TTL, neymspaces.
Habilitar jitter/soft-TTL, singleflight; alertas/dashboards básicos.
Para Redis, configure ACL, modo protegido, slowlog, política de memoria máxima.
11-25 días
Ir a un clúster Redis (Redis Cluster), réplicas.
Discapacidad a través de pub/sub o versión de neymspace; outbox en el DB.
Pruebas de carga de «readiestramiento» de kash; limiting origin.
26-45 días
Autopromoción/TTL canario, calentamiento antes del lanzamiento.
Streams para sobreesfuerzos write-behind/de fondo.
Informes semanales sobre hit-ratio, las principales claves, el costo de la memoria.
19) Métricas de madurez
Hit-ratio L2 ≥ el 80% (estadísticas por rutas/no rutas).
P95 GET <2-3 ms (in-DC), errores <SLO origin.
0 tormenta en invalidez masiva (probada por pruebas).
Invalidez automática y versionamiento de neimspaces.
La charding/replicación cubre la falla de 1 nodo sin degradación notable.
20) Conclusión
La arquitectura de kash fuerte es la disciplina de llaves y TTL, la protección contra tormentas, el charding correcto y el desplazamiento predecible. Redis da una rica semántica, persistencia y atomicidad; Memcached - máxima simplicidad y velocidad. Agregue la observabilidad, la discapacidad por eventos, L1 + L2, y el caché se convertirá en un acelerador de plataforma, no en una fuente de caídas accidentales y errores «místicos».