Innonic – Nemzetközi Sikertörténeteket Építünk

Hogyan cacheljünk akár 84%-kal hatékonyabban?

hogyan cacheljünk hatékonyabban
Azt hiszem az senki számára nem kérdés, hogy miért érdemes cachelni. Egyrészt a gyorsabb betöltési sebesség kevesebb szerverterheléshez vezet. Kevesebb szerverterhelés pedig kevesebb szerver költséget jelent. Másrészt a felhasználói élményt is javítjuk a gyorsabb betöltéssel. Így az üzemeltető és a látogató is elégedett lesz.

Ebben a cikkben olyan praktikákat mutatok be, amellyel nem csak hatékonyabb lesz a cachelésünk, de még a szerverköltségeken is spórolhatunk. Olvass tovább!

Mit cacheljünk?

Ez nyilván nagyban függ az adott weboldal felépítésétől és tartalmától, azonban általánosságban mégis elmondható, hogy mindig arra törekszünk, hogy a teljesítmény- vagy időigényes tartalom megjelenéseket szeretjük cachebe elrakni. Azaz minél kevesebb adatbázis lekérdezéssel és tartalom generálással kelljen küzdeni a szervereinknek. Meg kell próbálnunk ezeket a kódrészeket valamilyen cachelési technikával kiváltani. Általános elv az, hogy ha a lekérés paraméterei nem változnak, akkor arra az adott lekérésre mindig ugyanaz lesz a válasz, így elegendő ha egy cachelt statikus tartalmat adunk válaszul, nem kell minden alkalommal végrehajtanunk a konkrét kérést. Két fő irányunk lehet, hogy mely kéréseket cacheljük:



Hogyan cacheljünk?

A cél az, hogy minél több előre eltárolt tartalmunk legyen. Na de hol és hogyan tároljuk ezeket a statikus tartalmakat? Talán ez a legfontosabb kérdés ugyanis maga a cache elérése és tárolása meghatározza, hogy egyáltalán van-e értelme cachelni. A cachelt tartalmat gyorsabban kellene elérnünk, mintha az eredeti kérést szolgálnánk ki. Rengeteg módszer van cache tárolásra, nézzünk meg pár példát.



Hogyan cacheljünk hatékonyan?

El is érkeztünk a kulcs kérdéshez. Van egy nagyon gyors elérésű cache tárolónk, teljesen elégedettek vagyunk vele. Viszont a ShopRenternél közel 3000 áruház cachét kell tárolnunk. Egy 16GB memóriával rendelkező Redis szervert használunk. Bizony kezdtük elérni a memória limitet. Ekkor jött az ötlet, mi lenne ha tömörítenénk a cachet? A PHP-ban vannak beépített tömörítő függvények. Mivel futási időben fogunk be- és kitömöríteni, nagyon nem mindegy, hogy ez mennyi időt vesz igénybe, hiszen ha túl sok a tömörítési idő akkor nem nyerünk semmit a cacheléssel. A tömörítési algoritmusoknál megválaszthatjuk a tömörítés szintjét. Minél magasabb a szint annál kisebb tömörített fájlt kapunk, viszont annál több ideig dolgozik az algoritmus. Ezért egy pár tesztet érdemes futtatni mielőtt kiválasztjuk a kívánt tömörítési algoritmust és a tömörítés szintjét. Két népszerűt hasonlítsunk össze a bzcompress és gzcompress-t.



500 be- és kitömörítés idejét láthatjuk 30 KB-os fájlok esetén. Az időt másodperceben mértük. A vízszintes tengelyen a gzcompress majd a bzcompress idei szerepelnek. A piros görbe a becsomagolást, a zöld pedig a kicsomagolást jelzi. Átlagban a gzcompress 500ms alatt tömörít és 200ms kell a kitömörítéshez. Míg a bzcompress majdnem 3000ms alatt tömörít és 600ms alatt kitömörít. Tehát a gzcompress betömörítés esetén hatszor gyorsabb, kitömörítés esetén pedig háromszor gyorsabb. Futási időben eddig a gzcompress bizonyul jobbnak.



