Ezt több fejlesztőnek kellene tudnia az adatbázisokról

Jegyzet. ford.: Jaana Dogan a Google tapasztalt mérnöke, aki jelenleg a vállalat Go nyelven írt termelési szolgáltatásainak megfigyelhetőségén dolgozik. Ebben a cikkben, amely nagy népszerűségre tett szert az angol nyelvű közönség körében, 17 pontban gyűjtötte össze a DBMS-ekkel (és néha általában az elosztott rendszerekkel) kapcsolatos fontos technikai részleteket, amelyek hasznosak a nagy/igényes alkalmazások fejlesztői számára.

Ezt több fejlesztőnek kellene tudnia az adatbázisokról

A számítógépes rendszerek túlnyomó többsége nyomon követi állapotát, és ennek megfelelően valamilyen adattároló rendszert igényel. Hosszú időn keresztül halmoztam fel tudást az adatbázisokról, miközben tervezési hibákat követtem el, amelyek adatvesztéshez és leállásokhoz vezettek. A nagy mennyiségű információt feldolgozó rendszerekben az adatbázisok a rendszerarchitektúra középpontjában állnak, és kulcsfontosságú szerepet töltenek be az optimális megoldás kiválasztásában. Annak ellenére, hogy nagy figyelmet fordítanak az adatbázis munkájára, azok a problémák, amelyeket az alkalmazásfejlesztők próbálnak előre látni, gyakran csak a jéghegy csúcsát jelentik. Ebben a cikksorozatban megosztok néhány ötletet, amelyek hasznosak lehetnek azon fejlesztők számára, akik nem erre a területre specializálódtak.

  1. Szerencsés, ha az esetek 99,999%-ában a hálózat nem okoz problémát.
  2. A SAV sokféle dolgot jelent.
  3. Minden adatbázisnak megvannak a saját mechanizmusai a konzisztencia és az elszigeteltség biztosítására.
  4. Az optimista blokkolás akkor segít, ha nehéz fenntartani a megszokottat.
  5. A piszkos olvasáson és az adatvesztésen kívül más anomáliák is vannak.
  6. Az adatbázis és a felhasználó nem mindig ért egyet a cselekvés menetében.
  7. Az alkalmazásszintű felosztás az alkalmazáson kívülre helyezhető.
  8. Az automatikus növelés veszélyes lehet.
  9. Az elavult adatok hasznosak lehetnek, és nem kell zárolni őket.
  10. A torzítások minden időforrásra jellemzőek.
  11. A késleltetésnek sok jelentése van.
  12. A teljesítménykövetelményeket egy adott tranzakcióra kell értékelni.
  13. A beágyazott tranzakciók veszélyesek lehetnek.
  14. A tranzakciókat nem szabad az alkalmazás állapotához kötni.
  15. A lekérdezéstervezők sokat tudnak mondani az adatbázisokról.
  16. Az online migráció nehéz, de lehetséges.
  17. Az adatbázis jelentős növekedése a kiszámíthatatlanság növekedését vonja maga után.

Szeretnék köszönetet mondani Emmanuel Odeke-nek, Rein Henrichs-nek és másoknak a cikk korábbi verziójával kapcsolatos visszajelzéseikért.

Szerencsés, ha az esetek 99,999%-ában a hálózat nem okoz problémát.

Továbbra is kérdés, hogy mennyire megbízhatóak a modern hálózati technológiák, és milyen gyakran állnak le a rendszerek hálózati hibák miatt. Kevés információ áll rendelkezésre erről a kérdésről, és a kutatást gyakran a nagy szervezetek uralják speciális hálózatokkal, berendezésekkel és személyzettel.

A Spanner (a Google globálisan elosztott adatbázisa) 99,999%-os rendelkezésre állási arányával a Google azt állítja, hogy csak 7,6% problémák a hálózattal kapcsolatosak. Ugyanakkor a vállalat a magas rendelkezésre állás „fő pillérének” nevezi speciális hálózatát. Tanulmány Bailis és Kingsbury, amelyet 2014-ben végeztek, kihívást jelent az egyik „tévhitek az elosztott számítástechnikával kapcsolatban", amelyet Peter Deutsch 1994-ben fogalmazott meg. Tényleg megbízható a hálózat?

Az óriásvállalatokon kívül, a szélesebb internet érdekében végzett átfogó kutatás egyszerűen nem létezik. Arról sem áll rendelkezésre elegendő adat a jelentősebb szereplőktől, hogy ügyfeleik problémái hány százalékban kapcsolódnak hálózathoz. Tisztában vagyunk a nagy felhőszolgáltatók hálózati veremének leállásaival, amelyek több órára lebonthatják az internet egész részét, pusztán azért, mert nagy horderejű eseményekről van szó, amelyek sok embert és vállalatot érintenek. A hálózati kimaradások sokkal több esetben okozhatnak problémákat, még akkor is, ha ezek az esetek nem mindegyike kerül reflektorfénybe. A felhőszolgáltatások ügyfelei sem tudnak semmit a problémák okairól. Ha meghibásodás van, azt szinte lehetetlen hálózati hibának tulajdonítani a szolgáltató oldalán. Számukra a harmadik féltől származó szolgáltatások fekete dobozok. Lehetetlen felmérni a hatást nagy szolgáltató nélkül.

