Caching-Architektur: Redis, Memcached
Caching-Architektur: Redis, Memcached
1) Wann und warum der Cache
Ziele: Latenz reduzieren, DB/PSP/externe APIs entlasten und Spitzen abfedern.
Cache-Ebenen sind oft mehrstufig: in-process (L1) → service-level (Redis/Memcached L2) → edge/CDN. Der interne Cache beschleunigt „heiße“ Lesungen, L2 ist für Dienste üblich, Edge für öffentliche Inhalte.
2) Redis vs Memcached - kurz
Regel: Wenn Sie komplexe Datenstrukturen, Persistenz, pub/sub/streams/scripts benötigen - nehmen Sie Redis. Wenn super-einfache, schnelle, günstige KV-Cache-Layer ohne Durability - Memcached.
3) Caching-Muster
3. 1 Cache-aside (lazy)
Die Anwendung liest aus dem Cache → einem Fehler → liest aus der Datenbank → legt sie mit TTL in den Cache.
Einfache TTL-Kontrolle, Unabhängigkeit vom Cache. − Ein „Sturm“ bei Fehlschlägen ist möglich.
3. 2 Read-through
Der Client/Proxy zieht sich bei einem Fehler selbst vom Ursprung hoch und legt ihn in den Cache.
Zentralisierte Logik. − Schwieriger infrastrukturell.
3. 3 Write-through / Write-behind
Write-through: Schreiben Sie zuerst in den Cache, dann in die DB.
Write-behind: Schreiben in die Warteschlange, asynchrones Flash in der DB (potentieller Verlust bei schönem - Logbuch benötigt).
3. 4 Two-tier (L1+L2)
L1 (in-process) mit kurzer TTL und soft TTL, L2 (Redis/Memcached) ist die „Cache-Wahrheit“. Behinderung durch pub/sub.
4) TTL, Stürme und Konsistenz
TTL: Stellen Sie nahe an die Häufigkeit der Datenänderung. Verwenden Sie für Hot Keys die TTL-Randomisierung (jitter): 'ttl = base ± rand (0.. base0. 1)'- Entfernt synchrone Lecks.
Dogpile (Thundering-Herd): Schützen Sie Fehler:- Singleflight: Nur ein Prozess generiert einen Wert neu (siehe Beispiel Lua).
- Soft-TTL + background refresh: nach 'soft _ ttl' veraltet (stale) verschenken und mit dem Hintergrund aktualisieren.
- Semaphore/lock: `SET key:lock value NX PX=2000`.
- Near-stale: 'stale-while-revalidate' für die Antwort-API (siehe Abschnitt 8).
5) Schlüssel, Nijmspaces, Serialisierung
5. 1 Benennung der Schlüssel
Vorlage: '{domain}: {entity}: {id}: {field} '
Beispiele:- `user:profile:42` `catalog:product:1001:v2` `psp:rates:2025-11-03`
Fügen Sie eine Version des Schemas hinzu (': v2') - dies erleichtert die Massenbehinderung.
5. 2 Nijmspaces durch die „Version des Raumes“
Halten Sie den Schlüssel 'ns: Katalog = 17'. Echte Schlüssel: 'Katalog: 17: Produkt: 1001'. Für eine globale Katalog-Behinderung einfach 'ns: Katalog' inkrementieren.
5. 3 Serialisierung/Kompression
JSON - bequem, aber schwer. Verwenden Sie MessagePack/CBOR.
Aktivieren Sie die Kompression (LZ4/ZSTD) für große payload (> 1-2 KB). Bei Redis - auf Kundenseite.
6) Hot Keys und Sharding
Hot-keys: top-N durch hit/miss/byte überwachen. Für extrem heiße Schlüssel:- Repliziertes Lesemuster: Duplizieren Sie den Wert in mehreren Shard-Schlüsseln 'hot: k: 1.. N', wählen Sie beim Lesen zufällig aus.
- Local L1: Behalten Sie den Prozess mit einem Behindertenabonnement im Gedächtnis.
- Redis Cluster - nativ (16384 Hash-Slots).
- Memcached ist ein Client-konsistenter Hash.
- Der Hash-Tag in Redis'{...} 'fixiert den Steckplatz für den Schlüsselsatz:' user: {42}: profile' und 'user: {42}: limits' werden sich auf dem gleichen Charme befinden.
7) Verdrängungspolitiken und Dimensionen
Redis `maxmemory-policy`: `allkeys-lru`, `volatile-lru`, `allkeys-lfu`, `noeviction` и т. д. Für den Cache ist normalerweise' allkeys-lru '/' allkeys-lfu'.
Memcached — LRU на item-slab.
Schlüsselgröße und Wert: Achten Sie auf die max. Artikelgröße (standardmäßig 1 MB memcached, slab tuning).
Der Speicherüberschuss sollte vorhersehbar abgebaut werden: nicht 'noeviction' auf dem aktiven Pfad.
maxmemory 32gb maxmemory-policy allkeys-lfu hz 50 tcp-keepalive 60
8) Sturmschutzmuster - Code
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 (vereinfacht)
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) Behinderung und Kohärenz
Nach Ereignis: Wenn sich die Datenbank ändert, veröffentlichen Sie' pub/sub 'Ereignis' invalidate: {ns}: {id} '→ Abonnenten löschen die Schlüssel.
Per Timer: kurze TTL für häufig wechselnde Daten.
Versionierung: siehe' ns: 'Schlüssel.
Outbox: Garantie der Lieferung der Behinderung (Ereignis in Log/Topic, Retrays).
Idempotenz von Cache-Operationen: Verwenden Sie' SETXX/SETNX', Versionen ('etag') und Hash-Felder für das Inkrement.
10) Replikation, Cluster, Failover
10. 1 Redis
Sentinel: automatische fehlgeschlagene Master-Replik (StaatFUL IP/Name).
Cluster: Sharding + automatischer Failover; Kunden müssen „MOVED/ASK“ -Umleitungen unterstützen.
AOF/RDB: Für einen Cache in der Regel 'appendfsync everysec', können Sie ohne Persistenz (als reiner Cache).
10. 2 Memcached
Keine Replikation aus der Box. Zuverlässigkeit - durch Multi-Server-Shard + Wiederholung'n'(Client-Seite).
Wenn der Node fällt, steigt der Fehler und der Cache wird „umgeschult“.
10. 3 K8s und Netzwerkaspekte
Redis/Memcached mögen keine häufige Neuanlage von Pod's; Verwenden Sie StatefulSet + Antipoden von AZ, feste PVC/POD IP.
Setzen Sie PodDisruptionBudget und TopologySpreadConstraints.
11) Transaktionen, Skripte und Atomarität (Redis)
INCR/DECR, HINCRBY - Zähler, Quoten, Rate-Limits (nur Persist berücksichtigen).
MULTI/EXEC ist ein Bündel von atomaren Befehlen.
Lua (EVAL) - lesen-ändern-schreiben ohne Rennen.
Pipeline - Reduziert RTT (besonders beim Netzwerk-Hop).
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) Warteschlangen, pub/sub und Streams (Redis)
Pub/Sub: Behinderung, Signale. Keine Speicherung, nur Online-Hörer.
Streams: Event-Warteschlangen mit Bestätigung (ACK), Verbrauchergruppen, Retrays - praktisch für Write-Behind/Fan-Outs.
Listen („BRPOP“): einfache Warteschlangen.
Verwenden Sie Redis nicht als „Single Bus of Everything“ ohne Backup - es ist ein Cache/schneller Bus, kein Kafka.
13) Sicherheit und Zugang
Isolierung von Netzwerken/VPC, mTLS auf Ingress-Ebene, ACLs/Passwörter ('requirepass '/ACL in Redis 6 +).
Disable dangerous Befehle in Redis ('CONFIG', 'FLUSHALL', 'KEYS') über die ACL.
Für Memcached - nicht auf öffentliche Schnittstellen hören, '-U 0' (ohne UDP), nur private Netzwerke.
PII nicht aufbewahren; bei Bedarf - kurze TTL + Verschlüsselung auf Anwendungsebene.
14) Beobachtbarkeit und Wartung
Schlüsselmetriken:- Trefferverhältnis/Miss-Verhältnis (nach Namespace/Route).
- Latenz p95/p99 der Befehle' GET/SET/MGET', timeouts.
- Evictions и OOM errors.
- Replication lag (Redis), cluster state, migrate/rehash events.
- Top-N Keys nach Verkehr/Bytes (Sampling).
- Logs: langsame Befehle ('slowlog'), Netzwerkfehler.
- Dashboards: allgemein (CPU/RAM/Verbindungen), Befehle, Cluster-Slots, Sentinels, Durchlauf durch Prometheus-Exporteure.
15) Configs und Einsatz - Beispiele
15. 1 Redis Sentinel (Fragment)
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 (Helmwerte, vereinfacht)
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 als Read-Through-Proxy (API-Loop)
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) Testen und Tore
Belastungsprofile „kalt/warm/heiß cache“.
Injektion von Fehlwürfen (Purge massiv) - Herkunft muss „Umschulung“ standhalten.
Alertas: ein starker Rückgang der Hit-Ratio, ein Anstieg der Miss-Latenz, eine Lawine von Ereignissen, ein Anstieg der Timeouts.
17) Anti-Muster
Speichern Sie die „Wahrheit“ in Redis ohne AOF/RDB und ohne Redundanz.
TTL = 0 (unbefristet) für volatile Daten → ewige Inkonsistenz.
Masse' KEYS 'in der Produktion.
Das Fehlen von Jitter/Soft-TTL → synchrone Ausflüsse und Stürme.
Eine Instanz für alle Befehle ohne Sharding/Replikate.
Verwenden Sie Memcached für Aufgaben, die Atomizität/Skripte erfordern.
18) Checkliste Umsetzung (0-45 Tage)
0-10 Tage
Wählen Sie ein Muster (cache-aside + L1/L2), beschreiben Sie die Schlüssel, TTL, nijmspaces.
Aktivieren Sie jitter/soft-TTL, singleflight; Basis-Alerts/Dashboards.
Für Redis - Konfigurieren Sie ACL, protected-mode, slowlog, maxmemory-policy.
11-25 Tage
Wechseln Sie zu Sharding (Redis Cluster oder Client-Hash), Repliken.
Behinderung durch pub/sub oder neymspace Version; outbox in der DB.
Belastungstests „Umschulung“ des Cache; limiting origin.
26-45 Tage
Autopromo/Kanarienvogel TTL, Aufwärmen vor Release.
Streams für write-behind/fonowych peresborok.
Wöchentliche Berichte über Hit-Ratio, Top-Keys, Speicherkosten.
19) Reifegradkennzahlen
Hit-ratio L2 ≥ 80% (Statistik nach Routen/Nijmspaces).
GET- P95 <2-3 ms (in-DC), Fehler <SLO-Ursprung.
0 Stürme mit massiver Behinderung (nachgewiesen durch Tests).
Automatische Behinderung und Versionierung von Nijmspaces.
Sharding/Replikation deckt den Ausfall von 1 Knoten ohne erkennbare Degradation ab.
20) Schlussfolgerung
Eine starke Cache-Architektur ist die Disziplin von Schlüssel und TTL, Sturmschutz, richtiges Scharren und vorhersehbare Verdrängung. Redis gibt reiche Semantik, Persistenz und Atomarität; Memcached ist das Maximum an Einfachheit und Geschwindigkeit. Fügen Sie Beobachtbarkeit, Behinderung durch Ereignisse, L1 + L2 hinzu, und der Cache wird zum Plattformbeschleuniger, nicht zu einer Quelle zufälliger Stürze und „mystischer“ Bugs.