Architettura di cache: Redis, Memcached
Architettura di cache: Redis, Memcached
1) Quando e perché la cache
Obiettivi: ridurre la latitanza, scaricare il database/PSP/API esterne e ridurre i picchi.
I livelli di cache sono spesso su più livelli: in-process (L1) → service-level (Redis/Memcached L2) → edge/CDN. La cache interna accelera le letture hot, L2 le letture comuni ai servizi, edge i contenuti pubblici.
2) Redis vs Memcached - breve
Regola: Se avete bisogno di strutture complesse di dati, persistenza, pub/sub/striam/script, prendete Redis. Se super semplice, veloce, a basso costo KV-cash-slot senza durability - Memcached.
3) Modelli di cache
3. 1 Cache-aside (lazy)
L'app legge dalla cassaforte, legge dal database e la mette nella scatola con la TTL.
Controllo semplice della TTL, indipendenza dal caschetto.
3. 2 Read-through
Il client/proxy si allunga da origin in caso di errore e lo mette nella cache.
Logica centralizzata.
3. 3 Write-through / Write-behind
Write-through - Registra prima nella cache e poi nel database.
Write-behind: scrittura in coda, flash asincrono nel database (perdita potenziale crash - è necessario un registro).
3. 4 Two-tier (L1+L2)
L1 (in-process) con TTL corto e soft TTL, L2 (Redis/Memcached) è la verità della macchia. Invalidità tramite pub/sub.
4) TTL, tempeste e consistenza
TTL: imposta vicino alla frequenza di modifica dei dati. Per le chiavi calde, usa la randomizzazione TTL (jitter): 'ttl = base © rand (0.. base0. 1) '- rimuove le scadenze sincronizzate.
Dogpile (thundering herd) - Proteggi gli errori:- Singleflight - Un solo processo distingue il valore (vedere l'esempio Lua).
- Soft-TTL + background refresh: dopo «soft _ ttl», restituisci l'antiquato (stale) e aggiorna lo sfondo.
- Semaphore/lock: `SET key:lock value NX PX=2000`.
- Near-stale: «stale-while-revalidate» per le risposte API (vedere paragrafo 8).
5) Chiavi, Neimspace, serializzazione
5. 1 Denominazione chiavi
Modello: '{domain}: {entity}: {id}: {field}'
Esempi:- `user:profile:42` `catalog:product:1001:v2` `psp:rates:2025-11-03`
Aggiungi una versione dello schema ('v2') per facilitare la disabilità di massa.
5. 2 Neimspace attraverso la «versione spazio»
Tieni la chiave dì ns: catalog = 17 ". Chiavi reali: 'catalog: 17: product: 1001'. Per la disabilità globale della directory, è sufficiente incrementare «ns: catalog».
5. 3 Serializzazione/compressione
JSON - comodo, ma pesante. Usate il MessagePack/CBOR.
Attivare la compressione (LZ4/ZSTD) per i grandi payload (> 1-2 KB). Redis è dalla parte del cliente.
6) Chiavi calde e charding
Hot-keys: monitor top-N per hit/miss/byte. Per chiavi estremamente calde:- Replicated read pattern: duplica il valore in più chiavi shard «hot: k: 1.. N», scegli casuale durante la lettura.
- Locale L1 - Memorizza il processo con l'abbonamento alla disabilità.
- Redis Cluster - nativo (16384 hash slot).
- Memcached è un hash consistenziale client.
- Il tag hash di Redis' {...} 'fissa lo slot per il set di chiavi:' user: {42}: profile'e'user: {42}: limits '.
7) Criteri di espulsione e dimensioni
Redis `maxmemory-policy`: `allkeys-lru`, `volatile-lru`, `allkeys-lfu`, `noeviction` и т. д. Per la cache di solito «allkeys-lru »/« allkeys-lfu».
Memcached — LRU на item-slab.
Dimensione chiave e value - Tenere traccia di max item size (Memcached di default 1 MB, tuning slab).
L'eccesso di memoria deve degradarsi prevedibilmente senza «noeviction» sul percorso attivo.
maxmemory 32gb maxmemory-policy allkeys-lfu hz 50 tcp-keepalive 60
8) Pattern di protezione contro le tempeste - codice
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 (semplificato)
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) Disabilità e coerenza
Per evento, se modificato nel database, pubblicare «pub/sub» evento «invalidato: {ns}: {id}».
Timer: TTL breve per i dati che cambiano di frequente.
Versioning: vedere «ns:» chiavi.
Outbox - Garanzia di consegna invalidità (evento logic/topic, retrai).
Idampotenza delle operazioni di cache: usa SETXX/SETNX, versioni ('etag') e campi hash per l'incorporazione.
10) Replica, cluster, failover
10. 1 Redis
Sentinel: failover master-replica automatica (StatFUL IP/Nome).
Cluster: Charding + failover automatico; i clienti devono supportare i ready MOVED/ASK.
AOF/RDB - Per i caschi di solito «appendfsync everysec», è possibile non avere la persistenza (come un kash puro).
10. 2 Memcached
Nessuna replica dalla scatola. Affidabilità tramite shard multiserver + ripetizione «n» (client-side).
In caso di caduta di nodi, l'aumento di errori e la ricreazione del caschetto.
10. 3 K8s e aspetti di rete
I Redis/Memcached non amano il frequente reindirizzamento del Pod'ov; usa StatefulSet + antipodi AZ, PVC/POD IP fissi.
Mettete le PodDisruptionBudget e mettete le TopologySpreadConstraints.
11) Transazioni, script e atomia (Redis)
INCR/DECR, HINCRBY - Contatori, quote, rate-limits (solo conta persist).
MULTI/EXEC è un pacchetto di comandi atomici.
Lua (EVAL) - read-modify-write senza corse.
Pipeline - Riduce la RTT (specialmente con hop di rete).
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) Code, pub/sub e Streams (Redis)
Pub/Sub: disabilità, segnali. Senza salvare, solo gli ascoltatori online.
Streams: code di eventi di conferma (ACK), gruppi di consumatori, retrai - utile per write-behind/fan-out.
Lists ('BRPOP') - Code semplici.
Non usare Redis come un unico pneumatico senza becap è un pneumatico veloce o Kafka.
13) Sicurezza e accesso
Isolamento delle reti/VPC, mTLS a livello ingress, ACL/password ('richirepass '/ACL in Redis 6 +).
Disable dangerous comandi in Redis («CONFIG», «FLUSHALL», «KEYS») tramite ACL.
Per Memcached, non ascoltare interfacce pubbliche, '-U 0' (senza UDP), solo reti private.
PII non memorizzare; se necessario: TTL breve + crittografia a livello di applicazione.
14) Osservabilità e manutenzione
Metriche chiave:- Hit ratio/Miss ratio (namespace/itinerario).
- Latency p95/p99 comandi «GET/SET/MGET», timeouts.
- Evictions и OOM errors.
- Replication lag (Redis), cluster state, migrate/rehash events.
- Top-N keys per traffico/byte (sampling).
- Loghi: comandi lenti ('slowlog'), errori di rete.
- Dashboard: comune (CPU/RAM/connessioni), comandi, slot cluster, sentinels, omettendo l'esportatore Prometheus.
15) Confighi e implementazione - esempi
15. 1 Redis Sentinel (frammento)
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 values, semplificato)
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 come proxy read-through (tracciato 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) Test e gate
Profili di carico «cash freddo/caldo/caldo».
Iniezione di errori (purge in massa) - origin deve sopportare il «riutilizzo».
Alert: forte calo hit-ratio, crescita miss latency, valanga evictions, crescita timeouts.
17) Anti-pattern
Conserva la verità in Redis senza AOF/RDB e senza ridondanza.
TTL = 0 (a tempo indeterminato) per dati volatili è una non-consolazione eterna.
KEYS di massa in vendita.
L'assenza di jitter/soft-TTL → la scadenza sincrona e la tempesta.
Una sola istanza per tutte le squadre senza charding/repliche.
Usa Memcached per attività che richiedono atomatologia/script.
18) Assegno foglio di implementazione (0-45 giorni)
0-10 giorni
Seleziona un modello (cache-aside + L1/L2), descrive le chiavi, TTL, Neimspace.
Abilita jitter/soft-TTL, singleflight; alert di base/dashboard.
Per Redis - configura ACL, protected-mode, slowlog, maxmemory-policy.
11-25 giorni
Vai a charding (Redis Cluster o hash client), repliche.
Invalidità tramite pub/sub o versione neimspace; outbox nel database.
Test di carico dì riutilizzo "della cache; limiting origin.
26-45 giorni
Autotrasporto/canarini TTL, riscaldato prima del lancio.
Streams per l'intersezione write-behind/sfondo.
Report settimanali su hit-ratio, top chiavi, costo della memoria.
19) Metriche di maturità
L'Hit-ratio L2 è pari all '80% (statistiche itinerari/neimspace).
P95 GET <2-3 ms (in-DC), errori <SLO origin.
0 tempeste di disabilità di massa (provata dai test).
Disabilità automatica e versioning neimspace.
Sharding/replica copre il guasto di 1 nodo senza degrado evidente.
20) Conclusione
Una forte architettura di cache è la disciplina delle chiavi e della TTL, la protezione contro la tempesta, il giusto charding e la prevedibile espulsione. Redis dà una ricca semantica, persistenza e atomatologia; Memcached è il massimo di semplicità e velocità. Aggiungete osservazione, disabilità per evento, L1 + L2, e kash diventerà l'acceleratore della piattaforma, non la fonte di cadute accidentali e bagagli «mistici».