Strategie cache
Cache-Aside, Write-Through, Redis eviction policies, multi-level CDN+Redis+aplikacja i cache invalidation — jak zbudować efektywną warstwę cache.
6 wzorców cache
Każdy wzorzec optymalizuje inny aspekt — spójność, latencję zapisu, latencję odczytu lub zużycie pamięci.
| Wzorzec | Kiedy | Spójność | Write latencja | Read latencja | Ryzyko |
|---|---|---|---|---|---|
| Cache-Aside | Ogólne użycie, read-heavy | Eventual | Normalna | Miss = 3 ops | Stale data, stampede |
| Write-Through | Wymagana spójność | Silna | Wyższa (2 ops) | Niska (hit) | Nadmiarowe dane w cache |
| Read-Through | Transparentny cache layer | Eventual | Normalna | Miss = transparentne | Vendor lock-in (DAX) |
| Write-Behind | Write-heavy, batch DB | Eventual (ryzyko utraty) | Najniższa | Niska (hit) | Data loss przy crash |
| Write-Around | Rzadko czytane po write | Silna (DB source of truth) | Normalna | Miss = wyższa | Cold cache po write |
| Refresh-Ahead | Predictable access patterns | Silna (proaktywna) | Normalna | Zawsze hit | Zbędne odświeżanie |
Często zadawane pytania
Jakie są strategie cache i kiedy stosować Cache-Aside vs Write-Through?
Cache-Aside (Lazy Loading): aplikacja najpierw sprawdza cache. Cache miss -> aplikacja czyta z DB, zapisuje do cache, zwraca dane. Cache hit -> zwraca dane z cache. Zalety: tylko potrzebne dane w cache. Odporny na awarie cache (fallback do DB). Wady: cache miss = 3 operacje (cache read, DB read, cache write). Stale data przy concurrent updates. Write-Through: przy każdym write do DB -> jednocześnie update cache. Gwarancja spójności cache i DB. Zalety: cache zawsze aktualny. Zero stale data. Wady: write latencja wyższa (dwie operacje). Dane w cache które nigdy nie są czytane. Read-Through: cache layer pośredniczy. Aplikacja pyta cache, cache pobiera z DB jeśli brak. Transparentne dla aplikacji. Używają: AWS DAX (DynamoDB), Redis Enterprise. Write-Behind (Write-Back): zapis do cache, asynchronicznie do DB. Najwyższa write performance. Ryzyko: dane zgubione przy crash cache przed write do DB. Write-Around: bezpośredni write do DB, pominięcie cache. Cache trafia tylko przy read. Dla write-heavy danych które rzadko czytane. Refresh-Ahead: cache odświeża dane zanim TTL wygaśnie. Predykcja co będzie potrzebne. Netflix używa dla film metadata.
Cache invalidation — najtrudniejszy problem w informatyce?
Phil Karlton: 'There are only two hard things in Computer Science: cache invalidation and naming things.' Strategie invalidacji: TTL (Time-To-Live): najprostsza. Cache entry wygasa po N sekund. Wada: stale data przez cały TTL. Dobra dla: statyczne dane, tolerancja stale data. Event-Based Invalidation: przy update DB -> wyślij event -> invalidate cache keys. Np. OrderUpdated event -> del cache:order:{id}. Bardziej aktualne dane, wyższa złożoność. Versioned Cache Keys: klucz zawiera wersję (user:123:v5). Przy update -> inkrementuj wersję. Stare klucze automatycznie wygasają przez TTL. Cache Stampede (Thundering Herd): problem gdy TTL wygasa dla popularnego klucza. Setki requestów jednocześnie na DB. Rozwiązania: Mutex Lock — tylko jeden request odświeża, reszta czeka. Probabilistic Early Expiration — losowe odświeżanie przed TTL. Stale-While-Revalidate — zwróć stale data, odświeżaj w tle. Cache rzadko = prawidłowo: cache powinien być warstwą optymalizacji, nie wymaganiem. Jeśli cache down -> aplikacja działa wolniej ale działa. Distributed Cache Invalidation: multi-region invalidacja. Redis pub/sub do powiadamiania innych node. Cache coherency problem.
Multi-level caching — CDN, Nginx, Redis, aplikacja, DB?
Hierarchia cache (od najszybszego do najwolniejszego): L1 — In-process cache (aplikacja): HashMap/ConcurrentHashMap. Caffeine (Java) — high-performance local cache z LRU/LFU. Node.js memory cache. Najszybszy (ns latencja), najmniejszy, per-instancja. L2 — Distributed cache: Redis, Memcached. Wspólny dla wszystkich instancji aplikacji. ms latencja, większy, współdzielony. L3 — HTTP cache (Nginx/Varnish/CDN proxy): Cache-Control headers, Vary headers. Nginx proxy_cache. Sub-ms do ms latencja, duży. L4 — CDN (Edge cache): Cloudflare, AWS CloudFront, Fastly. Geograficznie bliski użytkownikowi. ms latencja, ogromny, globalny. L5 — DB cache (query cache, buffer pool): PostgreSQL shared_buffers. MySQL InnoDB buffer pool. Read replicas jako cache. Cache-Control headers dla CDN: max-age=3600 — cache 1 godzinę. s-maxage=86400 — CDN cache 24h (nadpisuje max-age dla shared caches). public — można cachować przez CDN. private — tylko przeglądarka. no-cache — revalidate przed użyciem. no-store — nie cachuj. stale-while-revalidate=60 — użyj stale przez 60s podczas odświeżania.
Redis jako cache — wzorce i best practices?
Redis Data Structures dla cache: String: prosty key-value. SET user:123 '{json}' EX 3600. Hash: pola użytkownika jako hash. HSET user:123 name 'Jan' age 30. Efektywne dla partial updates. List: kolejka, session history. Set: unikalne wartości (np. visited pages). Sorted Set: leaderboard, rate limiting (sliding window). Redis pipelining: wysyłaj wiele komend bez czekania na odpowiedź każdej. PIPELINE [SET, GET, SET] w jednym round-trip. Lua scripting: atomowe operacje złożone z wielu komend. Check-and-set bez race condition. Redis Cluster: automatyczny sharding. 16384 hash slots. Każdy node obsługuje część slotów. Horizontal scaling. Redis Sentinel: wysokie dostępność dla single shard. Automatyczny failover. Cache Eviction Policies: noeviction — błąd przy braku miejsca. allkeys-lru — wyrzuć najmniej ostatnio używane. allkeys-lfu — wyrzuć najmniej używane (frequency-based). volatile-lru — LRU tylko dla kluczy z TTL. allkeys-random — losowe. Dla cache: allkeys-lru lub allkeys-lfu. Memory optimization: maxmemory 4gb. maxmemory-policy allkeys-lfu. Kompresja JSON w cache (msgpack, brotli). Key naming: namespace:entity:id (user:profile:123). Monitoring: hit rate (cel 80-95%). Eviction rate. Memory fragmentation.
Jak mierzyć efektywność cache i optymalizować hit rate?
Kluczowe metryki cache: Cache Hit Rate = hits / (hits + misses). Cel: 80-95% dla production. Poniżej 80% -> problem. Eviction Rate: czy cache wyrzuca dane przed TTL? Jeśli tak -> za mały cache lub za długi TTL. Miss Latency: latencja cache miss -> DB. Porównanie z latencją bez cache. Mierzenie Redis: redis-cli INFO stats. keyspace_hits, keyspace_misses. hit rate = keyspace_hits / (keyspace_hits + keyspace_misses). Narzędzia: RedisInsight (GUI). Prometheus redis_exporter. Grafana dashboard. Optymalizacja hit rate: TTL tuning: zbyt krótki TTL = dużo miss. Zbyt długi = stale data i duże zużycie pamięci. Analiza access patterns (jakie klucze są miss-owane). Prefetching: ładuj dane do cache zanim użytkownik ich potrzebuje. Warm-up cache po deploymencie. Cache Warming: przy deploymencie -> pre-load popular data do cache. AWS ElastiCache: Global Datastore (multi-region). Cluster Mode. Backup i restore. Memcached vs Redis: Memcached — prosty, wielowątkowy, tylko string, brak persistence. Redis — więcej struktur danych, single-threaded (Redis 6+ multi-threaded dla IO), persistence, pub/sub, streams. Wybór: Redis prawie zawsze lepszy dla nowych projektów.
Powiązane artykuły
Skontaktuj się z nami
Porozmawiajmy o Twoim projekcie. Bezpłatna wycena w ciągu 24 godzin.
Wyślij zapytanie
Telefon
+48 790 814 814
Pon-Pt: 9:00 - 18:00
adam@fotz.pl
Odpowiadamy w ciągu 24h
Adres
Plac Wolności 16
61-739 Poznań
Godziny pracy
Wolisz porozmawiać?
Zadzwoń teraz i porozmawiaj z naszym specjalistą o Twoim projekcie.
Zadzwoń teraz