Tekintettel arra, hogy a nagy szereplők mit számolnak be rendszereikről, nyugodtan kijelenthetjük, hogy szerencséje van, ha a hálózati nehézségek a lehetséges leállási problémáknak csak kis százalékát teszik ki. A hálózati kommunikáció még mindig szenved az olyan hétköznapi dolgoktól, mint a hardverhibák, a topológia változásai, az adminisztratív konfigurációs változások és az áramkimaradások. Nemrég meglepődtem, amikor megtudtam, hogy a lehetséges problémák listája hozzáadásra került cápa harap (igen, jól hallottad).

A SAV sokféle dolgot jelent

Az ACID mozaikszó az Atomicity, Consistency, Isolation, Reliability rövidítése. A tranzakciók ezen tulajdonságainak célja, hogy biztosítsák azok érvényességét meghibásodások, hibák, hardverhibák stb. esetén. ACID vagy hasonló sémák nélkül az alkalmazásfejlesztők nehezen tudnának különbséget tenni aközött, hogy mi a felelős, és mi az, amiért az adatbázis. A legtöbb relációs tranzakciós adatbázis igyekszik ACID-kompatibilis lenni, de az olyan új megközelítések, mint a NoSQL, sok olyan adatbázist eredményeztek, amelyek nem tartalmaznak ACID-tranzakciókat, mivel ezek megvalósítása költséges.

Amikor először beléptem az iparágba, műszaki vezetőnk arról beszélt, mennyire releváns az ACID koncepció. Az igazság kedvéért, az ACID-t inkább durva leírásnak tekintik, mint szigorú végrehajtási szabványnak. Ma leginkább hasznosnak tartom, mert a problémák egy meghatározott kategóriáját veti fel (és egy sor lehetséges megoldást javasol).

Nem minden DBMS kompatibilis ACID-vel; Ugyanakkor az ACID-t támogató adatbázis-megvalósítások eltérően értelmezik a követelményeket. Az egyik ok, amiért az ACID-megvalósítások hézagosak, a sok kompromisszumnak köszönhető, amelyeket az ACID-követelmények megvalósításához meg kell tenni. Az alkotók bemutathatják adatbázisaikat ACID-kompatibilisként, de a szélső esetek értelmezése drámaian változhat, akárcsak a "valószínűtlen" események kezelésének mechanizmusa. A fejlesztők legalább magas szintű ismereteket szerezhetnek az alapmegvalósítások bonyolultságáról, hogy megfelelően megértsék speciális viselkedésüket és a tervezési kompromisszumokat.

A vita arról, hogy a MongoDB megfelel-e az ACID-követelményeknek, a 4-es verzió megjelenése után is folytatódik. A MongoDB-t hosszú ideig nem támogatják fakitermelés, bár alapértelmezés szerint az adatok legfeljebb 60 másodpercenként kerültek lemezre. Képzelje el a következő forgatókönyvet: egy alkalmazás két írást tesz közzé (w1 és w2). A MongoDB sikeresen tárolja a w1-et, de a w2 hardverhiba miatt elveszett.

Ezt több fejlesztőnek kellene tudnia az adatbázisokról
A forgatókönyvet illusztráló diagram. A MongoDB összeomlik, mielőtt adatokat írhatna a lemezre

A lemezre kötés költséges folyamat. A gyakori véglegesítés elkerülésével a fejlesztők javítják a rögzítési teljesítményt a megbízhatóság rovására. A MongoDB jelenleg támogatja a naplózást, de a piszkos írások továbbra is befolyásolhatják az adatok integritását, mivel a naplók alapértelmezés szerint 100 ms-onként kerülnek rögzítésre. Vagyis hasonló forgatókönyv továbbra is lehetséges a naplók és a bennük bemutatott változások esetében, bár a kockázat sokkal kisebb.

Minden adatbázisnak megvan a maga konzisztenciája és elkülönítési mechanizmusa

Az ACID-követelmények közül a konzisztencia és az elszigeteltség büszkélkedhet a legtöbb különböző megvalósítással, mivel a kompromisszumok köre szélesebb. Azt kell mondanunk, hogy a következetesség és az elszigeteltség meglehetősen drága funkciók. Koordinációt igényelnek, és fokozzák a versenyt az adatok konzisztenciájáért. A probléma összetettsége jelentősen megnő, ha az adatbázist vízszintesen kell skálázni több adatközponton keresztül (különösen, ha azok különböző földrajzi régiókban találhatók). A magas szintű konzisztencia elérése nagyon nehéz, mivel csökkenti a rendelkezésre állást és növeli a hálózat szegmentáltságát. A jelenség általánosabb magyarázatához azt tanácsolom, hogy hivatkozzon erre CAP tétel. Azt is érdemes megjegyezni, hogy az alkalmazások kis mértékű inkonzisztenciát is képesek kezelni, és a programozók elég jól megértik a probléma árnyalatait ahhoz, hogy további logikát építsenek be az alkalmazásba az inkonzisztenciák kezelésére anélkül, hogy nagy mértékben támaszkodnának az adatbázisra.

A DBMS-ek gyakran különböző szintű elkülönítést biztosítanak. Az alkalmazásfejlesztők preferenciáik alapján kiválaszthatják a leghatékonyabbat. Az alacsony szigetelés nagyobb sebességet tesz lehetővé, de növeli az adatverseny kockázatát is. A magas szigetelés csökkenti ezt a valószínűséget, de lelassítja a munkát, és versenyhez vezethet, ami olyan fékekhez vezet az alapban, hogy meghibásodások kezdődnek.

Ezt több fejlesztőnek kellene tudnia az adatbázisokról
A meglévő párhuzamossági modellek és a köztük lévő kapcsolatok áttekintése

Az SQL szabvány csak négy elkülönítési szintet határoz meg, bár elméletben és gyakorlatban sokkal több van. Jepson.io kiváló áttekintést nyújt a meglévő párhuzamossági modellekről. A Google Spanner például garantálja a külső szerializálhatóságot az óraszinkronizálással, és bár ez egy szigorúbb elválasztó réteg, a szabványos elkülönítési rétegekben nincs meghatározva.

Az SQL szabvány a következő elkülönítési szinteket említi:

  • serializable (legszigorúbb és legdrágább): A szerializálható végrehajtásnak ugyanaz a hatása, mint néhány szekvenciális tranzakció-végrehajtásnak. A szekvenciális végrehajtás azt jelenti, hogy minden további tranzakció csak az előző befejezése után kezdődik. Meg kell jegyezni, hogy a szint serializable gyakran úgynevezett pillanatkép-izolációként valósítják meg (például az Oracle-ben) az értelmezésbeli különbségek miatt, bár maga a pillanatkép-izoláció nem szerepel az SQL-szabványban.
  • Ismételhető olvasmányok: Az aktuális tranzakció nem véglegesített rekordjai elérhetők az aktuális tranzakció számára, de a többi tranzakció által végrehajtott módosítások (például új sorok) nem látható.
  • Olvasni elkötelezett: A nem lekötött adatok nem állnak rendelkezésre a tranzakciókhoz. Ebben az esetben a tranzakciók csak lekötött adatokat láthatnak, és fantomolvasások fordulhatnak elő. Ha egy tranzakció új sorokat szúr be és véglegesít, az aktuális tranzakció lekérdezéskor láthatja azokat.
  • Elkötelezettség nélkül olvasni (legkevésbé szigorú és költséges szint): A piszkos olvasás megengedett, a tranzakciók láthatják a többi tranzakció által végrehajtott, nem véglegesített változtatásokat. A gyakorlatban ez a szint hasznos lehet durva becsléseknél, például lekérdezéseknél COUNT(*) az asztalon.

Szint serializable minimalizálja az adatversenyek kockázatát, miközben a legdrágább a megvalósítás, és a rendszer legnagyobb versenyterhelését eredményezi. Más elkülönítési szintek könnyebben megvalósíthatók, de növelik az adatversenyek valószínűségét. Egyes DBMS-ek lehetővé teszik egyéni elkülönítési szint beállítását, mások erős preferenciákkal rendelkeznek, és nem minden szint támogatott.

Az elkülönítési szintek támogatását gyakran hirdetik egy adott DBMS-ben, de csak a viselkedés alapos tanulmányozása tudja feltárni, hogy mi is történik valójában.

Ezt több fejlesztőnek kellene tudnia az adatbázisokról
A párhuzamossági anomáliák áttekintése a különböző DBMS-ek különböző elkülönítési szintjein

Martin Kleppmann projektjében remetelak Összehasonlítja a különböző izolációs szinteket, beszél egyidejűségi anomáliákról, és arról, hogy az adatbázis képes-e betartani egy adott izolációs szintet. Kleppmann kutatása megmutatja, hogy az adatbázis-fejlesztők mennyire eltérően gondolkodnak az elszigeteltségi szintekről.

Az optimista blokkolás akkor segít, ha nehéz fenntartani a megszokottat.

A blokkolás nagyon költséges lehet, nem csak azért, mert fokozza a versenyt az adatbázisban, hanem azért is, mert az alkalmazásszervereknek folyamatosan csatlakozniuk kell az adatbázishoz. A hálózati szegmentáció súlyosbíthatja az exkluzív zárolási helyzeteket, és nehezen azonosítható és feloldható holtpontokhoz vezethet. Azokban az esetekben, amikor az exkluzív zárolás nem megfelelő, az optimista zárás segít.

Optimista zár egy olyan módszer, amelyben egy karakterlánc beolvasásakor figyelembe veszi annak verzióját, ellenőrző összegét vagy az utolsó módosítás idejét. Ez lehetővé teszi, hogy egy bejegyzés módosítása előtt megbizonyosodjon arról, hogy nincs atomi verzióváltás:

