Ugrás a főmenüre.
Web 2008.06.16.

Caching

A számítástechnikában semmi sem az, aminek látszik. Ennek egyik oka a caching, azaz átmeneti tár, ami szinte mindenhol jelen van és nagyon fontos. Például ha nem lenne a géped processzorában, akkor a teljesítménye a századára/ezredére esne vissza és csak poháralátétnek lenne jó.
Megpróbálom laikusok számára is érthető módon elmagyarázni, hogy mi ez és hogyan használjuk a weben - egy újabb tudományos-ismeretterjesztő fantasztikum a Szantog blogon! (A caching nem egyenlő cashing.)
Caching

A cache arra való, hogy amit már egyszer kiszámoltunk/elkészítettünk, ne kelljen mégegyszer. Egyszerű példával: ha megkéred a gépedet, hogy számolja ki mennyi 30x5, akkor nem áll neki egyből kiszámolni, hanem megnézi, hogy megvan-e neki már ez az eredmény. Ha megvan, akkor nem fog számolgatni és így teljesítményt spórol.

Ez nagyobb blokkokban is működik: lehet olyat, hogyha a gép már "kiszámolt", azaz elkészített egy weboldalt, akkor az újabb és újabb kérések esetén nem fogja ismét elkészíteni, csak a már eltárolt eredményt küldi ki.

Persze a világ összes tárhelye sem lenne elég egy átmeneti tárhoz, olyan sokféle eredmény lehetséges. Az átmeneti tárból a legkevésbé használt dolgok automatikusan törlésre kerülnek és ha mégis szükség lenne rájuk, ismét ki kell számolni őket. A cache tárhely gazdálkodása ezért nagyon fontos és roppant ügyes algoritmusokat találnak ki, hogy a lehető legnagyobb legyen a cache találati aránya, azaz amikor nem kell dolgozni hanem benne van a kért eredmény.

A cache másik jellemzője még, hogy általában több rétegű. Ahogy az életben más területekre is jellemző, semmi sincs ingyér: a gyors és fürge dolgokban lévő cache-eknek kicsi, a lassabb dolgokban lévőknek nagyobb a tárhelyük.

Ez még a gépedben lévő processzorban is jelen van. Egy mai darabban kétrétegű a cache tár, nézzük hát az elterjedt Intel Core 2 Duo-t példának:

  1. A legbelső cache jelzése L1 (Level 1), ez a processzor belső magjának a része, annak sebességével fut, viszont összesen csak 64kb (kilobájt) méretű. Cserébe kettő van belőle, mert a Core 2 Duo azért duó, hogy két magja legyen.
  2. Kijjebb van az L2 (Level 2) cache, ez sokkal lassabb (kábé tízszer-százszor), de típustól függően 2 vagy 4mb (megabájt) méretű, azaz sokkal nagyobb és a két mag egyszerre osztozik rajta.

Vannak háromszintű cache-tárral szerelt processzorok is. Az ügyes cache-tár szervezés és logika fontosabb és több teljesítményt hoz, mint a márketingnek jobban fekvő gigahertz hajhászás. Többek között ennek köszönhető, ha az ugyanannyi (vagy kevesebb!) gigahertzes proci mégis gyorsabb.

Cache a weben

Alapvetően ezekkel érdemes webes területen foglalkozni: opcode-cache, http (böngésző) cache, lokális, többszintű és elosztott cache.

Opcode-cache

Egy webes alkalmazás általában szkriptekkel íródik. Futtatáskor (tehát pl. amikor lekérsz egy weboldalt) ezeket a szkripteket először le kell fordítani a gép nyelvére, az egyszerűség kedvéért nevezzük ezt most gépi kódnak (a valóságban ez bonyolultabb és sokszor szintén többszintű). A gép a gépi kódot "érti", azt tudja végrehajtani és az eredmény egy weblap, amit megkapsz.

Az opcode-cache ezt a folyamatot rövidíti le azzal, hogy a már egyszer elkészített gépi kódokat tárolja és nem kell minden egyes kéréskor újra meg újra előállítani azokat. Ezek a kódok úgyis csak akkor változnak, ha módosítják a szkripteket, azaz borzasztó ritkán.

Az opcode-cache telepítése minden szerverre ajánlott, mert nagyon kevés erőforrást foglal (RAM-ból se kell több néhány megabájtnál) és kb. kétszer gyorsabb lesz tőle minden, vagy ha megfordítjuk, a szerver kétszer több látogatóval fog megbírkózni.

