a Cassandra DB méretezésének rossz módja, ha másodlagos indexek vannak a helyükön

a Cassandra a kedvenc (nem kezelt) adatbázisom több okból is: nincs egyetlen hibapontja (SPoF), támogatja a több régiót, jó az olvasási és írási műveletekhez, rugalmas az olvasási és írási konzisztencia szintjeiről, lineárisan skálázódik, és nem túl bonyolult a napi műveletek kezeléséhez.

mint minden adatbázis, a Cassandra-t is az adathozzáférési minták alapján kell használni, így ha rugalmas adatbázisra van szüksége az ad-hoc lekérdezésekhez, vagy elég adaptálható az adatbázismodell állandó változásaihoz, akkor más lehetőségeket is figyelembe kell vennie.

Cassandra egy oszlop-orientált DB, és ez nagyon erős, ha az adatok lekérdezések már definiált. A Datastax, a Cassandra-t támogató vállalat azt javasolja, hogy kezdje a lekérdezések, majd az adatmodell megtervezésével a Cassandra-ban. Az oszlopos szerkezet ellenére a Cassandra számos adatstruktúrát támogat oszlop (ok) típusként, például térképeket.

a Cassandra egy elsődleges kulcsadatbázis, ami azt jelenti, hogy az adatok megmaradnak és egy fürt köré szerveződnek az elsődleges kulcs hash értéke (a partíciós kulcs) alapján. Azoknál a tábláknál, amelyek egynél több PK-val rendelkeznek, a Cassandra csak a PK első részét tekinti partíciós kulcsnak. További információ az összetett kulcsokról itt.

hogy egyértelműbb legyen, térjünk vissza a Cassandra DB egyik legfontosabb jellemzőjéhez: ez az építészet és az a tény, hogy nincs SPoF.

a Cassandra klaszter csomópontokból áll (3 vagy több), és ezek a csomópontok együttesen alkotják a csomópontok gyűrűjét:

hat csomópontból álló Cassandra klaszter (n6)

hat csomópontból álló Cassandra klaszter (n6)

egy Cassandra klaszter hat csomóponttal (n6)

a Cassandra fürtjének minden csomópontja “függetlenül” működik, de a különböző csomópontok ugyanazokat az adatokat tárolhatják, ennek megfelelően a fürthöz konfigurált replikációs tényező (RF) konfiguráció.

ahhoz, hogy megtudja, hol (melyik csomópontban) vannak az adatai, a Cassandra az adott táblázat PK oszlopát használó következetes hash függvény segítségével kiszámított hash értéket (tokent) használja.

lekérdezés futtatásakor a koordinátor csomópont (általában a legközelebbi alkalmazáspéldány) megkeresi, hogy a gyűrű mely csomópontjai tartalmazzák az adatait, így ha az egyik csomópont valamilyen okból nem működik, egy másik csomópont kiszolgálhatja az adatokat (RF 6). Ez a varázslat a mester nélküli megközelítésben, ahol a gyűrű minden csomópontja egyenlő az olvasás és az írás szempontjából.

ez a PK-ról és a replikációs tényezőről szóló koncepció nagyon fontos ahhoz, hogy megértsük, hogyan kell méretezni a Cassandra-fürtöt, amikor az alkalmazás nagy terhelési körülmények között van.

másodlagos indexek

Cassandra is fogalma másodlagos indexek. A relációs adatbázisokban sok index lehet egy adott táblázatban, a másodlagos index költsége az írási műveletekhez kapcsolódik, nem pedig az olvasási műveletekhez. Cassandrában ez nem igaz.

a Cassandra másodlagos indexei hasznosak és csábítóak lehetnek, ha az adatmodell megváltozott, és új oszlop alapján kell lekérdezni.

ily módon egy másodlagos index segítségével futtathat egy ilyen lekérdezést:

SELECT * FROM my_table WHERE SECONDARY_INDEX = ‘érték’;

A másodlagos Index

használatával kapcsolatos probléma képzelje el a forgatókönyvet: Blackfriday/CyberMonday-ban vagy, és a Cassandra klasztere csúcseseményektől szenved, és több csomópontot kell hozzáadnia az adatbázis méretezéséhez, a forgalom jobb kiegyensúlyozásához és… túléléshez. Jól, igaz?

normális esetben ez egy normális helyzet egy nagyon skálázható alkalmazásban. De mi van akkor, ha az alkalmazás másodlagos index segítségével futtat lekérdezéseket?

Igen, érted a lényeget.

Emlékszel, amikor azt mondtam, hogy a Cassandra elosztja az adatokat egy gyűrűben a partíciós kulcs segítségével? Ez már megtörténik, de a probléma az, amikor másodlagos indexet vezet be a lekérdezésbe. A másodlagos indexek nem részei a partíciós kulcsnak, és a Cassandra tudja, hogy az adatok hol élnek a partíciós kulcson keresztül. Amikor ilyen típusú indexet használó lekérdezést futtat, a Cassandra azt keresi, hogy a gyűrű minden egyes csomópontja megpróbálja kielégíteni a lekérdezést.

valós forgatókönyv

