HTML

asdf

Appengine Datastore Writes

2012.02.16. 06:39 tvk

Ismét a Google Appengine kvótáival kapcsolatban ragadok billentyűzetet. A Datastore Writes-ról fogok írni, ami némi gondot okozott nekem az utóbbi időben. A Datastore Writes egy mérőszám, ami azt jelzi hogy a GAE alkalmazás mennyi adatbázis írás műveletet végzett a nap kezdete óta. Az első 50 ezer művelet ingyen van, efölött pedig 1 millió művelet kerül 1 dollárba. Ez egyáltalán nem nagy összeg, de azért érdemes figyelni rá. Először is nem árt tudni, tulajdonképpen mi számít egy adatbázis írásnak.

Egy entitás perzisztálása legalább egy darab művelet. Az entitás property-jeire a GAE automatikusan indexeket tesz (kivéve a Text és Blob típusúakat), amik arra kellenek, hogy filterezett vagy növekvő illetve csökkenő rendezett lekérdezéseket lehessen rájuk csinálni. Ez property-nként két indexet jelent, egyben plusz két írási műveletet. Ha összetett lekérdezéseket akarunk alkalmazni az adott entitásokra, akkor saját kompozit indexeket is el kell helyeznünk, amik szintén növelik az írási műveletek számát. Ha kihasználjuk a GAE datastore azon tulajdonságát, hogy egy property-nek több értéket is adunk, akkor találkozhatunk a robbanó indexekkel is. Extrém esetben el lehet érni az egy entitásra rakható indexek maximális értékét is (5000). Itt van egy táblázat arról, hogy az entitások módosítása és a törlése során hogyan számolódnak az adatbázis írás műveletek. Node hogyan lehet ezt optimalizálni?

Lehetőség van unindexed property-k használatára, azaz egyszerűen megmondjuk, hogy nem kérünk indexet az adott property-re. Ezt akkor érdemes kihasználni, ha előre tudjuk, hogy egy property-re biztosan nem akarunk majd rendezéseket vagy filterezett lekérdezéseket futtatni. Low-level Java API-ben egyszerűen a setUnindexedProperty-t kell hívni a setProperty helyett. JPA vagy JDO esetén annotációval kell ellátni az adott property-t: @Extension(vendorName="datanucleus", key="gae.unindexed", value="true"). Ez alapján a Datanucleus olyan bájtkódot fog buherálni, ami unindexed property-ket eredményez. Mivel pl. JPA esetén az annotáció a org.datanucleus.jpa.annotations package-ből jön, adtunk egy pofont a hordozhatóságnak. Elfut Datanucleus nélkül is, csak a datanucleus-jpa.jar-nak ott kell figyelnie a classpath-on, és JPA2.0 szükséges hozzá. A modernebb appengine ORM keretrendszerek (Objectify, Twig, SimpleDS) is mind támogatják az unindexed property-k használatát.

Annak sincs akadálya, hogy menet közben módosítsunk, azaz olyan property-t amin eddig volt index, a továbbiakban unindexed-ként mentsünk, vagy fordítva. Persze fel kell készíteni erre a programkódot, mert a filterezett vagy rendezett lekérdezésekből egyszerűen hiányozni fognak azok az entitások, amikben nincs index az adott property-re. Egyben így lehet kideríteni admin konzolból az indexezés állapotát. Beküldünk egy GQL-t az entitás típus (Kind) kérdéses indexére pl. order by-jal, és ha kevesebb rekordot kapunk mint az elemek száma, akkor bizonyos entitásokról hiányoznak az indexek. Ha üres eredményt kapunk, akkor egyáltalán nincsenek indexek az adott property-n.

Pár szó a Lob-okról: Ha egy entitást (javax.persistence) @Lob annotációval látunk el, az nem lesz indexelve és hosszú, Text típusú  adatszerkezetként lesz tárolva, tehát nem vonatkoznak rá a String max 500 byte-os szabályai. A datastore view-ben nem lesz szerkeszthető, de legalább nem egy apró textfield-ben jelenik meg az értéke, tehát látszik az egész, vagy legalábbis az eleje. (update 2012.10.27: új feature jelent meg. Egy klikkelés után a hosszabb content-et is meg lehet nézni kényelmesen.) Ha már létező String típusú property-t alakítunk át, a Lob-bal annotált mező fogja tudni olvasni. Ahogy fentebb írtam, index nem lesz rajta.

Valamennyit lehet spórolni az unindexed property-k használatával, de ez magában még nem mindig vezet kielégítő eredményre. Érdemes eleve takarékosabban szervezni az entitásmodellt: Apró de nagy számú, összetartozó entitásokat érdemesebb lehet egy fő entitás mezőjeként eltárolni JSON vagy XML formában. Olcsóbb lehet programozottan kiválogatni őket az adatszerkezetből, mint fenntartani a sok indexet rájuk, ami a lekérdezésükhöz szükséges. Az írási műveleteket pedig össze lehet vonni. Persze ez már jórészt az adott feladattól függ, nem lehet általánosítani.

Érdemes Max Ross blogját böngészgetni egyéb Appengine Datastore-es információkkal kapcsolatban. Ezen kívül a Programming Google App Engine könyvet tudom ajánlani, ami a 350 oldalából elég sokat szán a datastore ismertetésére. A Python és a Java koncepcióival is foglalkozik, beleértve a JDO-t és JPA-t. Az online doksinak is lett egy olyan része mostanság, ami egészen részletekbe menően foglalkozik a datastore-ral. Itt található: Mastering the datastore. Akinek pedig van egy órája és jól tud angolul, az megnézheti Brett Slatkin előadását még 2009-ből, a skálázhatósági kérdésekkel kapcsolatban. Ő eléggé a multivalue property-ket nyomja.

Egyébként, ha elfogy a datastore write kvóta és ahhoz is adatbázis írás kellene, hogy az alkalmazást egy takarékosabb üzemmódba konfiguráljuk, azt csak a kvóta nullázódása után lehet megtenni, azaz magyar idő szerint reggel 9 után. Erre nem árt figyelni. A nagy adatlapátolásokkal is úgy érdemes számolni, hogy zabálják a kvótát. Én például stressztesztelek mostanában és ha sikerül 50% fölé kihajtanom a datastore write kvótát, akkor a kiindulási állapot visszaállítását, azaz a beírt entitások törlését sokszor csak a következő napon tudom megtenni. Így viszont a törlés napján nem lehet stressztesztelni az alkalmazást. Persze ez nem gond, semmi akadálya két alkalmazást fenntartani erre a célra és felváltva tesztelni velük.

Kicsit ijesztőnek tűnhet, hogy appengine alkalmazás fejlesztése során ilyen mesterségesen felállított korlátokkal kell foglalkozni, de ez a felhőszolgáltatás sajátosságaiból adódik: Van egy iszonyat hardverpark, ami vígan ki tudná szolgálni az alkalmazásunkat bármekkora terhelés esetén (már ha jól írtuk meg), de valahogy muszáj határokat szabni. A Google-nál így oldották meg.

Saját hardveren hosztolt alkalmazásoknak is megvannak a határai, legfeljebb máshogy viselkednek amikor elérik őket. A tapasztalatom az, hogy akkor szokott kiderülni, hogy egyáltalán létezik egy határ, amikor már kezdjük elérni: a válaszidők megnövekednek, nem lehet használni a szoftvert, a felhasználók elégedetlenek, roló le, gáz van. Ilyenkor kötjük rá a diagnosztikai eszközöket a szerverre és jó esetben konfigurációval megoldható a probléma, rossz esetben nem. Ilyenkor jó lenne, ha meg lehetne oldani annyival a problémát, hogy bedobunk még egy kis aprót és megy tovább a játék. Appengine-nél elvileg meg lehet oldani.

2 komment

Címkék: java appengine datastore

A bejegyzés trackback címe:

https://kodzaj.blog.hu/api/trackback/id/tr384116679

Kommentek:

A hozzászólások a vonatkozó jogszabályok  értelmében felhasználói tartalomnak minősülnek, értük a szolgáltatás technikai  üzemeltetője semmilyen felelősséget nem vállal, azokat nem ellenőrzi. Kifogás esetén forduljon a blog szerkesztőjéhez. Részletek a  Felhasználási feltételekben és az adatvédelmi tájékoztatóban.

Kozka 2012.02.16. 16:00:43

> 1 millió művelet kerül 1 dollárba

Azert nagyobb terheles alatt ez komoly penzbe kerulhet. 1 millio lekerdezes egy key-value store-tol nem olyan nagy dolog. Szoval nekem ugy tunik inkab azoknak lehet ez jo, akiknek viszonylag kicsi forgalmuk van es nem akarnak sajat szerverfarmot hozza. Viszont azok meg hogyan fizetik meg a szoftverfejlesztest?

tvk · http://kodzaj.blog.hu 2012.02.16. 16:52:08

Az 1 millió *lekérdezés* tényleg nem nagy ügy, de lekérdezésnél lehet és kell is cache-et használni, amivel drasztikusan lehet csökkenteni az ilyen jellegű műveletek számát.

Az írások számát nem lehet ilyen könnyen csökkenteni. Viszont ha 1 millió írási művelet nem hordoz senki számára 1 dollár értéket, akkor az egész szoftver létjogosultsága, megkérdőjelezhető, még ha egy nagyon nemes célú, ingyenes, jótékonykodó szoftverről is van szó.