O databázích by to mělo vědět více vývojářů

Poznámka. přel.: Jaana Dogan je zkušená inženýrka ve společnosti Google, která v současnosti pracuje na pozorovatelnosti produkčních služeb společnosti napsaných v Go. V tomto článku, který si získal velkou oblibu mezi anglicky mluvícím publikem, shromáždila v 17 bodech důležité technické detaily týkající se DBMS (a někdy i distribuovaných systémů obecně), které jsou užitečné pro vývojáře velkých/náročných aplikací.

O databázích by to mělo vědět více vývojářů

Naprostá většina počítačových systémů sleduje svůj stav, a proto vyžaduje nějaký druh systému ukládání dat. Dlouhou dobu jsem shromažďoval znalosti o databázích, přičemž jsem dělal chyby v návrhu, které vedly ke ztrátě dat a výpadkům. V systémech, které zpracovávají velké objemy informací, jsou databáze jádrem systémové architektury a fungují jako klíčový prvek při výběru optimálního řešení. Přestože je práci databáze věnována velká pozornost, problémy, které se vývojáři aplikací snaží předvídat, jsou často jen špičkou ledovce. V této sérii článků sdílím některé nápady, které budou užitečné pro vývojáře, kteří se v této oblasti nespecializují.

  1. Máte štěstí, pokud síť v 99,999 % případů nezpůsobuje problémy.
  2. ACID znamená mnoho různých věcí.
  3. Každá databáze má své vlastní mechanismy pro zajištění konzistence a izolace.
  4. Optimistické blokování přichází na pomoc, když je obtížné udržet obvyklé.
  5. Kromě nečistého čtení a ztráty dat existují další anomálie.
  6. Ne vždy se databáze a uživatel shodnou na postupu.
  7. Sharding na úrovni aplikace lze přesunout mimo aplikaci.
  8. Autoinkrementace může být nebezpečná.
  9. Zastaralá data mohou být užitečná a není třeba je zamykat.
  10. Zkreslení jsou typická pro jakékoli časové zdroje.
  11. Zpoždění má mnoho významů.
  12. Požadavky na výkon by měly být vyhodnoceny pro konkrétní transakci.
  13. Vnořené transakce mohou být nebezpečné.
  14. Transakce by neměly být vázány na stav aplikace.
  15. Plánovači dotazů vám mohou o databázích hodně říct.
  16. Online migrace je obtížná, ale možná.
  17. Výrazný nárůst databáze s sebou nese zvýšení nepředvídatelnosti.

Rád bych poděkoval Emmanuelu Odekeovi, Rein Henrichsovi a dalším za jejich zpětnou vazbu k dřívější verzi tohoto článku.

Máte štěstí, pokud síť v 99,999 % případů nezpůsobuje problémy.

Otázkou zůstává, jak spolehlivé jsou moderní síťové technologie a jak často dochází k výpadkům systémů kvůli výpadkům sítě. Informace o této problematice jsou vzácné a výzkumu často dominují velké organizace se specializovanými sítěmi, vybavením a personálem.

S mírou dostupnosti 99,999 % pro Spanner (globálně distribuovaná databáze Google) Google tvrdí, že pouze 7,6% problémy souvisí se sítí. Svou specializovanou síť přitom společnost nazývá „hlavním pilířem“ vysoké dostupnosti. Studie Bailis a Kingsbury, provedená v roce 2014, zpochybňuje jednu z „mylné představy o distribuovaném počítání“, kterou Peter Deutsch formuloval v roce 1994. Je síť opravdu spolehlivá?

Komplexní výzkum mimo obří společnosti, prováděný pro širší internet, prostě neexistuje. Od hlavních hráčů také není dostatek údajů o tom, jaké procento problémů jejich zákazníků souvisí se sítí. Jsme si dobře vědomi výpadků v síti velkých poskytovatelů cloudu, které mohou na několik hodin zrušit celý kus internetu jen proto, že se jedná o významné události, které ovlivňují velké množství lidí a společností. Výpadky sítě mohou způsobit problémy v mnoha dalších případech, i když ne všechny tyto případy jsou v centru pozornosti. Klienti cloudových služeb také nic nevědí o příčinách problémů. Pokud dojde k poruše, je téměř nemožné připsat ji na vrub síťové chybě na straně poskytovatele služeb. Služby třetích stran jsou pro ně černými skříňkami. Není možné posoudit dopad, aniž byste byli velkým poskytovatelem služeb.

Vzhledem k tomu, co o svých systémech hlásí velcí hráči, lze s jistotou říci, že máte štěstí, pokud potíže se sítí představují pouze malé procento potenciálních problémů s výpadky. Síťová komunikace stále trpí tak světskými věcmi, jako jsou selhání hardwaru, změny topologie, změny administrativní konfigurace a výpadky napájení. Nedávno mě překvapilo, že byl přidán seznam možných problémů žraločí kousnutí (ano, slyšeli jste dobře).

ACID znamená spoustu různých věcí

Zkratka ACID znamená atomicita, konzistence, izolace, spolehlivost. Tyto vlastnosti transakcí mají zajistit jejich platnost v případě selhání, chyb, selhání hardwaru atd. Bez ACID nebo podobných schémat by pro vývojáře aplikací bylo obtížné rozlišit, za co jsou zodpovědní oni a za co je zodpovědná databáze. Většina relačních transakčních databází se snaží být kompatibilní s ACID, ale nové přístupy jako NoSQL daly vzniknout mnoha databázím bez transakcí ACID, protože jejich implementace je nákladná.

Když jsem poprvé vstoupil do tohoto odvětví, náš technický vedoucí hovořil o tom, jak relevantní je koncept ACID. Abychom byli spravedliví, ACID je považován spíše za hrubý popis než za přísný implementační standard. Dnes to považuji za užitečné, protože vyvolává specifickou kategorii problémů (a navrhuje řadu možných řešení).

Ne každý DBMS je kompatibilní s ACID; Zároveň databázové implementace, které podporují ACID, chápou sadu požadavků odlišně. Jedním z důvodů, proč jsou implementace ACID nejednotné, je kvůli mnoha kompromisům, které je třeba provést při implementaci požadavků ACID. Tvůrci mohou prezentovat své databáze jako ACID kompatibilní, ale interpretace hraničních případů se může dramaticky lišit, stejně jako mechanismus pro zpracování „nepravděpodobných“ událostí. Vývojáři mohou přinejmenším na vysoké úrovni porozumět složitosti základních implementací, aby správně porozuměli jejich zvláštnímu chování a kompromisům v designu.

Debata o tom, zda MongoDB splňuje požadavky ACID pokračuje i po vydání verze 4. MongoDB již dlouhou dobu není podporováno protokolování, ačkoli ve výchozím nastavení byla data uložena na disk maximálně jednou za 60 sekund. Představte si následující scénář: aplikace odešle dva zápisy (w1 a w2). MongoDB úspěšně ukládá w1, ale w2 je ztraceno kvůli selhání hardwaru.

O databázích by to mělo vědět více vývojářů
Diagram znázorňující scénář. MongoDB se zhroutí dříve, než může zapisovat data na disk

Potvrzení na disk je nákladný proces. Tím, že se vývojáři vyhýbají častým komisím, zlepšují výkon nahrávání na úkor spolehlivosti. MongoDB v současné době podporuje protokolování, ale nečisté zápisy mohou stále ovlivnit integritu dat, protože protokoly jsou ve výchozím nastavení zachycovány každých 100 ms. To znamená, že podobný scénář je stále možný pro protokoly a změny v nich prezentované, i když riziko je mnohem nižší.

Každá databáze má své vlastní mechanismy konzistence a izolace

