Cache není spása výkonu Vaší aplikace

Jan Barášek
Nov 7 · 4 min read

Cache a proces cachování v širším kontextu vyjadřuje snahu o uložení těžko získaných dat někam stranou do rychle dostupného uložiště, z kterého můžeme odpověď příště načíst efektivně. Jako koncept to vypadá velmi dobře, ale lze jednoduše chybovat. Článek ukáže možnosti, jak o cachování přemýšlet a proč je naivní implementace špatně.

Cache jako řešení pomalého načítání webu

Pokud provozujete webovou aplikaci, kterou navštěvují byť jen desítky uživatelů za hodinu, časem zjistíte, že při naivní implementaci vnítřního backendu nebo databáze dochází k výkonnostním problémům a stránky se načítají pomalu. Rozumně navržený web by měl na request odpovědět do 200 ms, u složitějších dotazů (třeba filtrace produktů) zhruba do 750 ms. Pokud potřebujete více času, je vhodné zátěž rozložit a draze získaná data načíst ajaxem asynchronně.

Jak přemýšlet o cachování a její odpovědnosti

Jsem přesvědčen, že cache nemá být řešení pomalého načítání nebo odložiště pro zpracování konkrétní úlohy.

Pokud se naučíme psát aplikace velmi efektivně, aby se vyhodnocovaly rychle i bez použití cache, lze ušetřit mnoho výpočetního výkonu a ten investovat lépe.

Dobře navržená aplikace používá cache jen jako škálovací vrstvu, aby odolávala častému načítání stejných dat. Pokud jsou však požadavky na výpočet jiné, dokáže nová data rychle vyrobit a cache opět použije jen pro opakované načítání.

Výkonnostní peklo, když se cache používá jako řešení problémů s výkonem

Představte si jakoukoli netriviální webovou aplikaci, kde řešíme náročné získávání dat — třeba filtrace nad kategorií produktů, přičemž si vybereme hned několik omezujících filtrů a celý výsledek chceme ještě seřadit.

Jedná se už jenom z principu o velmi pomalou operaci, která zabere určitě mnoho sekund, pokud se implementuje špatně (naivně). Jednoduché a přímočaré řešení problému by bylo uložit jednou vyfiltrovaná data do cache, ale proč je to špatně?

  • Většinu dotazů budou uživatelé hledat jen jednou a cache nebude existovat (existují miliardy kombinací, jak může být filtr nastaven).
  • Data o produktech rychle stárnou a cache je potřeba invalidovat.
  • Při vyšší návštěvnosti může mít cache velmi rychle větší datový objem, než zdrojová data. Někdy i desetkrát víc. Důvodem je počet kombinací.

Reálný důsledek bude ten, že hlavní kategorie a časté filtry se budou načítat okamžitě (protože budou v cache), ale jakmile uživatel změní býť jediný filtr vůči výchozímu stavu, cache existovat nebude a bude se muset všechno pomalu sestavovat původním algoritmem.

A teď si představte, že filtrujete výsledky vyhledávání. Tam existuje kombinací téměř nekonečně (nekonečně mnoho dotazů vs. miliardy kombinací filtrů a řazení).

Řešením tohoto problému je ukládání dat do správné datové struktury, která umožňuje rychlé vyhledávání. Například filtry produktů a parametrů lze ukládat jako strom, případně použít objektovou databázi. Pokud je hledání určitého typu dotazu časté, je dobré data neukládat do cache, ale vymyslet vhodný index, který bude obsahovat vždy všechny možnosti, narozdíl od cache, která obsahuje jen data, která už někdo požadoval.

Největší problém cache je její invalidace

Představte si, že máte na hlavní stránce webu vypsány nejnovější články a u každého z nich počet komentářů a počet sdílení, které zjišťujete pomalu přes API z externího zdroje. Příklad na cachování jak dělaný.

Naivní představa zní, že jednou sestavíme seznam článků, pro každý si zjistíme přes API další data a výsledek uložíme do cache, který lze načíst téměř okamžitě.

Rozhodně by bylo chybou, kdyby se v případě vydání nového článku neaktualizoval přehled na hlavní straně, nebo kdyby se v případě zvýšení počtu komentářů neaktualizoval jejich počet.

Naivní řešení je uložit data na určitý časový interval a pak cache automaticky invalidovat (smazat). Při tomto přístupu bude aplikace reagovat většinou rychle, ale myslete i na případ, že cache ještě neexistuje a musí se teprve vygenerovat. V takovém případě si může uživatel počkat i několik sekund.

Správné řešení tohoto problému je žádnou cache nepoužít a data načítat pokaždé ze správné datové struktury. Mnohem lepší je data o článcích ukládat do databázové tabulky, která obsahuje index pro efektivní řazení a čtení, díky kterému získáme přehled článků tčeba za 1 ms. Navíc vždy aktuální. Tabulka bude zároveň sloužít jako takový malý “index” dat, protože bude obsahovat sloupec vyjadřující počet komentářů a počet sdílení. Data do tohoto sloupce může zapisovat například 10 minutový cron, který provede aktualizaci asynchronně bez zdržování uživatele. Druhé možné řešení je zapsat data do indexu při vytvoření článku, to ale zase zdrží administrátora. Asynchronní operace je pro tento případ nejlepší volba.

Cache s nekonečnou platností

Líbí se mi přístup, který používá jádro Nette pro řešení cachování DI kontejneru a Latte šablon. Cache se vytvoří pouze na začátku v prvním requestu a poté se už nikdy neinvaliduje. Zkrátka existuje pořád, dokud ji nesmaže deploy nové verze webu.

Pokud dokážete aplikaci navrhnout tak, že nebude spoléhat na data v cache, ale všechno načte nebo vytvoří vždy ze správné datové struktury, lze provozovat opravdu robustní a výkonnou aplikaci.

Vždy přemýšlejte nad tím, jak data uložit navždy.

Pokud se data mohou v čase změnit, vymyslete aktivní prvek, který bude datovou strukturu průběžně opravovat na pozadí. Získáte tím okamžitou odpověď aplikace, stále aktuální výsledky a nemusíte nárazově generovat obrovské množství dat, která se zobrazí často jen jednou.

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade