Čo je caching?
Caching znamená uloženie dát, ktoré budeme pravdepodobne potrebovať znova, do rýchlejšie dostupného úložiska.
Predstavme si napríklad e-commerce aplikáciu. Používateľ otvorí stránku produktu a aplikácia musí načítať jeho informácie z PostgreSQL databázy.
Ak tú istú stránku otvorí tisíc používateľov, databáza môže vykonať rovnakú alebo veľmi podobnú operáciu tisíckrát.
Ak sa údaje produktu medzi týmito požiadavkami nezmenili, nie je vždy potrebné získavať ich zakaždým nanovo.
Namiesto toho môžeme výsledok uložiť do cache:
Prvá požiadavka → databáza → výsledok → Redis
Ďalšie požiadavky potom môžu ísť:
Požiadavka → Redis → výsledok
Redis tak môže výrazne znížiť počet operácií, ktoré musí databáza spracovať.
Prečo databáza nemusí byť vždy bottleneck?
Keď je aplikácia pomalá, databáza býva jedným z prvých podozrivých miest.
Nie vždy je však problém v samotnej databáze.
Databáza môže byť dokonale schopná spracovať konkrétny query, ale problém vzniká vtedy, keď sa rovnaký query vykonáva príliš často.
Predstavme si dashboard, ktorý zobrazuje štatistiky za posledných 24 hodín. Ak sa tieto údaje menia iba každých päť minút, nemusí mať zmysel počítať ich nanovo pri každom otvorení stránky.
Cache nám umožní výsledok na určitý čas uchovať.
To môže znamenať menej databázových query, nižšiu záťaž servera a rýchlejšiu odozvu aplikácie.
Dôležité však je najprv zistiť, čo je skutočným bottleneckom. Cache nie je univerzálny nástroj na opravu pomalej aplikácie.
Redis vs. databáza
Redis aj PostgreSQL dokážu ukladať dáta, ale používajú sa na odlišné účely.
PostgreSQL je databáza, v ktorej chceme dáta dlhodobo a spoľahlivo uchovávať. Rieši transakcie, vzťahy medzi dátami, konzistenciu a komplexné query.
Redis je in-memory data store. Dáta drží primárne v operačnej pamäti, vďaka čomu k nim dokáže pristupovať veľmi rýchlo.
Redis preto typicky používame na dočasné alebo často používané dáta.
Napríklad:
- výsledky náročných query,
- session data,
- dočasné tokeny,
- rate limiting,
- počítadlá,
- výsledky API požiadaviek,
- dáta, ktoré sa často čítajú a menej často menia.
Redis však nemá automaticky nahradiť PostgreSQL.
V dobre navrhnutej aplikácii môžu fungovať spolu:
PostgreSQL = source of truth
Redis = rýchla vrstva medzi aplikáciou a databázou
Cache-Aside Pattern
Jedným z najbežnejších spôsobov práce s cache je cache-aside pattern.
Princíp je jednoduchý.
Aplikácia najskôr skontroluje Redis. Ak tam požadované dáta nájde, použije ich.
Ak nie, načíta ich z databázy a uloží výsledok do cache.
Proces vyzerá takto:
- Aplikácia potrebuje dáta.
↓
- Skontroluje Redis.
↓
- Dáta existujú?
Ak áno, aplikácia ich použije.
Ak nie, pokračuje:
↓
- Načíta dáta z PostgreSQL.
↓
- Uloží ich do Redis s nastaveným TTL.
↓
- Vráti ich používateľovi.
Prvý request môže byť preto o niečo pomalší, ale ďalšie požiadavky môžu dostať dáta priamo z cache.
Čo je TTL?
Pri cache je dôležitý pojem TTL – Time To Live.
Určuje, ako dlho bude konkrétna hodnota v cache platná.
Napríklad:
product:123 → TTL 5 minút
Po piatich minútach môže byť hodnota automaticky odstránená a pri ďalšej požiadavke sa znovu načíta z databázy.
TTL je jednoduchý spôsob, ako zabrániť tomu, aby aplikácia používala zastarané dáta príliš dlho.
Nie každé dáta však potrebujú rovnaké TTL.
Aktuálne štatistiky môžu mať cache na niekoľko sekúnd alebo minút, zatiaľ čo dáta, ktoré sa menia len zriedka, môžu byť uložené oveľa dlhšie.