Z požadavků ACID se konzistence a izolace mohou pochlubit největším počtem různých implementací, protože rozsah kompromisů je širší. Je třeba říci, že konzistence a izolace jsou docela drahé funkce. Vyžadují koordinaci a zvyšují konkurenci o konzistenci dat. Složitost problému se výrazně zvyšuje, když je nutné horizontálně škálovat databázi napříč více datovými centry (zejména pokud se nacházejí v různých geografických oblastech). Dosažení vysoké úrovně konzistence je velmi obtížné, protože to také snižuje dostupnost a zvyšuje segmentaci sítě. Pro obecnější vysvětlení tohoto jevu vám doporučuji odkázat na CAP věta. Za zmínku také stojí, že aplikace dokážou zvládnout malé množství nekonzistence a programátoři dokážou dostatečně dobře porozumět nuancím problému, aby do aplikace implementovali další logiku pro řešení nekonzistence, aniž by se příliš spoléhali na to, že to zvládne databáze.

DBMS často poskytují různé úrovně izolace. Vývojáři aplikací si mohou vybrat tu nejúčinnější na základě svých preferencí. Nízká izolace umožňuje vyšší rychlost, ale také zvyšuje riziko datového závodu. Vysoká izolace tuto pravděpodobnost snižuje, ale zpomaluje práci a může vést ke konkurenci, která povede k takovým brzdám v základně, že začínají poruchy.

O databázích by to mělo vědět více vývojářů
Přehled existujících modelů souběžnosti a vztahů mezi nimi

Standard SQL definuje pouze čtyři úrovně izolace, i když teoreticky a prakticky jich je mnohem více. Jepson.io nabízí vynikající přehled o existujících souběžných modelech. Například Google Spanner zaručuje externí serializaci se synchronizací hodin, a přestože se jedná o přísnější izolační vrstvu, není definována ve standardních izolačních vrstvách.

Standard SQL zmiňuje následující úrovně izolace:

  • Serializovatelné (nejpřísnější a nejdražší): Serializovatelné provádění má stejný účinek jako provádění některých sekvenčních transakcí. Sekvenční provádění znamená, že každá následující transakce začíná až po dokončení předchozí. Nutno podotknout, že úroveň Serializovatelné často implementována jako takzvaná izolace snímků (například v Oracle) kvůli rozdílům v interpretaci, ačkoli samotná izolace snímků není ve standardu SQL zastoupena.
  • Opakovatelné čtení: Nepotvrzené záznamy v aktuální transakci jsou dostupné pro aktuální transakci, ale změny provedené jinými transakcemi (jako jsou nové řádky) neviditelný.
  • Čtěte odevzdaně: Nepotvrzená data nejsou pro transakce k dispozici. V tomto případě mohou transakce vidět pouze potvrzená data a může dojít k fantomovému čtení. Pokud transakce vloží a potvrdí nové řádky, aktuální transakce je bude moci při dotazu vidět.
  • Číst nezávazně (nejméně přísná a nákladná úroveň): Nečisté čtení jsou povoleny, transakce mohou vidět nepotvrzené změny provedené jinými transakcemi. V praxi může být tato úroveň užitečná pro hrubé odhady, jako jsou dotazy COUNT(*) na stole.

Úroveň Serializovatelné minimalizuje riziko datových závodů, přičemž je nejnákladnější na implementaci a vede k nejvyššímu konkurenčnímu zatížení systému. Jiné úrovně izolace jsou snadněji implementovatelné, ale zvyšují pravděpodobnost datových závodů. Některé DBMS umožňují nastavit vlastní úroveň izolace, jiné mají silné preference a ne všechny úrovně jsou podporovány.

Podpora úrovní izolace je v dané DBMS často inzerována, ale pouze pečlivá studie jejího chování může odhalit, co se skutečně děje.

O databázích by to mělo vědět více vývojářů
Přehled anomálií souběžnosti na různých úrovních izolace pro různé DBMS

Martin Kleppmann ve svém projektu poustevna Porovnává různé úrovně izolace, hovoří o anomáliích souběžnosti a o tom, zda je databáze schopna dodržovat konkrétní úroveň izolace. Kleppmannův výzkum ukazuje, jak rozdílně uvažují vývojáři databází o úrovních izolace.

Optimistické blokování přichází na pomoc, když je obtížné udržet obvyklé.