PHP-nál ajánlom az APC-t vagy az XCache-t, mindkettő teljesen stabil free/open source megoldás, viszonylag egyszerűen telepíthető és egyben a lokális cache-re is megoldást ad.

Lokális cache

Ha valamilyen adatra többször van szükséged a szkripted futása során, akkor azt általában eltárolod egy adattömbben, azaz a memóriában. Most lefektetünk egy viszonyítási alapot, legyen ennek a sebessége 1000. Ha végigfut a szkripted, akkor ez az adat elvész, egy újabb futásban esetleg ismét elő kell állítani.

Erre a problémára kínál megoldást a lokális cache, ami egy olyan RAM-ban (memóriában) tárolási megoldás, aminek a tartalma mindig elérhető, akármennyi példányban és akármikor fut a szkript. Gyakorlatilag egy közös memóriatár, viszont lassabb a sebessége, csak kb. 268.

Megjegyzés

Vedd észre, hogy a cache-ben nem csak "szimpla" adatok tárolása lehetséges, komplett weboldalakat is simán tolhatsz bele! Úgy érdemes "cache-elni", hogy egy-egy nagyobb blokkot, netán komplett oldalt tárolsz. Bonyolultabb rendszereknél egy oldal kiszolgálásához akár 5-8 cache kérés is tartozhat, de ez még normális és ami még fontosabb, skálázódik. Egy jó rendszer még így is a századára csökkenti a szerver(farm) terhelését, ugye nagyon nem mindegy?

Elosztott cache

Oké, a szerveren van lokális cache, de mi van, ha több szerverünk van, mert egy már nem bírná a terhelést? Erre való az elosztott cache, ami pont ugyanolyan, mint a lokális, de a tartalma elérhető az összes szerverről. Olyan, mint egy nagy "felhő", amibe fellövöd az adatot.

Az elosztott cache a legfontosabb fegyverünk az adatbázis-kezelő olvasási oldalának (SELECT) tehermentesítésében. Bár alig 10-20%-kal gyorsabb egy gyors MySQL adatbázis-kezelőnél, viszont sokkal egyszerűbb skálázni (azaz újabb és újabb elosztott cache szervereket indítani), mint MySQL replikációkkal bajlódni.

Ennek a sebessége mindössze 33, míg egy gyors MySQL lekérdezés általában 14-20, hogy legyen viszonyítási alap (query cache-t most hagyjuk, nagyobb rendszereknél nem pálya). Messze a leghíresebb, legtöbbet használt és legjobb elosztott cache a Memcached, ráadásul tök free.

Humorous Pictures

Többszintű cache a weben

Mivel látszik a fentieknél, hogy a mérettel és az elérhetőséggel fordítottan arányos a sebesség, ezért célszerű a többszintű cache-rendszer kialakítása. Magyarul írnod kell egy olyan cache osztályt, ami először a lokális, aztán pedig az elosztott cache-ből kérdez, illetve elvégzi a cache szintek frissítését.

Pölö ha valami nincs meg a lokálisban csak az elosztottban, akkor az elosztottból történő olvasás után egyből be kell tolni a lokálisba a zadatot, hogy a következő olvasáskor már onnan legyen találat. A jól kialakított cache rendszer borzasztóan lecsökkenti az adatbázisból történő olvasást, sokszor egyenesen nullára.

Lemezes cache

Úgy korrekt, ha megemlítem ezt is: a tárolni kívánt izét elmentjük egy fájlba és onnan olvasgatjuk be. A trükk az, hogy az operációs rendszerek csalnak, a gyakran használt fájlokat betöltik a memóriába, így ennek a megoldásnak a sebessége 74. Hátránya, hogy nem olyan egyszerű használni és gond a konkurens (közel egy időben történő) írás.

HTTP (böngésző) cache

Kicsit mostohagyerek ügy, különösen a mai webkettes alkalmazások világában. Ugyanis alapértelmezettként érdemes kikapcsolni, azaz olyan fejléceket (header) küldünk ki a nagyvilágba, hogy a tartalmunk egyből elévül, még a böngésző "vissza" gombja esetén is újra kell kérni, majd cache-elünk mi a szerveren. Így egyszerűbb az élet, pláne a hibakeresés.

Látogatottabb oldalaknál, pl. egy címlapon azért érdemes pár másodpercre, netán (forradalmi gondolat!) fél percre is beállítani, meg lehet vele spórolni néhány százalék teljesítményt.

A többi (lokális, elosztott) cache-re is igaz, hogy akár néhány másodpercre is érdemes tárolgatni, tehát akkor is, ha tudjuk, hogy az adat 5 másodperc múlva elévül. Miért? Mert egy számítógép belső dolgai szerint ez már rettentő hosszúságú idő, ennyi alatt akár 500 oldalt is kiszolgálhat!