UPDATE products
SET name = 'Telegraph receiver', version = 2
WHERE id = 1 AND version = 1

Ebben az esetben a táblázat frissítése products nem kerül végrehajtásra, ha egy másik művelet korábban módosított ebben a sorban. Ha más művelet nem történt ezen a sorban, akkor az egyik sor változása megtörténik, és azt mondhatjuk, hogy a frissítés sikeres volt.

A piszkos olvasáson és az adatvesztésen kívül más anomáliák is vannak

Amikor az adatok konzisztenciájáról van szó, a hangsúly a versenyfeltételeken van, amelyek piszkos leolvasáshoz és adatvesztéshez vezethetnek. Az adatok anomáliái azonban nem érnek véget.

Az ilyen anomáliák egyik példája a felvételi torzítás (írási ferdeség). A torzulásokat nehéz észlelni, mert általában nem keresik őket aktívan. Nem piszkos olvasás vagy adatvesztés, hanem az adatokra vonatkozó logikai korlátok megsértése miatt következnek be.

Vegyünk például egy olyan megfigyelő alkalmazást, amely megköveteli, hogy mindig egy operátor legyen készenlétben:

BEGIN tx1;                      BEGIN tx2;
SELECT COUNT(*)
FROM operators
WHERE oncall = true;
0                               SELECT COUNT(*)
                                FROM operators
                                WHERE oncall = TRUE;
                                0
UPDATE operators                UPDATE operators
SET oncall = TRUE               SET oncall = TRUE
WHERE userId = 4;               WHERE userId = 2;
COMMIT tx1;                     COMMIT tx2;

A fenti helyzetben rekordsérülés következik be, ha mindkét tranzakció sikeresen végrehajtódik. Bár nem történt piszkos olvasás vagy adatvesztés, az adatok sértetlensége veszélybe került: most egyszerre két ember számít ügyeletnek.

A sorosozható elkülönítés, a sématervezés vagy az adatbázis-megszorítások segíthetnek az írássérülések kiküszöbölésében. A fejlesztőknek képesnek kell lenniük az ilyen rendellenességek azonosítására a fejlesztés során, hogy elkerüljék őket a gyártás során. A rögzítési torzításokat ugyanakkor rendkívül nehéz a kódbázisban keresni. Főleg nagy rendszerekben, amikor különböző fejlesztőcsapatok felelősek a funkciók azonos táblák alapján történő megvalósításáért, és nem értenek egyet az adathozzáférés sajátosságaiban.

Az adatbázis és a felhasználó nem mindig ért egyet abban, hogy mit tegyen

Az adatbázisok egyik legfontosabb jellemzője a végrehajtási sorrend garanciája, de ez a megbízás maga nem biztos, hogy átlátható a szoftverfejlesztő számára. Az adatbázisok a beérkezési sorrendben hajtják végre a tranzakciókat, nem a programozók szándéka szerint. A tranzakciók sorrendjét nehéz megjósolni, különösen a nagy terhelésű párhuzamos rendszerekben.

A fejlesztés során, különösen, ha nem blokkoló könyvtárakkal dolgozunk, a rossz stílus és az alacsony olvashatóság miatt a felhasználók azt hihetik, hogy a tranzakciók szekvenciálisan hajtódnak végre, pedig valójában bármilyen sorrendben megérkezhetnek az adatbázisba.

Első pillantásra az alábbi programban a T1 és a T2 szekvenciálisan hívódnak, de ha ezek a függvények nem blokkolnak, és azonnal visszaadják az eredményt a következő formában ígéret, akkor a hívások sorrendjét az adatbázisba való belépés pillanatai határozzák meg:

eredmény1 = T1() // a valós eredmények ígéretek
eredmény2 = T2()

Ha atomitásra van szükség (vagyis minden műveletet be kell fejezni vagy meg kell szakítani), és a sorrend számít, akkor a T1 és T2 műveleteket egyetlen tranzakción belül kell végrehajtani.

Az alkalmazásszintű felosztás az alkalmazáson kívülre helyezhető

A megosztás az adatbázis vízszintes particionálásának módszere. Egyes adatbázisok képesek automatikusan vízszintesen felosztani az adatokat, míg mások nem, vagy nem túl jók ebben. Amikor az adattervezők/-fejlesztők pontosan meg tudják jósolni, hogy az adatokhoz hogyan fognak hozzáférni, vízszintes partíciókat hozhatnak létre a felhasználói térben ahelyett, hogy ezt a munkát az adatbázisra delegálnák. Ezt a folyamatot "alkalmazásszintű felosztásnak" nevezik. (alkalmazásszintű felosztás).

Sajnos ez a név gyakran azt a tévhitet kelti, hogy a sharding az alkalmazásszolgáltatásokban él. Valójában külön rétegként is megvalósítható az adatbázis előtt. Az adatnövekedéstől és a séma iterációitól függően a felosztási követelmények meglehetősen összetettek lehetnek. Egyes stratégiák számára előnyös lehet az alkalmazáskiszolgálók újratelepítése nélkül történő iteráció.