Blokování může být velmi drahé, nejen proto, že zvyšuje konkurenci v databázi, ale také proto, že vyžaduje, aby se aplikační servery neustále připojovaly k databázi. Segmentace sítě může zhoršit situace výhradního zamykání a vést k uváznutí, které je obtížné identifikovat a vyřešit. V případech, kdy výhradní zamykání není vhodné, pomáhá optimistické zamykání.

Optimistický zámek je metoda, při které se při čtení řetězce bere v úvahu jeho verze, kontrolní součet nebo čas poslední úpravy. To vám umožní zajistit, že před změnou položky nedojde ke změně atomické verze:

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

V tomto případě aktualizujte tabulku products neprovede se, pokud jiná operace dříve provedla změny v tomto řádku. Pokud na tomto řádku nebyly provedeny žádné další operace, dojde ke změně u jednoho řádku a můžeme říci, že aktualizace proběhla úspěšně.

Kromě nečistého čtení a ztráty dat existují další anomálie

Pokud jde o konzistenci dat, důraz je kladen na potenciál pro závody, které mohou vést k nečistým čtením a ztrátě dat. Tím však datové anomálie nekončí.

Jedním z příkladů takových anomálií je zkreslení záznamu (pište zkresleně). Zkreslení je obtížné odhalit, protože se obvykle aktivně nevyhledávají. Nejsou způsobeny nečistými čteními nebo ztrátou dat, ale porušením logických omezení kladených na data.

Vezměme si například monitorovací aplikaci, která vyžaduje, aby byl jeden operátor neustále v pohotovosti:

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;

Ve výše uvedené situaci dojde k poškození záznamu, pokud jsou obě transakce úspěšně potvrzeny. Přestože nedošlo k žádným špinavým čtením nebo ztrátě dat, integrita dat byla narušena: nyní jsou dva lidé považováni za hovory současně.

Serializovatelná izolace, návrh schématu nebo omezení databáze mohou pomoci eliminovat poškození zápisu. Vývojáři musí být schopni identifikovat takové anomálie během vývoje, aby se jim ve výrobě vyhnuli. Přitom zkreslení záznamu se v kódové základně hledá extrémně obtížně. Zejména ve velkých systémech, kdy různé vývojové týmy odpovídají za implementaci funkcí založených na stejných tabulkách a neshodnou se na specifikách přístupu k datům.

Databáze a uživatel se ne vždy shodnou na tom, co dělat

Jednou z klíčových vlastností databází je garance provedení příkazu, ale tento příkaz sám o sobě nemusí být pro vývojáře softwaru transparentní. Databáze provádějí transakce v pořadí, v jakém byly přijaty, nikoli v pořadí, v jakém zamýšlejí programátoři. Pořadí transakcí je obtížné předvídat, zejména ve vysoce zatížených paralelních systémech.

Během vývoje, zejména při práci s neblokujícími knihovnami, může špatný styl a nízká čitelnost způsobit, že uživatelé budou věřit, že transakce jsou prováděny postupně, i když ve skutečnosti mohou do databáze dorazit v libovolném pořadí.

Na první pohled jsou v programu níže T1 a T2 volány postupně, ale pokud jsou tyto funkce neblokující a okamžitě vrátí výsledek ve tvaru slib, pak bude pořadí hovorů určeno okamžiky, kdy vstoupily do databáze:

výsledek1 = T1() // skutečné výsledky jsou sliby
výsledek2 = T2()

Pokud je vyžadována atomičnost (to znamená, že buď všechny operace musí být dokončeny nebo přerušeny) a záleží na pořadí, musí být operace T1 a T2 provedeny v rámci jedné transakce.

Sharding na úrovni aplikace lze přesunout mimo aplikaci

Sharding je metoda horizontálního rozdělení databáze. Některé databáze dokážou automaticky horizontálně rozdělit data, zatímco jiné ne, nebo v tom nejsou příliš dobré. Když jsou datoví architekti/vývojáři schopni přesně předpovědět, jak bude k datům přistupováno, mohou vytvořit horizontální oddíly v uživatelském prostoru namísto delegování této práce na databázi. Tento proces se nazývá „sharding na úrovni aplikace“ (sharding na úrovni aplikace).