Mese

Felhő mondta nekem, hogy a Ustream főoldalát 3 másodpercig cache-elik és megéri. A Webcsatornánál egy video adatfolyamot 20 másodpercig cache-elünk. Ennek annyi a hátulütője, hogyha pont abban a néhány másodpercben történik valami, például leállítanak egy Ustream főoldalról linkelt adást, akkor a ráklikkelő látogató már csak a nagy semmit fogja látni. Ez egy kompromisszum, amit fel kell vállalni a teljesítmény miatt és úgy állítunk be, hogy a bekövetkezési esélye minimális legyen.

Ez az egyik oka annak is, hogyha mondjuk az Index címlapon kattintasz egy cikkre, néha a "nem találom", vagy csak egy szimpla fehér oldalra jutsz. A szerkesztők néha pont a te látogatásod ideje alatt változtatják meg a cikk linkjét, de ez a cache miatt még "nem szivárog fel".

Spoiler: én háromszintű cache osztályt írtam PHP-ban, majd írok róla bővebben és lehet, hogy ki is adom a forrást, mert tud egy-két különleges dolgot.

5 hozzászólás

  1. idézem 2008.06.16. 10:05
    • adobi
    vagany iras! varom a folytatast, foleg a php-s megvalositast :)
  2. idézem 2008.06.17. 07:46
    • kacsandiz
    énisénis
  3. idézem 2008.06.17. 13:23
    Jó kis post, de azért lenne pár észrevétel. :)


    Opcode cache: itt nincs szó gépi kódról. A PHP kód lefordul egy byte kódra, amik már azok az elemi utasítások (opcode), amit a PHP motor végre tud hajtani.


    A kétszeres sebességnövekedésnél jóval több is lehet. Alap esetben az opcode cache nézegeti, hogy megváltozott-e a PHP fájl, de pl. APC-nél ez kikapcsolható (érdemes is), ezzel elég komoly növekedés érhető el. Szintén nem mindegy, hogy milyen lockolási stratégia van használatban, itt is elég komoly különbségek lehetnek. Érdemes a facebook féle APC slide-okat végiglapozni.


    Bár konkrét tapasztalatom nincs (rendszergazdai dolgok nem az én asztalom), de ezzel együtt az APC-t javaslom egyértelműen. A nagyok (facebook, yahoo) ezt használja, és érdemes megnézni, hogy kik fejlesztik.


    1000 vs 268: Ejnye Ottó, cheatelsz egy kicsit, illett volna egy forrás megjelölés. ;)


    MySQL vs Memcahce: nyilván függhet sok mindentől is, de én azt tapasztaltam, hogy ennél jóval magasabb a különbség, simán nagyságrendi. Ha belegondolsz azért még egy nagyon egyszerű query esetén is lényegesen bonyolultabb a "protokoll", mint a Memcache.


    Kifejezetten session kezelésre még érdekes lehet ez a cucc is: thethoughtlab.blogspot.com/2007/01/session-management-with-phpdance.html (nem használtam még).


    Ezzel az automatikus 3 szintű cache-sel nem értek teljesen egyet. Van egy komoly különbség mondjuk egy APC cache és egy Memcache között: az utóbbi LRU, míg az előbbi nem. Ezért nem teheted meg, hogy csak úgy zúzod bele az APC-be dolgokat, főleg abban az esetben ahol behoztad az elosztott cache-t: amikor már nem fér el az cache-elendő adat egy szerver memóriájában. Memcahe esetén az LRU miatt ezzel nem kell törődnöd, ha megtelet, akkor szépen kidobálja a már nem használt dolgokat.

    Szintén nem szerencsés ez az automatizmus pl. a cache invalidálása miatt. Ez simán bonyolultabb pl. APC esetében, míg Memcahcenél ismét csak ki lehet használni, hogy a régi cuccok egyszerűen kiesnek, és a kulccsal történő játékkal automatikusan invalidálódhat egy adott cache.

    Szóval szerintem más jellegű adatokat érdemes tárolni a kettőben, ritkán lehet arra szükség, hogy csak "bután" másoljon az ember egyikből a másikba (persze lehet ilyen, de nem alap pattern), és még egy gondolat ehhez: a memcache jóval nagyobb funkcionalitással bír (pl. számláló atomi növelés, csökkentése stb.).


    Fájl cache: azért szerintem itt az 1000 az nagyon ritkán ezer, átlagosan lényegesen rosszabb a teljesítménye. Itt inkább megint arról van szó, hogy szituációtól függ, hogy mikor érdemes ilyet használni. Ha kifejezetten cache-ről van szó, akkor az írás nem olyan nagy probléma: mindegyik szál először egy egyedi nevű (timestamp+pid) átmeneti fájlba ír, majd átnevezi a végleges névre, és ez utóbbi művelet már atomi lesz, és az OS (windows alatt nem) megoldja a sorbarendezést.


    Üdv,
    Felhő
  4. idézem 2008.06.17. 15:32
    • ee
    És ne feledkezzünk meg arról, hogy ez még nem a teljes világ, pl. Java-t használva a felállás azért elég különböző. Okosan használva azért lehet gyorsabb is bizonyos helyzetekben..

    A böngésző cache kikapcsolás alapból meg nem biztos, hogy mindig a legokosabb. A GWT pl. azt csinálja, hogy van egy nagyon kicsit loader HTML oldal, ami no-cache, és betölti a nagy batár JS-eket. A JS-ek neve viszont fordításonként változik (GWT-ben Java-ból generáljuk a JS kódot). A loader mindig tudja kit kell betölteni, viszont ha nincs új fordítás, akkor a nagy batár JS-eket nem tölti le újra.
  5. idézem 2008.06.17. 23:13
    @Felhő Kösz a konstruktívat, így összeállhat egy jó kis tudásbázis.

    Az opcode cache-nél említettem, hogy a valóságban ez bonyolultabb és most csak egyszerűsítek, mert ez egy tudományos-fantasztikus ismeretterjesztő, fejeket irányba fordító bejegyzés. :-)

    Én személy szerint opcode cache-sel sohasem mértem kétszeresnél nagyobb gyorsulást.

    Forrásmegjelölés. A személyes fejlesztői iMac-emen becsülettel kimértem én is a klasszikus microtime PHP-s kalapáccsal, tök hasonlókat.

    Az APC-nél nincs LRU? Nem találok semmi infót erről a weben, lehet, hogy bénán keresek. Ha nincs, az gáz, meg tudod erősíteni? Az APC és az XCache is rendelkezik állítható garbage collection-nel, ami úgy tudom, hogy többek között LRU elven is töröl, ha túlfutnál a beállított memória limiten.

    Az APC-ben tényleg nincs számláló növelés/csökkentés, de egyébként a többit tudja. Az XCache-ben (én azt használom leginkább) viszont van és tényleg mindent tud. Mellesleg ezt a számlálós dolgot nem használom, mást eszeltem ki, majd írok arról, volt spoiler.

    Fájl cache: hehe, bentmaradt egy ezres... mikor írtam a dolgot a számok helyére 1000-et tettem és később helyettesítettem be, ez kimaradt. A helyes érték 74.

    Statikus objektumoknál, pl. az említett JS-eknél a http cache-t nem szoktuk alapból kikapcsolni, ez igaz.