Najťažšia časť? Invalidácia cache
Pri cache existuje známy problém:
There are only two hard things in Computer Science: cache invalidation and naming things.
Dôvod je jednoduchý.
Predstavme si, že produkt stojí 50 €. Túto informáciu uložíme do Redis.
Neskôr zmeníme cenu v PostgreSQL na 45 €.
Ak cache neaktualizujeme alebo neodstránime, aplikácia môže používateľovi stále zobrazovať 50 €.
Cache teda prináša rýchlosť, ale zároveň ďalšiu vrstvu, ktorú musíme správne synchronizovať.
Existuje niekoľko spôsobov, ako to riešiť.
Pri zmene dát môžeme príslušný cache key okamžite odstrániť. Ďalšia požiadavka potom načíta aktuálne údaje z databázy.
Ďalšou možnosťou je aktualizovať cache spolu s databázou.
Pri jednoduchých prípadoch môže byť najpraktickejšie použiť TTL a akceptovať krátke obdobie, počas ktorého môže cache obsahovať staršiu hodnotu.
Správna stratégia závisí od toho, ako kritická je aktuálnosť konkrétnych dát.
Čo sa môže pokaziť?
Cache môže aplikáciu výrazne zrýchliť, ale nesprávne použitá cache môže vytvoriť nové problémy.
Stale data
Najčastejší problém. Používateľ dostane staršiu verziu dát, pretože cache nebola správne invalidovaná.
Cache stampede
Ak cache hodnota naraz expirovala a veľké množstvo používateľov si ju vyžiada v rovnakom okamihu, všetky requesty môžu naraz smerovať do databázy.
Namiesto odľahčenia databázy tak vznikne krátkodobý nápor.
Príliš veľa dát
Redis používa operačnú pamäť, ktorá nie je neobmedzená. Ukladať do cache všetko preto nie je dobrá stratégia.
Komplikovanejší systém
Každá ďalšia infraštruktúrna vrstva znamená ďalšiu vec, ktorú treba monitorovať, konfigurovať a udržiavať.
Ak aplikácia Redis nepotrebuje, jeho pridanie môže byť skôr komplikáciou než optimalizáciou.
Kedy Redis nepoužívať?
Nie každá aplikácia potrebuje Redis.
Ak máte jednoduchú aplikáciu s malým počtom používateľov a databáza bez problémov zvláda aktuálnu záťaž, pridanie cache nemusí priniesť dostatočný benefit.
Redis tiež nie je riešením pre každý pomalý query.
Ak je problémom napríklad chýbajúci index alebo neefektívne napísaný SQL dotaz, správnym riešením môže byť optimalizácia databázy, nie pridanie cache.
Rovnako nie je vhodné cacheovať dáta, ktoré sa musia zobrazovať vždy v reálnom čase a pri ktorých by aj krátke oneskorenie mohlo spôsobiť problém.
Najprv preto treba merať:
Kde aplikácia trávi čas? Ako často sa rovnaké dáta načítavajú? Ako často sa menia? A akú úroveň aktuálnosti používateľ skutočne potrebuje?
Až potom má zmysel rozhodovať, či je cache správnym riešením.
Redis + Django + PostgreSQL
Redis sa veľmi dobre hodí do aplikácií postavených na Django a PostgreSQL.
Django poskytuje cache framework, ktorý umožňuje aplikácii pracovať s rôznymi cache backendmi bez toho, aby bola celá logika aplikácie pevne naviazaná na jeden konkrétny systém.
V praxi tak môže architektúra vyzerať približne:
Django → Redis → PostgreSQL
Django prijme request, skontroluje cache a ak požadované dáta nie sú dostupné, načíta ich z PostgreSQL a uloží výsledok do Redis.
Takýto prístup môže byť veľmi efektívny pri aplikáciách, kde sa niektoré dáta čítajú výrazne častejšie, než sa menia.
Cache nie je náhrada za dobrú architektúru
Redis dokáže byť veľmi užitočný nástroj, ale nemal by byť prvou odpoveďou na každú výkonnostnú otázku.
Dobrá optimalizácia začína meraním.
Najprv treba pochopiť, kde vzniká bottleneck. Potom môže prísť optimalizácia query, indexov, aplikačnej logiky alebo architektúry.
A až keď dáva zmysel znížiť počet opakovaných operácií, môže byť cache veľmi efektívnym riešením.
Redis nie je kúzelná skratka. Je to ďalšia vrstva, ktorá pri správnom použití dokáže výrazne zrýchliť aplikáciu a odbremeniť databázu.
Najdôležitejšia otázka preto nie je:
„Mali by sme používať Redis?“
Ale:
„Ktoré dáta sa oplatí načítať raz a použiť ich viackrát?“