Bohužel tento název často vytváří mylnou představu, že sharding žije v aplikačních službách. Ve skutečnosti může být implementován jako samostatná vrstva před databází. V závislosti na růstu dat a iteracích schématu mohou být požadavky na sdílení poměrně složité. Některé strategie mohou těžit ze schopnosti iterace bez nutnosti znovu nasazovat aplikační servery.

O databázích by to mělo vědět více vývojářů
Příklad architektury, ve které jsou aplikační servery odděleny od služby sdílení

Přesunutím shardingu do samostatné služby se rozšiřuje možnost používat různé strategie shardingu bez nutnosti opětovného nasazení aplikací. Vitess je příkladem takového systému shardingu na aplikační úrovni. Vites poskytuje horizontální sharding pro MySQL a umožňuje klientům připojit se k němu prostřednictvím protokolu MySQL. Systém segmentuje data do různých uzlů MySQL, které o sobě nic nevědí.

Autoinkrementace může být nebezpečná

AUTOINCREMENT je běžný způsob generování primárních klíčů. Často se vyskytují případy, kdy jsou databáze použity jako generátory ID a databáze obsahuje tabulky určené ke generování identifikátorů. Existuje několik důvodů, proč generování primárních klíčů pomocí automatického inkrementování není zdaleka ideální:

  • V distribuované databázi je auto-inkrementace vážným problémem. Pro vygenerování ID je vyžadován globální zámek. Místo toho můžete vygenerovat UUID: to nevyžaduje interakci mezi různými uzly databáze. Automatické zvyšování pomocí zámků může způsobit spory a výrazně snížit výkon vložek v distribuovaných situacích. Některé DBMS (například MySQL) mohou vyžadovat speciální konfiguraci a větší pozornost, aby bylo možné správně organizovat replikaci master-master. A při konfiguraci je snadné dělat chyby, které povedou k selhání nahrávání.
  • Některé databáze mají rozdělovací algoritmy založené na primárních klíčích. Po sobě jdoucí ID mohou vést k nepředvídatelným aktivním bodům a zvýšenému zatížení některých oddílů, zatímco jiné zůstávají nečinné.
  • Primární klíč je nejrychlejší způsob přístupu k řádku v databázi. Díky lepším způsobům identifikace záznamů mohou sekvenční ID změnit nejdůležitější sloupec v tabulkách na zbytečný sloupec plný nesmyslných hodnot. Proto, kdykoli je to možné, zvolte globálně jedinečný a přirozený primární klíč (např. uživatelské jméno).

Než se rozhodnete pro přístup, zvažte dopad automatického zvyšování ID a UUID na indexování, dělení a sdílení.

Zastaralá data mohou být užitečná a nevyžadují zamykání

Multiversion Concurrency Control (MVCC) implementuje mnoho požadavků na konzistenci, které byly stručně popsány výše. Některé databáze (například Postgres, Spanner) používají MVCC k „krmení“ transakcí se snímky – starší verze databáze. Snapshot transakce lze také serializovat, aby byla zajištěna konzistence. Při čtení ze starého snímku se čtou zastaralá data.

Čtení mírně zastaralých dat může být užitečné například při generování analytiky z dat nebo při výpočtu přibližných agregovaných hodnot.

První výhodou práce se staršími daty je nízká latence (zejména pokud je databáze distribuována v různých geografických oblastech). Druhým je, že transakce pouze pro čtení jsou bez zámku. To je značná výhoda pro aplikace, které hodně čtou, pokud si poradí se zastaralými daty.

O databázích by to mělo vědět více vývojářů
Aplikační server čte data z místní repliky, která je 5 sekund zastaralá, i když je nejnovější verze dostupná na druhé straně Tichého oceánu.

Systémy DBMS automaticky vyčistí starší verze a v některých případech vám to umožní na požádání. To uživatelům umožňuje například Postgres VACUUM na požádání a také pravidelně provádí tuto operaci automaticky. Spanner provozuje garbage collector, aby se zbavil snímků starších než jedna hodina.

Jakékoli časové zdroje podléhají zkreslení