A fenti diagramon a vízszintes tengelyen ismét előbb a gzcompress méréseit láthatjuk, aztán a bzcompresst. Százalékosan mértük, hogy mennyivel lesz kisebb a tömörített fájl, az eredeti fájlhoz képest. Láthatjuk, hogy gzcompress level 6 felett már nem sokkal fog csökkenni a fájl mérete. A bzcompress esetén pedig mintha nem is számítana, hogy milyen szinten tömörítünk. Így a futási időt és az elérhető fájlméretet figyelembe véve a gzcompress-re esett a választásunk.

A gzcompress neve félrevezető lehet, a ZLIB tömörítési szabványt használja, nem pedig a gzip-et. A készítők a 6 szintű tömörítést ajánlják, de gyakorlatilag ez olvasható ki a diagrammokból is, így mi is ezt választottuk. Az előzetes számítások szerint a tömörítési arány miatt 84%-kal kisebb cache méreteink lesznek. Azaz a jelenlegi 13GB memória helyett csupán 2GB memóriát fogunk felhasználni. http://php.net/manual/en/function.gzcompress.php

Új cachelés élesítésének tapasztalatai

Miután élesítettük a fejlesztésünket, azt tapasztaltuk, hogy nemhogy a Redis memóriánk felszabadult, de network-ben is rengeteget nyertünk.



Közel negyedére esett vissza a hálózati forgalom a szervereinken. Nyilván köszönhetően annak, hogy kisebb méretű cache-t kell letölteni, tehát azt a picit, amit órajelben elvesztünk a tömörítés miatt gyakorlatilag kamatostul megtérül a hálózati forgalomban. Igazából, nemhogy megtérül, bőven nyerünk vele. A fenti ábra elég szignifikánsan szemlélteti.



Amikor élesítettük a fejlesztést, a fenti ábrán látható, hogy a szabad memória szinte nulla volt, így swapolt a Redis, ami eléggé csökkenti a hatékonyságát. Amint élesítettük a fejlesztést, a képen az látható, hogy 16GB szabad RAM elkezdett csökkeni. Sajnos arról már nincs diagram, de 13+ GB-ról 6 GB-ra esett a redis memória használat. Ez körülbelül 54%-os hatékonyság. Nem akarunk telhetetlenek lenni, de hova tűnt az a körülbelül 30%-os különbség, amit várnánk a tömörítési aránynak megfelelően? Egyrészt a cache-k egy része lehet olyan tartalommal bír, amit már annyira nem lehet tömöríteni, másrészt a redis ugye key -> value alapú, amelyből a kulcsot is ugyanúgy tárolni kell, mint magát az értéket. Ezzel is érdemes számolni, ha több millió kulcsunk van.

Figyeljünk a kulcsokra

A key -> value alapú tárolásnál figyeljünk arra, hogy a kulcsot is ugyanúgy tárolnunk kell, nem csak az értéket. Erre legfőképp akkor kell figyelnünk, ha milliós nagyságrendű kulcsunk van. Nálunk mivel az összes bolt összes cache adatát egy szerver tárolja így több millió kulcsunk lesz. Egy példán keresztül nézzük meg, miért is kell erre figyelmet fordítani.

Például így épül fel a kulcs nevünk: shopnév/frontend/modulnév/termékazonosító

egy ilyen azonosító 41 karakter. Amihez 41 byte szükséges a tároláshoz. Tegyük fel van körülbelül 50 millió kulcsunk. 50,000,000 X 41 = 2050,000,000 byte (több mint 2 milliárd byte) 2050,000,000 ÷ (1024×1024×1024) = 1,9 GB.

Tehát erre is különösen érdemes figyelni, ha több millió kulcsokat akarunk tárolni, hogy a kulcsok neveit minél inkább rövidítsük, mert sokkal több memóriát foglal a tárolásuk, mint elsőre gondolnánk.

Összegzés

Bármit is cachelünk, mindig próbáljuk meg tömöríteni is azt. Manapság már olyan processzorokkal rendelkeznek a szerverek, hogy szinte észre sem vehető a kitömörítéssel elvesztett idő. Sőt, egyéb területeken sokkal többet nyerhetünk, mivel kisebb adatokkal kell dolgoznunk. Érdemes minden szerverünk minden paraméterét figyelni a tömörítés bevezetése előtt, mert olyanfajta terheléseket csökkenthetünk, amelyet elsőre nem is gondolnánk.