Arhitectura caching: Redis, Memcached
Arhitectura caching: Redis, Memcached
1) Când și de ce cache
Obiective: reducerea latenței, descărcarea API DB/PSP/externe și atenuarea vârfurilor.
Straturile cache sunt adesea multilevel: în proces (L1) → service-level (Redis/Memcached L2) → edge/CDN. Memoria cache internă accelerează citirile fierbinți, L2 este comun pentru servicii, marginea este pentru conținut public.
2) Redis vs Memcached - Scurt
Regulă: dacă aveți nevoie de structuri complexe de date, persistență, pub/sub/streams/scripts - ia Redis. În cazul în care stratul de cache KV super-simplu, rapid, ieftin, fără durabilitate este Memcached.
3) Modele de caching
3. 1 Cache-deoparte (leneș)
Aplicația citește din memoria cache → o miss → citește din baza de date → o pune în memoria cache cu TTL.
Controlul TTL simplu, independența cache. − Posibil „furtună” în caz de ratări.
3. 2 Read-through
Clientul/proxy-ul în sine trage de la origine la o ratare și o pune în memoria cache.
Logică centralizată, − infrastructură mai complexă.
3. 3 Scriere/Scriere în spate
Scrieți: scrieți mai întâi la memoria cache, apoi la baza de date.
Write-back: scrierea la coadă, flash asincron în baza de date (pierdere potențială atunci când se prăbușește - aveți nevoie de un jurnal).
3. 4 Două niveluri (L1 + L2)
L1 (în proces) cu TTL scurt și TTL moale, L2 (Redis/Memcached) - "adevărul cache. "Handicap prin pub/sub.
4) TTL, furtuni și consistență
TTL-Set aproape de frecvența schimbării datelor. Pentru tastele fierbinți, utilizați randomizarea TTL (jitter): 'ttl = base ± rand (0.. base0. 1) "- elimină ieșirile sincrone.
Dogpile (turmă tunătoare): protejați ratările:- Singleflight: doar un singur proces suprasaturează valoarea (vezi exemplul Lua).
- Soft-TTL + refresh fundal: după 'soft _ ttl', da-l vechi și actualiza cu fundalul.
- Semaphore/lock: 'SET cheie: valoare de blocare NX PX = 2000'.
- Near-stale: „stale-în timp ce-revalidate” pentru API-uri de răspuns (vezi pct. 8).
5) Chei, namespace, serializare
5. 1 Denumire cheie
Template: '{domeniu}: {entitate}: {id}: {câmp}'
Exemple:- 'utilizator: profil: 42' 'catalog: produs: 1001: v2' 'psp: rate: 2025-11-03'
Adăugați o versiune schemă („: v2”) - acest lucru facilitează dizabilitatea în masă.
5. 2 Neimspaces prin „versiune spațială”
Țineți apăsată tasta 'ns: catalog = 17'. Chei reale: 'catalog: 17: produs: 1001'. Pentru handicap director global, pur și simplu increment 'ns: catalog'.
5. 3 Serializare/Compresie
JSON este convenabil, dar greu. Utilizaţi MessagePack/CBOR.
Activați compresia (LZ4/ZSTD) pentru sarcină utilă mare (> 1-2 KB). În Redis - pe partea de client.
6) chei fierbinți și sharding
Hot-chei: Monitor top-N de lovit/dor/octet. Pentru chei extrem de fierbinte:- Model de citire replicat: duplicați valoarea în mai multe taste cioburi "fierbinte: k: 1.. N ', alegeți aleatoriu atunci când citiți.
- Local L1: Țineți cont de procesul de abonare pentru persoanele cu handicap.
- Redis Cluster - nativ (16384 sloturi hash).
- Memcached este un hash consistent client-side.
- Hash-tag în Redis '{...}' fixează un slot pentru un set de taste: 'utilizator: {42}: profil' și 'utilizator: {42}: limite' va fi pe aceeași carte.
7) Politici de preempțiune și dimensiuni
Redis 'maxmemory-policy': 'allkeys-lru', 'volatile-lru', 'allkeys-lfu', 'noeviction' и т. д. Pentru memoria cache, de obicei „allkeys-lru ”/„ allkeys-lfu”.
Memcached - LRU на element-lespede.
Dimensiunea și valoarea cheii: urmăriți dimensiunea maximă a elementului (Memcached în mod implicit 1 MB, placă de tuning).
Depășirea memoriei ar trebui să se degradeze previzibil: nu „noevicție” pe calea activă.
maxmemory 32gb maxmemory-policy allkeys-lfu hz 50 tcp-keepalive 60
8) Modele de protecție împotriva furtunilor - Cod
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 Nod. js cache-deoparte (simplificat)
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) Handicap și coerență
După eveniment: Atunci când schimbați în baza de date, publicați 'pub/sub' event 'invalidate: {ns}: {id}' → abonații șterg cheile.
Prin cronometru: scurt TTL pentru schimbarea frecventă a datelor.
Versioning: a se vedea „ns:” chei.
Outbox: garanție de livrare a dizabilității (eveniment jurnal/subiect, retrai).
Idempotența operațiunilor cache: utilizați 'SETXX/SETNX', versiunile ('etag') și câmpurile hash pentru increment.
10) Replicare, cluster, failover
10. 1 Redis
Sentinel: automat failover master-replica (stateFUL IP/nume).
Cluster: sharding + failover automat; clienții trebuie să sprijine redirecționările 'MOVED/ASK'.
AOF/RDB: pentru memoria cache de obicei „appendfsync everysec”, este posibil fără persistență (ca o memorie cache pură).
10. 2 Memcached
Nici o replicare din cutie. Fiabilitate - prin cioburi multi-server + repetare 'n' (client-side).
Când nodurile cad, există o creștere a ratărilor și a „recalificării” memoriei cache.
10. 3 K8s și Networking
Redis/Memcached nu le place recrearea frecventă a păstăilor; utilizați StatefulSet + AZ antipozi, fixe PVC/POD IP.
Setați PodDisruptionBudget și TopologySpreadConstricts.
11) Tranzacții, script-uri și atomicitate (Redis)
INCR/DECR, HINCRBY - contoare, cote, limite de rată (luați în considerare persista).
MULTI/Ï - un pachet de comenzi atomice.
Lua (EVAL) - citire-modificare-scriere fără curse.
Conducte - reduce RTT (în special în hamei de rețea).
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) Cozi, pub/sub și fluxuri (Redis)
Pub/Sub: handicap, semnale. Fără salvare, doar ascultători online.
Fluxuri: Cozi de evenimente de confirmare (ACK), Consumer Group, Retrai - la îndemână pentru write-back/fan-out.
Liste („BRPOP”): cozi simple.
Nu utilizați Redis ca un „autobuz unic de tot” fără o copie de rezervă - acesta este un cache/autobuz rapid, nu Kafka.
13) Securitate și acces
Izolarea rețelei/VPC, mTLS la nivel de intrare, ACL/parole ("requirement pass'/ACL în Redis 6 +).
Dezactivați comenzile periculoase din Redis ('CONFIG', 'FLUSHALL', 'KEYS') prin ACL.
Pentru Memcached - nu ascultați interfețe publice, „-U 0” (fără UDP), doar rețele private.
A nu se păstra PII; dacă este necesar - criptare TTL + scurtă la nivelul aplicației.
14) Observabilitate și întreținere
Valori cheie:- Raportul lovit/raportul Miss (prin namespace/traseu).
- Latență p95/p99 „GET/SET/MGET” comenzi, timeout.
- Evacuări и erori OOM.
- Replicarea lag (Redis), starea clusterului, migrează/rehash evenimente.
- Top-N chei de trafic/octeți (eșantionare).
- Jurnale: comenzi lente ('slowlog'), erori de rețea.
- Tablouri de bord: general (CPU/RAM/conexiuni), comenzi, sloturi de cluster, santine, care trec prin exportatorii Prometheus.
15) Configurări și implementări - exemple
15. 1 Redis Sentinel (fragment)
port 6379 protected-mode yes appendonly yes appendfsync everysec maxmemory-policy allkeys-lfu
'sentinel. conf. univ. dr
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 (valori ale cârmei, simplificate)
yaml cluster:
enabled: true nodes: 6 # 3 masters + 3 replicas persistence:
size: 100Gi resources:
requests: { cpu: "500m", memory: "2Gi" }
15. 3 Memcached (implementare)
yaml containers:
- image: memcached:1. 6 args: ["-m", "32768", "-I", "2m", "-v", "-t", "8", "-o", "modern"]
ports: [{ containerPort: 11211 }]
15. 4 NGINX ca proxy read-through (buclă 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) Testarea și porțile
Profile de încărcare cache rece/cald/cald.
Injecția de ratări (purge en masse) - originea trebuie să reziste la „recalificare”.
Alerte: scădere bruscă a raportului hit, creștere a latenței miss, avalanșă de evacuări, creștere a termenelor.
17) Anti-modele
Stocați „adevărul” în Redis fără AOF/RDB și fără redundanță.
TTL = 0 (perpetuu) pentru date volatile → inconsecvență perpetuă.
Mass' KEYS' in prod.
Absența jitter/soft-TTL → întreruperi sincrone și furtuni.
Un exemplu pentru toate comenzile fără shardings/replicas.
Utilizați Memcached pentru sarcini care necesită atomicitate/scripturi.
18) Lista de verificare a implementării (0-45 zile)
0-10 zile
Selectați un șablon (cache-deoparte + L1/L2), descrieți tastele, TTL, namespaces.
Activați jitter/soft-TTL, singleflight; alerte de bază/tablouri de bord.
Pentru Redis - configurați ACL, modul protejat, slowlog, politica maxmemory.
11-25 zile
Comutare la sharding (Redis Cluster sau client hash), replici.
Handicap prin pub/sub sau versiunea neimspace; outbox în baza de date.
cache „recalificare” încercări de sarcină; limitarea originii.
26-45 zile
Autopromo/canar TTL, warm-up înainte de lansare.
Fluxuri pentru redistribuire în spate/fundal.
Rapoarte săptămânale despre raportul de succes, tastele de top, costul memoriei.
19) Valorile maturității
Hit-ratio L2 ≥ 80% (statistici privind rutele/namespaces).
P95 GET <2-3 ms (in-DC), ratează <originea SLO.
0 furtuni în handicap în masă (dovedit prin teste).
Invaliditate automată și versioning nymspace.
Sharding/replicare acoperă 1 eșec nod fără degradare apreciabilă.
20) Concluzie
Arhitectura cache puternică este disciplina cheilor și TTL, protecția împotriva furtunii, timiditatea adecvată și preempțiunea previzibilă. Redis dă semantică bogată, persistență și atomicitate; Memcached - simplitate maximă și viteză. Adăugați observabilitate, handicap eveniment, L1 + L2, iar memoria cache devine un accelerator platformă, nu o sursă de picături accidentale și bug-uri „mistice”.