Nejlépe střeženým tajemstvím informatiky je, že všechna časovací API lžou. Ve skutečnosti naše stroje neznají přesný aktuální čas. Počítače obsahují křemenné krystaly, které generují vibrace, které se používají k udržení času. Nejsou však dostatečně přesné a mohou být napřed/zaostávat za přesným časem. Směna může dosáhnout 20 sekund za den. Čas na našich počítačích proto musí být pravidelně synchronizován s tím síťovým.

K synchronizaci se používají servery NTP, ale samotný proces synchronizace podléhá síťovým zpožděním. I synchronizace se serverem NTP ve stejném datovém centru nějakou dobu trvá. Je jasné, že práce s veřejným NTP serverem může vést k ještě většímu zkreslení.

Pro určování aktuálního času jsou lepší atomové hodiny a jejich GPS protějšky, které jsou však drahé a vyžadují složité nastavení, nelze je tedy nainstalovat do každého auta. Z tohoto důvodu datová centra používají víceúrovňový přístup. Atomové a/nebo GPS hodiny ukazují přesný čas, po kterém jsou vysílány do dalších strojů prostřednictvím sekundárních serverů. To znamená, že každý stroj zažije určitý posun od přesného času.

Situaci zhoršuje fakt, že aplikace a databáze jsou často umístěny na různých strojích (ne-li v různých datových centrech). Čas se tedy bude lišit nejen na DB uzlech distribuovaných na různých strojích. Na aplikačním serveru to bude také jiné.

Google TrueTime má úplně jiný přístup. Většina lidí věří, že pokrok Googlu v tomto směru je vysvětlen banálním přechodem na atomové a GPS hodiny, ale to je jen část celkového obrazu. TrueTime funguje takto:

  • TrueTime využívá dva různé zdroje: GPS a atomové hodiny. Tyto hodiny mají nekorelované režimy selhání. [viz strana 5 pro podrobnosti zde - Cca. překlad.), takže jejich společné použití zvyšuje spolehlivost.
  • TrueTime má neobvyklé API. Vrací čas jako interval s integrovanou chybou měření a nejistotou. Skutečný časový okamžik je někde mezi horní a dolní hranicí intervalu. Spanner, distribuovaná databáze společnosti Google, jednoduše čeká, až bude možné bezpečně říci, že aktuální čas je mimo rozsah. Tato metoda vnáší do systému určitou latenci, zejména pokud je nejistota na masterech vysoká, ale zajišťuje správnost i v globálně distribuované situaci.

O databázích by to mělo vědět více vývojářů
Komponenty Spanner používají TrueTime, kde TT.now() vrací interval, takže Spanner jednoduše spí až do bodu, kdy si může být jistý, že aktuální čas uplynul určitým bodem.

Snížená přesnost určování aktuálního času znamená prodloužení doby trvání operací Spanner a snížení výkonu. Proto je důležité zachovat nejvyšší možnou přesnost, i když není možné získat zcela přesné hodinky.

Zpoždění má mnoho významů

Když se zeptáte tuctu odborníků na to, co je zpoždění, pravděpodobně dostanete různé odpovědi. V DBMS se latence často nazývá „databázová latence“ a liší se od toho, co vnímá klient. Faktem je, že klient dodržuje součet zpoždění sítě a zpoždění databáze. Schopnost izolovat typ latence je kritická při ladění rostoucích problémů. Při shromažďování a zobrazování metrik se vždy snažte sledovat oba typy.

Požadavky na výkon by měly být vyhodnoceny pro konkrétní transakci

Někdy jsou výkonnostní charakteristiky DBMS a jeho omezení specifikovány z hlediska propustnosti zápisu/čtení a latence. To poskytuje obecný přehled klíčových parametrů systému, ale při hodnocení výkonu nového DBMS je mnohem komplexnějším přístupem samostatné vyhodnocení kritických operací (pro každý dotaz a/nebo transakci). Příklady:

  • Propustnost zápisu a latence při vkládání nového řádku do tabulky X (s 50 miliony řádků) se zadanými omezeními a odsazením řádků v souvisejících tabulkách.
  • Zpoždění zobrazení přátel přátel určitého uživatele, když je průměrný počet přátel 500.
  • Latence při načítání 100 nejlepších záznamů z historie uživatele, když uživatel sleduje 500 dalších uživatelů s X záznamů za hodinu.