a Blackfriday során alkalmazásaink nagy terheléssel rendelkeztek. Sok-sok ügyfél szeretne részesülni a Blackfriday esemény által nyújtott hatalmas kedvezményekből.

vettünk egy pillantást a APM és az összes elemzés vezetett minket, hogy a kitartás, ebben az esetben a Cassandra DB. Hosszú késleltetési időt kaptunk, de nem minden kérésre, csak néhányra.

megpróbáltuk a dolgokat újra normális állapotba hozni, az első manőverünk az volt, hogy további csomópontokat adtunk a Cassandra klaszterünkhöz.

hozzáadtuk, és még mindig szenvedünk a késleltetési problémáktól. A kérdés az volt: miért történik ez még mindig?

tévedtünk. Leegyszerűsítő következtetés volt, és egy nagyon fontos részletre nem figyeltünk: ez a viselkedés nem minden kérésben, hanem néhányban történt.

ha gondolt a másodlagos index, bingó! Pontosan ez volt a probléma.

a csomópontok hozzáadása soha nem oldaná meg a problémát, mert a probléma nem kapcsolódott az adatbázisba érkező összes lekérdezéshez, a probléma néhányban volt, és ezek voltak a valódiak, amelyek rontották az adatbázis teljesítményét. Teljesen Pareto dolog volt.

részletezve a problémát, és hogyan enyhítjük

a Blackfriday esemény előtt egy pillanattal meg kellett változtatnunk az adatmodellünket. Regionalizáltuk alkalmazásunkat, és az ügyfél régiója kezdett fontos dolog lenni számunkra, egy termék vagy régió alapján kellett adatokat lekérdeznünk.

visszatekintve és összekötve a pontokat, rájöttünk, hogy nagyon értékesek vagyunk a megvalósításban, mivel ezt az új viselkedést nemcsak az API rétegben (new query param) akartuk tükrözni, hanem a Cassandra adataihoz való hozzáférés módjában is.

és miért voltunk olyan értékesek? Mert még ha figyelembe vesszük is, hogy a lekérdezési időnk nem nőtt annyira, elvégeztük a változást.

ez a megvalósítás nem csak növelte a lekérdezési időt egy másodlagos index használatával, hanem több problémát is generált a Cassandra infrastruktúrájának méretének megfelelően. Ahogy több csomópontot adtunk hozzá a klaszterünkhöz, több csomópontot jelentett az adatok megkeresésére, így a probléma exponenciálisan nőtt.

a probléma enyhítése érdekében visszavettük a korábban meglévő csomópontok számát, és növeltük a replikációs tényezőt a fürtben lévő csomópontok többségénél.

az olvasási konzisztencia szintjét is megváltoztattuk, hogy kevésbé konzisztens legyen. A * QUORUMOT használtuk, és helyette eggyé váltunk. Ez segített csökkenteni a csomópontok terhelését.

mivel napokkal az esemény előtt lefagyasztottuk alkalmazásainkat, tudtuk, hogy nincsenek új adataink (írási műveletek), és az adatok a jelenlegi állapotukban konzisztensek lesznek.

the days after and the DB model solution

a végleges megoldás részeként át kellett gondolnunk az adatbázis-modellünket, és vissza kellett állítanunk azokat a változtatásokat, amelyeket enyhítési útvonalként tettünk az esemény során.

az esemény előtt a termékazonosítót (PID)használtuk partíciós kulcsként, ami jó döntés volt, mivel a PID jó tulajdonságokkal rendelkezik, hogy PK legyen, mivel jellege miatt sorszám (magas kardinalitás), és így egyenletesen terjeszti az adatokat a klaszter körül.

az új “régió” mezőről a Cassandra collections adattípust használjuk, és minden régióhoz egy térképet használunk oszlopként a terméktáblázatban.

A másodlagos indexek mindig rossz ötlet?

a rövid válasz nem.

egy kicsit jobban elmagyarázva, a Cassandra-ban kétféle index létezik: helyi és globális indexek.

a helyi index, ahogy a neve is mondja, egyfajta index, amely csak lokálisan létezik, vagyis egy csomópontban. Másodlagos index létrehozásakor a Cassandra létrehoz egy új (rejtett) táblát, ahol a másodlagos elsődleges kulcs lesz ebben a táblázatban. Ennek az új táblának a láthatósága csomópont, nem gyűrű (fürt). Ez a helyzet a másodlagos indexekkel.

másrészt a globális index gyűrűs láthatósággal rendelkezik a partíciós kulcson keresztül, így Cassandra tudja, hol vannak az adatok a gyűrűben a partíciós kulcson keresztül.

másodlagos indexek lehetnek alternatívak, ha a lekérdezésben mind az elsődleges, mind a másodlagos indexek vannak. Ebben az esetben a Cassandra tudja, hol található az adat (melyik csomópont) a partíciós kulcson keresztül, majd megkeresi a csomópont helyi tábláját, amely a (helyi) másodlagos indexekre utal.

a másodlagos indexekkel kapcsolatban vannak más árnyalatok is, amelyeket itt nagyon jól elmagyarázunk, de a legjobb gyakorlat az, ha elkerüljük őket az adatmodell denormalizálásával.

Vélemény, hozzászólás?

Az e-mail-címet nem tesszük közzé.