Architektura buforowania: Redis, Memcached
Architektura buforowania: Redis, Memcached
1) Kiedy i dlaczego pamięć podręczna
Cele: zmniejszenie opóźnień, odciążenie DB/PSP/zewnętrznych API i złagodzenie pików.
Warstwy pamięci podręcznej są często wielopoziomowe: in-process (L1) → service-level (Redis/Memcached L2) → edge/CDN. Wewnętrzna pamięć podręczna przyspiesza gorące odczyty, L2 jest powszechne dla usług, krawędź jest dla treści publicznych.
2) Redis vs Memcached - krótki
Zasada: jeśli potrzebujesz złożonych struktur danych, trwałości, pub/sub/streams/scripts - weź Redis. Jeśli super-prosta, szybka, tania warstwa pamięci podręcznej KV bez trwałości jest Memcached.
3) Wzory buforowania
3. 1 Cache-off (leniwy)
Aplikacja czyta z pamięci podręcznej → miss → czyta z bazy → umieszcza ją w pamięci podręcznej z TTL.
Proste sterowanie TTL, niezależność pamięci podręcznej. − Możliwe „burza” w przypadku braków.
3. 2 Czytanie
Klient/serwer proxy sam wyciąga z pochodzenia na miss i umieszcza go w pamięci podręcznej.
Scentralizowana logika. − Bardziej złożona infrastruktura.
3. 3 Odpis/odpis
Zapis: pisanie najpierw do pamięci podręcznej, a następnie do bazy danych.
Zapis: pisanie do kolejki, asynchroniczny błysk w bazie danych (potencjalna strata podczas awarii - potrzebujesz dziennika).
3. 4 Dwupoziomowe (L1 + L2)
L1 (w procesie) z krótkim TTL i miękkim TTL, L2 (Redis/Memcached) - "cache truth. "Niepełnosprawność przez pub/sub.
4) TTL, burze i spójność
TTL-Set blisko częstotliwości zmiany danych. W przypadku kluczy gorących należy użyć randomizacji TTL (jitter): 'ttl = base ± rand (0.. base0. 1) "- usuwa odpływ synchroniczny.
Dogpile (grzmące stado): chronić braki:- Singleflight: tylko jeden proces nadrzędnie generuje wartość (patrz przykład Lua).
- Soft-TTL + tło odświeżyć: po 'soft _ ttl', dać go stale i zaktualizować z tłem.
- Semahore/lock: 'SET key: lock value NX PX = 2000'.
- Near-stale: „stale-while-revalidate” dla API odpowiedzi (patrz punkt 8).
5) Klucze, obszary nazw, serializacja
5. 1 Nazwa klucza
Szablon: '{domain}: {entity}: {id}: {field}'
Przykłady:- „użytkownik: profil: 42” „katalog: produkt: 1001: v2” „psp: stawki: 2025-11-03”
Dodaj wersję schematu (': v2') - ułatwia to masową niepełnosprawność.
5. 2 Neimspaces poprzez „wersja kosmiczna”
Przytrzymaj klucz 'ns: catalog = 17'. Prawdziwe klucze: 'katalog: 17: produkt: 1001'. Dla niepełnosprawności katalogu globalnego, po prostu przyrost 'ns: catalog'.
5. 3 Serializacja/kompresja
JSON jest wygodny, ale ciężki. Należy użyć opakowania/CBOR.
Włącz kompresję (LZ4/ZSTD) dla dużego ładunku użytkowego (> 1-2 KB). W Redis - po stronie klienta.
6) Gorące klucze i shading
Hot-keys: Monitor top-N przez hit/miss/byte. Dla niezwykle gorących kluczy:- Replikowany wzór odczytu: powielanie wartości w kilku klawiszach odłamkowych 'hot: k: 1.. N', wybierz losowo podczas czytania.
- Lokalne L1: Pamiętaj o procesie subskrypcji niepełnosprawności.
- Redis Cluster - rodzime (16384 sloty skrótu).
- Memcached jest konsekwentnym skrótem po stronie klienta.
- Hash-tag w Redis '{...}' naprawia slot dla zestawu kluczy: 'user: {42}: profile' i 'user: {42}: limits' będzie na tej samej karcie.
7) Zasady i rozmiary preempcji
Redis "maxmemory-policy": "allkeys-lru", "volatile-lru", "allkeys-lfu", "noeviction", "ма. д. W przypadku pamięci podręcznej zwykle 'allkeys-lru '/' allkeys-lfu'.
Memcached - LRU на pozycja-płyta.
Rozmiar i wartość klucza: zegarek dla maksymalnego rozmiaru elementu (domyślnie Memcached 1 MB, płyta dostrajająca).
Przekroczenie pamięci powinno być przewidywalne: nie „noeksmisja” na aktywnej ścieżce.
maxmemory 32gb maxmemory-policy allkeys-lfu hz 50 tcp-keepalive 60
8) Wzory ochrony przed burzą - Kod
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 Węzeł. js cache-off (uproszczony)
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) Niepełnosprawność i spójność
Przez zdarzenie: Podczas zmiany w bazie danych, opublikować 'pub/sub' event 'unieważnić: {ns}: {id}' → abonenci usunąć klucze.
Przez timer: krótki TTL dla często zmieniających się danych.
Wersioning: patrz 'ns:' klucze.
Outbox: gwarancja dostawy niepełnosprawności (log/topic event, retrai).
Operacje pamięci podręcznej: użyć 'SETXX/SETNX', wersji ('etag') i pola skrótu do przyrostu.
10) Replikacja, klaster, awaria
10. 1 Redis
Sentinel: automatyczna master-replika awaryjna („FUL IP/name”).
Klaster: shading + automatyczna awaria; klienci muszą obsługiwać przekierowania „MOVED/ASK”.
AOF/RDB: dla pamięci podręcznej zwykle „appendix sync everysec” jest możliwe bez trwałości (jak czysty pamięć podręczna).
10. 2 Memcached
Nie ma replikacji z pudełka. Niezawodność - poprzez odłamek wielozadaniowy + powtarzanie 'n' (po stronie klienta).
Gdy węzły spadają, następuje wzrost braków i „przekwalifikowania” pamięci podręcznej.
10. 3 K8s i tworzenie sieci
Redis/Memcached nie podoba się częste ponowne tworzenie strąków; używać antypodów Stat Set + AZ, stałych PVC/POD IP.
Ustaw budżet PodDis i Maksymalne Ograniczenia.
11) Transakcje, skrypty i atomowość (Redis)
INCR/DECR, HINCRBY - liczniki, kwoty, limity stawek (po prostu rozważyć utrzymać).
MULTI/EXEC - pakiet poleceń atomowych.
Lua (EVAL) - read-modify-write bez wyścigów.
Rurociąg - zmniejsza RTT (zwłaszcza w chmielu sieciowym).
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) Kolejki, pub/sub i strumienie (Redis)
Pub/Sub: niepełnosprawność, sygnały. Nie oszczędzaj, tylko słuchacze online.
Strumienie: Kolejki zdarzeń potwierdzających (ACK), Grupa konsumencka, Retrai - przydatne do odpisów/wentylatorów.
Listy ('BRPOP'): proste kolejki.
Nie używaj Redis jako „pojedynczego autobusu wszystkiego” bez kopii zapasowej - jest to pamięć podręczna/szybki autobus, nie Kafka.
13) Bezpieczeństwo i dostęp
Izolacja sieci/VPC, mTLS na poziomie wejścia, ACL/hasła ('default '/ACL w Redis 6 +).
Wyłączanie niebezpiecznych poleceń w Redis ('CONFIG', 'FLUSHALL', 'KEYS') poprzez ACL.
Dla Memcached - nie słuchaj interfejsów publicznych, '-U 0' (bez UDP), tylko sieci prywatne.
Nie przechowywać PII; w razie potrzeby - krótkie szyfrowanie TTL + na poziomie aplikacji.
14) Obserwowalność i konserwacja
Kluczowe wskaźniki:- Współczynnik trafienia/stosunek Miss (według przestrzeni nazw/trasy).
- Latency p95/p99 'GET/SET/MGET' polecenia, timeouts.
- Evictions - błędy OOM.
- Opóźnienie replikacji (Redis), stan klastra, migracja/rehash zdarzeń.
- Klucze top-N przez ruch/bajty (pobieranie próbek).
- Dzienniki: powolne polecenia ('slowlog'), błędy sieciowe.
- Deski rozdzielcze: ogólne (CPU/RAM/connections), polecenia, gniazda klastra, czujniki, przechodzące przez eksporterów Prometheusa.
15) Konfiguracje i rozmieszczenia - przykłady
15. 1 Redis Sentinel (snippet)
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 Klaster Redis (wartości steru, uproszczone)
yaml cluster:
enabled: true nodes: 6 # 3 masters + 3 replicas persistence:
size: 100Gi resources:
requests: { cpu: "500m", memory: "2Gi" }
15. 3 Memcached (rozmieszczenie)
yaml containers:
- image: memcached:1. 6 args: ["-m", "32768", "-I", "2m", "-v", "-t", "8", "-o", "modern"]
ports: [{ containerPort: 11211 }]
15. 4 NGINX jako serwer proxy (pętla 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) Badania i bramy
Profile obciążenia pamięci podręcznej zimnej/ciepłej/gorącej.
Wstrzyknięcie braków (masowo oczyszczonych) - pochodzenie musi wytrzymać „przekwalifikowanie”.
Ostrzeżenia: gwałtowny spadek współczynnika trafienia, wzrost opóźnienia, lawina eksmisji, wzrost czasu.
17) Anty-wzory
Przechowywać „prawdę” w leku Redis bez AOF/RDB i bez redundancji.
TTL = 0 (wieczyste) dla danych lotnych → niekonsekwencja wieczysta.
Mass 'KEYS' w prod.
Brak jitter/soft-TTL → synchroniczne przerwy i burze.
Jeden przykład dla wszystkich poleceń bez odłamków/replik.
Użyj Memcached do zadań wymagających atomowości/skryptów.
18) Lista kontrolna wdrażania (0-45 dni)
0-10 dni
Wybierz szablon (cache-aside + L1/L2), opisz klucze, TTL, obszary nazw.
Włącz jitter/soft-TTL, single flight; podstawowe alerty/deski rozdzielcze.
Dla Redis - konfiguracja ACL, tryb chroniony, slowlog, maxmemory-policy.
11-25 dni
Przełącz na shading (klaster Redis lub hash klienta), repliki.
Niepełnosprawność za pośrednictwem wersji pub/sub lub neimspace; outbox w bazie danych.
badania obciążenia „przekwalifikowania” pamięci podręcznej; ograniczenie pochodzenia.
26-45 dni
Autopromo/kanarka TTL, rozgrzewka przed zwolnieniem.
Strumienie do odpisu/reasekuracji tła.
Cotygodniowe raporty na temat wskaźnika trafień, najlepszych kluczy, kosztów pamięci.
19) Wskaźniki zapadalności
Współczynnik trafienia L2 ≥ 80% (dane statystyczne dotyczące tras/obszarów nazw).
P95 GET <2-3 ms (in-DC), brakuje <pochodzenia SLO.
0 burz w masowej niepełnosprawności (potwierdzonych testami).
Automatyczna niepełnosprawność i niymprzestrzeń wersioning.
Powielanie/replikacja obejmuje 1 awarię węzła bez znacznej degradacji.
20) Wniosek
Silna architektura pamięci podręcznej to dyscyplina kluczy i TTL, ochrona przed burzą, właściwa sztywność i przewidywalne uprzedzenie. Redis daje bogatą semantykę, trwałość i atomowość; Memcached - maksymalna prostota i prędkość. Dodaj obserwowalność, niepełnosprawność zdarzeń, L1 + L2, a pamięć podręczna staje się przyspieszeniem platformy, a nie źródłem przypadkowych kropli i „mistycznych” błędów.