Vyhodnocení a experimentování může zahrnovat takové kritické případy, dokud si nebudete jisti, že databáze splňuje požadavky na výkon. Podobné pravidlo bere toto rozdělení v úvahu také při shromažďování metrik latence a určování SLO.

Buďte si vědomi vysoké mohutnosti při shromažďování metrik pro každou operaci. Použijte protokoly, shromažďování událostí nebo distribuované trasování k získání vysoce výkonných ladicích dat. V článku "Chcete ladit latenci?» se můžete seznámit s metodikami ladění zpoždění.

Vnořené transakce mohou být nebezpečné

Ne každý DBMS podporuje vnořené transakce, ale když ano, mohou takové transakce vést k neočekávaným chybám, které není vždy snadné odhalit (to znamená, že by mělo být zřejmé, že existuje nějaký druh anomálie).

Můžete se vyhnout používání vnořených transakcí pomocí klientských knihoven, které je dokážou detekovat a obejít. Pokud nelze vnořené transakce opustit, věnujte jejich implementaci zvláštní pozornost, abyste předešli neočekávaným situacím, kdy jsou dokončené transakce náhodně přerušeny kvůli vnořeným transakcím.

Zapouzdření transakcí do různých vrstev může vést k neočekávaným vnořeným transakcím a z hlediska čitelnosti kódu může být obtížné pochopit záměry autora. Podívejte se na následující program:

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

Jaký bude výstup výše uvedeného kódu? Vrátí zpět obě transakce, nebo jen tu vnitřní? Co se stane, když se spoléháme na více vrstev knihoven, které za nás zapouzdřují vytváření transakcí? Budeme schopni takové případy identifikovat a zlepšit?

Představte si datovou vrstvu s více operacemi (např. newAccount) je již implementován ve vlastních transakcích. Co se stane, když je spustíte jako součást obchodní logiky vyšší úrovně, která běží v rámci vlastní transakce? Jaká by byla v tomto případě izolace a konzistence?

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

Místo hledání odpovědí na takové nekonečné otázky je lepší se vnořeným transakcím vyhnout. Vaše datová vrstva totiž může snadno provádět operace na vysoké úrovni bez vytváření vlastních transakcí. Kromě toho je obchodní logika sama o sobě schopna iniciovat transakci, provádět s ní operace, provést nebo zrušit transakci.

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.

Transakce by neměly být vázány na stav aplikace

Někdy je lákavé použít stav aplikace v transakcích ke změně určitých hodnot nebo vyladění parametrů dotazu. Kritickou nuancí, kterou je třeba zvážit, je správný rozsah použití. Klienti často restartují transakce, když se vyskytnou problémy se sítí. Pokud pak transakce závisí na stavu, který je měněn nějakým jiným procesem, může zvolit špatnou hodnotu v závislosti na možnosti datového závodu. Transakce musí brát v úvahu riziko datových závodů v aplikaci.

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

Výše uvedená transakce zvýší pořadové číslo pokaždé, když je provedena, bez ohledu na konečný výsledek. Pokud se potvrzení nezdaří kvůli problémům se sítí, požadavek bude při dalším pokusu proveden s jiným pořadovým číslem.

Plánovači dotazů vám mohou o databázi hodně říct

Plánovače dotazů určují, jak bude dotaz v databázi proveden. Také analyzují požadavky a optimalizují je před jejich odesláním. Plánovači mohou poskytnout pouze některé možné odhady na základě signálů, které mají k dispozici. Jaká je například nejlepší metoda vyhledávání pro následující dotaz?

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

Výsledky lze získat dvěma způsoby:

  • Kompletní skenování stolu: Můžete se podívat na každý záznam v tabulce a vrátit články s odpovídajícím jménem autora a pak si je objednat.
  • Indexové skenování: Pomocí indexu můžete najít odpovídající ID, získat tyto řádky a pak je seřadit.