Ezt több fejlesztőnek kellene tudnia az adatbázisokról
Példa egy olyan architektúrára, amelyben az alkalmazáskiszolgálók el vannak választva a felosztási szolgáltatástól

A felosztásnak egy külön szolgáltatásba való áthelyezése kibővíti a különböző felosztási stratégiák alkalmazásának lehetőségét az alkalmazások újratelepítése nélkül. Vitess egy példa egy ilyen felosztási rendszerre az alkalmazás szintjén. A Vitess vízszintes felosztást biztosít a MySQL számára, és lehetővé teszi az ügyfelek számára, hogy a MySQL protokollon keresztül csatlakozzanak hozzá. A rendszer az adatokat különböző MySQL csomópontokra szegmentálja, amelyek semmit sem tudnak egymásról.

Az automatikus növelés veszélyes lehet

Az AUTOINCREMENT az elsődleges kulcsok generálásának általános módja. Gyakran előfordul, hogy adatbázisokat használnak azonosító generátorként, és az adatbázis azonosítók generálására szolgáló táblákat tartalmaz. Számos oka van annak, hogy az elsődleges kulcsok automatikus növeléssel történő generálása messze nem ideális:

  • Egy elosztott adatbázisban az automatikus növelés komoly probléma. Az azonosító generálásához globális zárra van szükség. Ehelyett létrehozhat egy UUID-t: ehhez nincs szükség interakcióra a különböző adatbázis-csomópontok között. A zárakkal történő automatikus növelés vitához vezethet, és jelentősen csökkenti a betétek teljesítményét elosztott helyzetekben. Egyes DBMS-ek (például a MySQL) speciális konfigurációt és nagyobb odafigyelést igényelhetnek a fő-fő replikáció megfelelő megszervezéséhez. A konfigurálás során könnyű hibákat elkövetni, amelyek rögzítési hibákhoz vezetnek.
  • Egyes adatbázisok elsődleges kulcsokon alapuló particionáló algoritmusokkal rendelkeznek. Az egymást követő azonosítók előre nem látható hot spotokhoz és megnövekedett terheléshez vezethetnek egyes partíciókon, míg mások tétlen maradnak.
  • Az elsődleges kulcs a leggyorsabb módja az adatbázis egy sorának elérésének. A rekordok azonosításának jobb módszereivel a szekvenciális azonosítók a táblázatok legfontosabb oszlopát értelmetlen értékekkel teli haszontalan oszlopokká változtathatják. Ezért, amikor csak lehetséges, válasszon globálisan egyedi és természetes elsődleges kulcsot (pl. felhasználónevet).

Mielőtt a megközelítés mellett döntene, fontolja meg az azonosítók és UUID-k automatikus növelésének hatását az indexelésre, a particionálásra és a felosztásra.

Az elavult adatok hasznosak lehetnek, és nem igényelnek zárolást

A Multiversion Concurrency Control (MVCC) számos konzisztenciakövetelményt valósít meg, amelyeket fent röviden tárgyaltunk. Egyes adatbázisok (például Postgres, Spanner) az MVCC-t használják a tranzakciók pillanatképekkel történő „táplálására” – az adatbázis régebbi verzióival. A pillanatkép-tranzakciók sorba rendezhetők a következetesség biztosítása érdekében. Ha egy régi pillanatképből olvas, az elavult adatokat olvassa be.

A kissé elavult adatok olvasása hasznos lehet például az adatokból elemzések generálásakor vagy hozzávetőleges összesített értékek kiszámításakor.

Az örökölt adatokkal való munka első előnye az alacsony késleltetés (különösen, ha az adatbázis különböző földrajzi területeken van elosztva). A második az, hogy a csak olvasható tranzakciók zárolásmentesek. Ez jelentős előny a sokat olvasó alkalmazások számára, amennyiben képesek kezelni az elavult adatokat.

Ezt több fejlesztőnek kellene tudnia az adatbázisokról
Az alkalmazásszerver a helyi replikából 5 másodpercig elavult adatokat olvas be, még akkor is, ha a legújabb verzió elérhető a Csendes-óceán túloldalán

A DBMS-ek automatikusan törlik a régebbi verziókat, és bizonyos esetekben ezt kérésre lehetővé teszik. Például a Postgres lehetővé teszi a felhasználók számára VACUUM kérésre, és időnként automatikusan elvégzi ezt a műveletet. Spanner egy szemétgyűjtőt működtet, hogy megszabaduljon az egy óránál régebbi pillanatképektől.

Bármilyen időforrás torzításnak van kitéve

A számítástechnika legjobban őrzött titka az, hogy minden időzítő API hazudik. Valójában a gépeink nem tudják a pontos időt. A számítógépek kvarckristályokat tartalmaznak, amelyek rezgéseket generálnak, amelyeket az idő megtartására használnak. Azonban nem elég pontosak, és előfordulhat, hogy megelőzik/lemaradnak a pontos időnél. A műszak elérheti a napi 20 másodpercet. Ezért a számítógépeinken lévő időt rendszeresen szinkronizálni kell a hálózati idővel.