Új hozzászólás
A sortörések automatikusak. Csak az üzenet kitöltése kötelező, a többi mező opcionális. A megadott e-mail címet nem tesszük közzé. Engedélyezett HTML tagek: p, a, strong, em, blockquote, ul, ol, li, dl, dt, dd.

Legutolsó hozzászólások

Veoh.com: szánalmas!: zola2000: Megtaláltam a legegyszerűbb megoldást veohra: használjatok operát, és kapcsoljátok be az opera turbot, ekkor az opera norvégiai jön be a...

Végre IKEA!: Ági: Heló bárkinek, aki idetéved! A weboldalunk domain-je - a kedvenc áruházunk ügyvédjének nyumására :) - megváltozott: Az új cím: is...

DJ PLAYER Blue Edition: Gábor: Ja, és természetesen megy iPad-en is, hiszen _minden_ iOS app megy iPad-en.

DJ PLAYER Blue Edition: Gábor: Bug report-okat itt fogadunk: http://djplayer.net/page/bug_report_fixes

DJ PLAYER Blue Edition: hohand: Hello!A dj player mukodik iPad-on is?Tegnap feltettem, wifi-n athuztam ra zeneket,de amikor ranyomtam egy zeneszamra,error-t dobott es valami is!...

iMect means internet, media and other cool things. We're a small company located in Hungary. There is a big footer on every page where you can discover what we do and what happens with us.

Az iMect jelentése: internet, média és egyéb király dolgok. Egy kis magyar cég vagyunk. Minden oldalon van egy nagy lábléc, ahol felfedezheted, hogy mivel foglalkozunk.