Úkolem plánovače dotazů je určit, která strategie je nejlepší. Stojí za zvážení, že plánovače dotazů mají pouze omezené prediktivní schopnosti. To může vést ke špatným rozhodnutím. DBA nebo vývojáři je mohou použít k diagnostice a doladění nedostatečně výkonných dotazů. Nové verze DBMS mohou konfigurovat plánovače dotazů a autodiagnostika může pomoci při aktualizaci databáze, pokud nová verze vede k problémům s výkonem. Pomalé protokoly dotazů, hlášení problémů s latencí nebo statistiky doby provádění mohou pomoci identifikovat dotazy, které vyžadují optimalizaci.

Některé metriky prezentované plánovačem dotazů mohou podléhat šumu (zejména při odhadu latence nebo času CPU). Dobrým doplňkem plánovačů jsou nástroje pro trasování a sledování cesty provádění. Umožňují vám diagnostikovat takové problémy (bohužel ne všechny DBMS takové nástroje poskytují).

Online migrace je obtížná, ale možná

Online migrace, migrace za provozu nebo migrace v reálném čase znamená přesun z jedné databáze do druhé bez výpadků nebo poškození dat. Živá migrace se snáze provádí, pokud k přechodu dochází v rámci stejného DBMS/enginu. Situace se zkomplikuje, když je nutné přejít na nový DBMS s jinými požadavky na výkon a schéma.

Existují různé modely online migrace. Zde je jeden z nich:

  • Povolit dvojité zadávání v obou databázích. Nová databáze v této fázi nemá všechna data, ale přijímá pouze nejnovější data. Jakmile si tím budete jisti, můžete přejít k dalšímu kroku.
  • Povolit čtení z obou databází.
  • Nakonfigurujte systém tak, aby čtení a zápis probíhaly primárně v nové databázi.
  • Zastavte zápis do staré databáze a pokračujte ve čtení dat z ní. V této fázi nová databáze stále postrádá některá data. Měly by být zkopírovány ze staré databáze.
  • Stará databáze je pouze pro čtení. Zkopírujte chybějící data ze staré databáze do nové. Po dokončení migrace změňte cesty k nové databázi a zastavte starou a odstraňte ji ze systému.

Pro další informace doporučuji kontaktovat článek, který podrobně popisuje strategii migrace společnosti Stripe založenou na tomto modelu.

Výrazný nárůst databáze s sebou nese zvýšení nepředvídatelnosti

Růst databáze vede k nepředvídatelným problémům spojeným s jejím rozsahem. Čím více víme o vnitřní struktuře databáze, tím lépe můžeme předvídat, jak se bude škálovat. Některé okamžiky však stále nelze předvídat.
Jak základna roste, předchozí předpoklady a očekávání týkající se objemu dat a požadavků na šířku pásma sítě mohou být zastaralé. Tehdy vyvstává otázka zásadních přepracování návrhu, rozsáhlých provozních vylepšení, přehodnocení nasazení nebo migrace na jiné DBMS, aby se předešlo potenciálním problémům.

Nemyslete si ale, že výborná znalost vnitřní struktury stávající databáze je to jediné, co je nutné. Nové váhy s sebou přinesou nové neznámé. Nepředvídatelné bolestivé body, nerovnoměrná distribuce dat, neočekávané problémy s šířkou pásma a hardwarem, stále rostoucí provoz a nové segmenty sítě vás donutí přehodnotit přístup k databázi, datový model, model nasazení a velikost databáze.

...

V době, kdy jsem začal uvažovat o zveřejnění tohoto článku, bylo na mém původním seznamu již pět dalších položek. Pak přišlo obrovské číslo nové nápady o tom, co dalšího lze pokrýt. Proto se článek dotýká těch nejméně zjevných problémů, které vyžadují maximální pozornost. Neznamená to však, že téma bylo vyčerpáno a již se k němu ve svých budoucích materiálech nebudu vracet a neprovedu změny toho současného.

PS

Přečtěte si také na našem blogu:

Zdroj: www.habr.com

Přidat komentář