NTP-szervereket használnak a szinkronizáláshoz, de maga a szinkronizálási folyamat hálózati késéseknek van kitéve. Még az ugyanabban az adatközpontban lévő NTP-kiszolgálóval való szinkronizálás is eltart egy ideig. Nyilvánvaló, hogy a nyilvános NTP-kiszolgálóval végzett munka még nagyobb torzulásokhoz vezethet.

Az atomórák és GPS-társaik jobbak az aktuális idő meghatározására, de drágák és bonyolult beállítást igényelnek, így nem szerelhetők fel minden autóra. Emiatt az adatközpontok többszintű megközelítést alkalmaznak. Az atom- és/vagy GPS-órák a pontos időt mutatják, ami után másodlagos szervereken keresztül továbbítják a többi gépre. Ez azt jelenti, hogy minden gép egy bizonyos eltérést tapasztal a pontos időhöz képest.

A helyzetet súlyosbítja, hogy az alkalmazások és adatbázisok gyakran különböző gépeken találhatók (ha nem is különböző adatközpontokban). Így az idő nem csak a különböző gépeken elosztott DB-csomópontokon különbözik. Ez az alkalmazásszerveren is más lesz.

A Google TrueTime teljesen más megközelítést alkalmaz. A legtöbben úgy vélik, hogy a Google ebben az irányban történő előrehaladását az atom- és GPS-órákra való banális átállás magyarázza, de ez csak egy része a nagy képnek. Így működik a TrueTime:

  • A TrueTime két különböző forrást használ: GPS-t és atomórát. Ezek az órák nem korrelált hibamódokkal rendelkeznek. [a részleteket lásd az 5. oldalon itt - kb. fordítás.), így közös használatuk növeli a megbízhatóságot.
  • A TrueTime szokatlan API-val rendelkezik. Az időt mint intervallumot adja vissza, amibe mérési hiba és bizonytalanság van beépítve. Az aktuális pillanat valahol az intervallum felső és alsó határa között van. A Spanner, a Google elosztott adatbázisa egyszerűen megvárja, amíg biztonságosan kijelenthetjük, hogy az aktuális idő kívül esik a tartományon. Ez a módszer némi késleltetést visz be a rendszerbe, különösen, ha nagy a bizonytalanság a mastereken, de biztosítja a helyességet még globálisan elosztott helyzetben is.

Ezt több fejlesztőnek kellene tudnia az adatbázisokról
A Spanner komponensek a TrueTime-ot használják, ahol a TT.now() egy intervallumot ad vissza, így a csavarkulcs egyszerűen alszik addig a pontig, amíg biztos lehet benne, hogy az aktuális idő elhaladt egy bizonyos ponton

Az aktuális idő meghatározásának csökkentett pontossága a villáskulcs-műveletek időtartamának növekedését és a teljesítmény csökkenését jelenti. Éppen ezért fontos a lehető legnagyobb pontosság megőrzése, még akkor is, ha teljesen pontos órát nem lehet kapni.

A késleltetésnek sok jelentése van

Ha egy tucat szakértőt kérdez meg arról, hogy mi a késés, valószínűleg eltérő válaszokat fog kapni. A DBMS-ben a késleltetést gyakran "adatbázis késleltetésnek" nevezik, és eltér attól, amit az ügyfél észlel. A helyzet az, hogy a kliens megfigyeli a hálózati késleltetés és az adatbázis késleltetés összegét. A késleltetés típusának elkülönítésének képessége kritikus fontosságú a növekvő problémák hibakeresése során. A mutatók összegyűjtése és megjelenítése során mindig mindkét típust próbálja meg szemmel tartani.

A teljesítménykövetelményeket egy adott tranzakcióra kell értékelni

Néha egy DBMS teljesítményjellemzői és korlátai az írási/olvasási átviteli sebesség és a késleltetés tekintetében vannak megadva. Ez általános áttekintést nyújt a kulcsfontosságú rendszerparaméterekről, de egy új DBMS teljesítményének értékelésekor sokkal átfogóbb megközelítés a kritikus műveletek külön értékelése (minden lekérdezés és/vagy tranzakció esetében). Példák:

  • Írja be az átviteli sebességet és a késleltetést, amikor új sort szúr be az X táblába (50 millió sorral), meghatározott megszorításokkal és sorkitöltéssel a kapcsolódó táblázatokban.
  • Késleltetés egy bizonyos felhasználó barátai barátainak megjelenítésében, ha az ismerősök átlagos száma 500.
  • A 100 legjobb bejegyzés lekérésének késleltetése a felhasználó előzményeiből, amikor a felhasználó óránként X bejegyzéssel követ 500 másik felhasználót.

Az értékelés és a kísérletezés tartalmazhat ilyen kritikus eseteket, amíg nem biztos abban, hogy az adatbázis megfelel a teljesítménykövetelményeknek. Egy hasonló ökölszabály szintén figyelembe veszi ezt a bontást a késleltetési mutatók gyűjtésekor és az SLO-k meghatározásakor.

Ügyeljen arra, hogy az egyes műveletekre vonatkozó mérőszámok gyűjtése során nagy a számosság. Használjon naplókat, eseménygyűjtést vagy elosztott nyomkövetést a nagy teljesítményű hibakeresési adatok beszerzéséhez. A cikkben "Szeretné hibakeresési késleltetést?» megismerkedhet a késleltetett hibakeresés módszertanával.

A beágyazott tranzakciók veszélyesek lehetnek

Nem minden DBMS támogatja a beágyazott tranzakciókat, de ha igen, az ilyen tranzakciók váratlan hibákat eredményezhetnek, amelyeket nem mindig könnyű észlelni (vagyis nyilvánvalónak kell lennie, hogy valamilyen rendellenességről van szó).

Elkerülheti a beágyazott tranzakciók használatát olyan ügyfélkönyvtárak használatával, amelyek képesek észlelni és megkerülni azokat. Ha a beágyazott tranzakciókat nem lehet elhagyni, különösen ügyeljen azok megvalósítására, hogy elkerülje azokat a váratlan helyzeteket, amikor a befejezett tranzakciók véletlenül megszakadnak a beágyazott tranzakciók miatt.

A tranzakciók különböző rétegekbe ágyazása váratlan egymásba ágyazott tranzakciókhoz vezethet, és kódolvashatósági szempontból megnehezítheti a szerző szándékainak megértését. Vessen egy pillantást a következő programra:

with newTransaction():
   Accounts.create("609-543-222")
   with newTransaction():
       Accounts.create("775-988-322")
       throw Rollback();

Mi lesz a fenti kód kimenete? Visszavonja mindkét tranzakciót, vagy csak a belsőt? Mi történik, ha a könyvtárak több rétegére támaszkodunk, amelyek magukban foglalják a tranzakciók létrehozását számunkra? Sikerül-e azonosítani és javítani az ilyen eseteket?

Képzeljünk el egy adatréteget több művelettel (pl. newAccount) már be van építve a saját tranzakcióiba. Mi történik, ha azokat a magasabb szintű üzleti logika részeként futtatja, amely a saját tranzakcióján belül fut? Mi lenne ebben az esetben az elszigeteltség és a következetesség?

function newAccount(id string) {
  with newTransaction():
      Accounts.create(id)
}

Ahelyett, hogy ilyen végtelen kérdésekre keresnénk a választ, jobb elkerülni a beágyazott tranzakciókat. Végül is az adatréteg könnyen végrehajthat magas szintű műveleteket anélkül, hogy saját tranzakciókat hozna létre. Ezenkívül maga az üzleti logika képes tranzakciót kezdeményezni, műveleteket végrehajtani, tranzakciót végrehajtani vagy megszakítani.

function newAccount(id string) {
   Accounts.create(id)
}
// In main application:
with newTransaction():
   // Read some data from database for configuration.
   // Generate an ID from the ID service.
   Accounts.create(id)
   Uploads.create(id) // create upload queue for the user.

A tranzakciókat nem szabad az alkalmazás állapotához kötni

Néha csábító az alkalmazás állapotának használata a tranzakciókban bizonyos értékek módosítására vagy a lekérdezési paraméterek módosítására. A kritikus árnyalat, amelyet figyelembe kell venni, a megfelelő alkalmazási kör. Az ügyfelek hálózati problémák esetén gyakran újraindítják a tranzakciókat. Ha a tranzakció egy olyan állapottól függ, amelyet valamilyen más folyamat módosít, akkor az adatverseny lehetőségétől függően rossz értéket választhat. A tranzakcióknak figyelembe kell venniük az adatverseny feltételeinek kockázatát az alkalmazásban.

var seq int64
with newTransaction():
    newSeq := atomic.Increment(&seq)
    Entries.query(newSeq)
    // Other operations...

A fenti tranzakció minden egyes végrehajtása során növeli a sorszámot, függetlenül a végeredménytől. Ha a véglegesítés hálózati problémák miatt meghiúsul, a kérés más sorszámmal fog végrehajtásra kerülni, amikor újra megpróbálja.

A lekérdezéstervezők sokat tudnak mondani egy adatbázisról

A lekérdezéstervezők határozzák meg, hogy egy lekérdezés hogyan kerül végrehajtásra az adatbázisban. Ezenkívül elemzik és optimalizálják a kéréseket, mielőtt elküldik őket. A tervezők csak néhány lehetséges becslést tudnak adni a rendelkezésükre álló jelzések alapján. Például mi a legjobb keresési módszer a következő lekérdezéshez?

SELECT * FROM articles where author = "rakyll" order by title;

Az eredményeket kétféleképpen lehet lekérni:

  • Teljes táblázat szkennelés: Megnézheti a táblázat egyes bejegyzéseit, és visszaküldheti a cikkeket egyező szerzőnévvel, majd megrendelheti őket.
  • Index szkennelés: Egy index segítségével megtalálhatja a megfelelő azonosítókat, lekérheti ezeket a sorokat, majd rendezheti őket.

A lekérdezéstervező feladata annak meghatározása, hogy melyik stratégia a legjobb. Érdemes megfontolni, hogy a lekérdezéstervezők csak korlátozott előrejelzési képességekkel rendelkeznek. Ez rossz döntésekhez vezethet. A DBA-k vagy a fejlesztők használhatják őket a rosszul teljesítő lekérdezések diagnosztizálására és finomhangolására. A DBMS új verziói konfigurálhatják a lekérdezéstervezőket, és az öndiagnózis segíthet az adatbázis frissítésében, ha az új verzió teljesítményproblémákhoz vezet. A lassú lekérdezési naplók, a várakozási idővel kapcsolatos problémák jelentései vagy a végrehajtási időre vonatkozó statisztikák segíthetnek azonosítani az optimalizálást igénylő lekérdezéseket.

A lekérdezéstervező által megjelenített egyes mutatók zajnak lehetnek kitéve (különösen a várakozási idő vagy a CPU-idő becslésekor). Az ütemezők jó kiegészítője a végrehajtási útvonal nyomon követésére és nyomon követésére szolgáló eszközök. Lehetővé teszik az ilyen problémák diagnosztizálását (sajnos nem minden DBMS biztosít ilyen eszközöket).

Az online migráció nehéz, de lehetséges

Az online migráció, az élő migráció vagy a valós idejű migráció azt jelenti, hogy egyik adatbázisból a másikba költözik leállás vagy adatsérülés nélkül. Az élő migráció könnyebben végrehajtható, ha az átállás ugyanazon a DBMS-en/motoron belül történik. A helyzet bonyolultabbá válik, ha egy új, eltérő teljesítmény- és sémakövetelményekkel rendelkező DBMS-re kell váltani.

Különféle online migrációs modellek léteznek. Íme az egyik közülük:

  • Engedélyezze a kettős bejegyzést mindkét adatbázisban. Az új adatbázis ebben a szakaszban nem rendelkezik minden adattal, csak a legfrissebb adatokat fogadja el. Ha megbizonyosodott ebben, továbbléphet a következő lépésre.
  • Engedélyezze az olvasást mindkét adatbázisból.
  • Állítsa be a rendszert úgy, hogy az olvasás és írás elsősorban az új adatbázison történjen.
  • Hagyja abba az írást a régi adatbázisba, miközben folytatja az adatok beolvasását. Ebben a szakaszban az új adatbázis még nem tartalmaz néhány adatot. Ezeket a régi adatbázisból kell átmásolni.
  • A régi adatbázis csak olvasható. Másolja át a hiányzó adatokat a régi adatbázisból az újba. Az áttelepítés befejezése után állítsa át az elérési utat az új adatbázisra, állítsa le a régit, és törölje azt a rendszerből.

További információért javaslom a kapcsolatot cikk, amely részletezi a Stripe ezen a modellen alapuló migrációs stratégiáját.

Az adatbázis jelentős növekedése a kiszámíthatatlanság növekedését vonja maga után

Az adatbázis növekedése előre nem látható problémákhoz vezet a méretével kapcsolatban. Minél többet tudunk az adatbázis belső struktúrájáról, annál jobban megjósolhatjuk, hogy milyen méretezésű lesz. Néhány pillanatot azonban még mindig lehetetlen előre látni.
A bázis növekedésével az adatmennyiséggel és a hálózati sávszélességgel kapcsolatos korábbi feltételezések és várakozások elavulhatnak. Ekkor vetődik fel a nagy tervezési átalakítások, a nagyszabású működési fejlesztések, a telepítések újragondolása vagy más DBMS-ekre való migráció kérdése a lehetséges problémák elkerülése érdekében.

De ne gondolja, hogy a meglévő adatbázis belső szerkezetének kiváló ismerete az egyetlen dolog, ami szükséges. Az új mérlegek új ismeretleneket hoznak magukkal. Az előre nem látható fájdalompontok, az egyenetlen adateloszlás, a váratlan sávszélesség- és hardverproblémák, az egyre növekvő forgalom és az új hálózati szegmensek arra kényszerítik Önt, hogy újragondolja az adatbázis-megközelítést, az adatmodellt, a telepítési modellt és az adatbázis méretét.

...

Amikor elkezdtem gondolkodni a cikk közzétételén, már öt további elem volt az eredeti listámon. Aztán jött egy hatalmas szám új ötletek arról, hogy mit lehet még fedezni. Ezért a cikk a legkevésbé nyilvánvaló problémákat érinti, amelyek maximális figyelmet igényelnek. Ez azonban nem jelenti azt, hogy a téma kimerült, és a jövőbeni anyagaimban már nem térek vissza rá, és nem változtatok a jelenlegin.

PS

Olvassa el blogunkon is:

Forrás: will.com

Hozzászólás