Na internetu je spousta článků popisujících vzory škálovatelnosti databáze, ale většinou se jedná o roztroušené články – jen techniky, které jsou definovány nahodile bez velkého kontextu. Zjistil jsem, že nejsou definovány krok za krokem, a nediskutuji o tom, kdy zvolit kterou možnost škálování, které možnosti škálování jsou v praxi proveditelné a proč.
Proto plánuji některé techniky podrobně probrat v budoucích článcích. Pro začátek mám pocit, že je lepší, když proberu techniky krok za krokem s určitým kontextem svým vlastním způsobem. Tento článek je článek na vysoké úrovni — nebudu zde podrobně rozebírat techniky škálování, ale poskytnu přehled. Tak pojďme začít.
Případová studie
Předpokládejme, že jste vybudovali startup, který nabízí sdílení jízdy za nízkou cenu. Zpočátku, když začínáte, zacílíte na město a po počáteční reklamě máte sotva desítky zákazníků.
Všechny zákazníky, cesty, místa, údaje o rezervacích a historii cest zákazníků uložíte do stejné databáze nebo s největší pravděpodobností do jediného fyzického stroje. Neexistuje žádné luxusní ukládání do mezipaměti nebo velký datový kanál k řešení problémů, protože vaše aplikace je velmi nová. To je v tuto chvíli ideální pro váš případ použití, protože je zde velmi málo zákazníků a váš systém například stěží zarezervuje 1 cestu za 5 minut.
Ale jak čas plyne, do vašeho systému se začíná přihlašovat více lidí, protože jste nejlevnější službou na trhu a díky vaší propagaci a reklamám. Začnete rezervovat řekněme 10 rezervací za minutu a pomalu se číslo zvyšuje na 20, 30 rezervací za minutu.
V tomto okamžiku si uvědomíte, že systém začal fungovat špatně:latence API se hodně zvýšila a některé transakce uvázly nebo hladověly a nakonec selžou. Reakce vaší aplikace trvá déle, což způsobuje nespokojenost zákazníků. Co můžete udělat pro vyřešení problému?
Vzor 1 – Optimalizace dotazů a implementace fondu připojení:
První řešení, které mě napadá, je, že mezipaměť často používá nedynamická data, jako je historie rezervací, historie plateb, uživatelské profily a tak dále. Ale po tomto ukládání do mezipaměti aplikační vrstvy nemůžete vyřešit problém s latencí rozhraní API odhalujících dynamická data, jako je aktuální poloha řidiče nebo nejbližší taxíky pro daného zákazníka nebo aktuální náklady na cestu v určitém okamžiku po zahájení cesty.
Zjistíte, že vaše databáze je pravděpodobně silně normalizována, takže zavedete některé nadbytečné sloupce (tyto sloupce se často objevují v WHERE
nebo JOIN ON
klauzule v dotazech) ve velmi používaných tabulkách z důvodu denormalizace. To snižuje počet spojovacích dotazů, rozděluje velký dotaz na několik menších dotazů a sčítá jejich výsledky v aplikační vrstvě.
Další paralelní optimalizací, kterou můžete udělat, je vyladění databázových připojení. Databázové klientské knihovny a externí knihovny jsou dostupné téměř ve všech programovacích jazycích. Knihovny fondu připojení můžete použít k ukládání databázových připojení do mezipaměti nebo můžete nakonfigurovat velikost fondu připojení v samotném systému správy databází.
Vytvoření jakéhokoli síťového připojení je nákladné, protože vyžaduje určitou komunikaci mezi klientem a serverem. Sdružování připojení vám může pomoci optimalizovat počet připojení. Knihovny fondu připojení vám mohou pomoci s multiplexováním připojení – více vláken aplikace může používat stejné připojení k databázi. Uvidím, jestli mohu později v samostatném článku podrobně vysvětlit sdružování připojení.
Změřte latenci vašich API a najděte pravděpodobně 20–50 % nebo více sníženou latenci. V tomto okamžiku je to dobrá optimalizace.
Nyní jste rozšířili své podnikání o jedno další město, přihlásilo se více zákazníků, pomalu začínáte provádět 80–100 rezervací za minutu. Váš systém není schopen toto měřítko zvládnout. Opět vidíte, že latence API se zvýšila, databázová vrstva se vzdala, ale tentokrát vám žádná optimalizace dotazů nepřináší žádný významný nárůst výkonu. Zkontrolujete systémovou metriku, zjistíte, že místo na disku je téměř plné, CPU je zaneprázdněno 80 % času, RAM se zaplňuje velmi rychle.
Vzor 2 – Vertikální škálování nebo škálování:
Po prozkoumání všech systémových metrik víte, že neexistuje jiné snadné řešení než upgrade hardwaru systému. Velikost paměti RAM upgradujete 2krát, místo na disku řekněme 3krát nebo více. Toto se nazývá vertikální škálování nebo škálování vašeho systému. Informujete svůj tým pro infrastrukturu nebo vývojový tým nebo agenty datového centra třetí strany, aby upgradovali váš počítač.
Jak ale nastavíte stroj pro vertikální škálování?
Přidělujete větší stroj. Jedním z přístupů je nemigrovat data ručně ze starého počítače, ale nastavit nový počítač jako replica
na stávající stroj (primary
)-vytvořit dočasnou primary replica
konfigurace. Nechte replikaci probíhat přirozeně. Po dokončení replikace povýšte nový počítač na primární a přepněte starší počítač do režimu offline. Vzhledem k tomu, že se očekává, že větší stroj obslouží všechny požadavky, veškeré čtení/zápis proběhne na tomto stroji.
Chladný. Váš systém je opět v provozu se zvýšeným výkonem.
Vaše firma si vede velmi dobře a vy se rozhodnete rozšířit na 3 další města – nyní působíte celkem v 5 městech. Provoz je 3x vyšší než dříve, očekává se, že provedete přibližně 300 rezervací za minutu. Ještě než dosáhnete této cílové rezervace, opět se dostanete do kritického stavu, velikost indexu databáze se v paměti výrazně zvětšuje, potřebuje neustálou údržbu, skenování tabulek s indexem je stále pomalejší než kdy jindy. Vypočítáte náklady na další rozšíření stroje, ale nejste přesvědčeni o nákladech. Co teď děláš?
Vzor 3 – Segregace odpovědnosti za příkazový dotaz (CQRS):
Zjistíte, že velký stroj není schopen zpracovat veškeré read/write
žádosti. Ve většině případů také každá společnost potřebuje transakční schopnost write
ale ne na read
operace. Také vám vyhovuje trochu nekonzistentní nebo opožděné read
operace a vaše firma s tím také nemá problém. Vidíte příležitost, kdy by mohlo být dobrou možností oddělit read
&write
operace fyzické strojově. Vytvoří prostor pro jednotlivé stroje, aby zvládly více read/write
operace.
Nyní vezmete dva další velké stroje a nastavíte je jako replica
k aktuálnímu stroji. Replikace databáze se postará o distribuci dat z primary
stroj na replica
stroje. Procházíte všechny čtené dotazy (Query (Q
) v CQRS
) k replikám — jakékoli replica
může obsloužit jakýkoli požadavek na čtení, můžete procházet všechny dotazy pro zápis (Command (C
) v CQRS
) na primary
. V replikaci může dojít k malému zpoždění, ale podle vašeho obchodního případu je to v pořádku.
Většina středně velkých startupů, které každý den obsluhují několik stovek tisíc požadavků, může přežít s nastavením primární repliky za předpokladu, že budou pravidelně archivovat starší data.
Nyní přejdete na další 2 města a uvidíte, že je to vaše primary
není schopen zpracovat všechny write
žádosti. Mnoho write
požadavky mají latenci. Navíc zpoždění mezi primary
&replica
někdy má dopad na zákazníky a řidiče – ex – když cesta skončí, zákazník řidiči úspěšně zaplatí, ale řidič platbu nevidí, protože aktivita zákazníka je write
požadavek, který jde na primary
, zatímco aktivita řidiče je read
požadavek, který jde do jedné z replik. Váš celkový systém je tak pomalý, že řidič nevidí platbu alespoň půl minuty, což je frustrující pro řidiče i zákazníka. Jak to vyřešíte?
Vzor 4 – více primární replikace
S primary-replica
jste škálovali opravdu dobře konfiguraci, ale nyní potřebujete vyšší výkon zápisu. Možná jste připraveni udělat malý kompromis ohledně read
požadovat plnění. Proč nedistribuovat požadavek na zápis do replica
také?
V multi-primary
konfigurace, všechny stroje mohou fungovat jako primary
&replica
. Můžete si představit multi-primary
jako kruh strojů říká A->B->C->D->A
. B
může replikovat data z A
, C
může replikovat data z B
, D
dokáže replikovat data z C
, A
dokáže replikovat data z D
. Data můžete zapisovat do libovolného uzlu, při čtení dat můžete dotaz vysílat do všech uzlů, kdo odpoví, to vrátí. Všechny uzly budou mít stejné schéma databáze, stejnou sadu tabulek, index atd. Musíte se tedy ujistit, že v id
nedochází ke kolizi mezi uzly ve stejné tabulce, jinak by během vysílání více uzlů vracelo různá data pro stejné id
.
Obecně je lepší použít UUID
nebo GUID
pro id. Další nevýhodou této techniky je — read
dotazy mohou být neefektivní, protože zahrnují vysílaný dotaz a získání správného výsledku – v podstatě metoda shromažďování rozptylu.
Nyní přejdete na dalších 5 měst a váš systém je znovu v bolestech. Očekává se, že zpracujete zhruba 50 požadavků za sekundu. Zoufale potřebujete vyřídit velké množství souběžných požadavků. Jak toho dosáhnete?
Vzor 5 – Rozdělení:
Víte, že vaše location
databáze je něco, co je stále více write
&read
provoz. Pravděpodobně write:read
poměr je 7:3
. To vytváří velký tlak na stávající databáze. location
tabulky obsahují několik primárních dat, jako je longitude
, latitude
, timestamp
, driver id
, trip id
atd. Nemá to mnoho společného s cestami uživatelů, uživatelskými údaji, platebními údaji atd. Co takhle oddělit location
tabulky v samostatném schématu databáze? Co takhle umístit tuto databázi na samostatné počítače se správnou primary-replica
nebo multi-primary
konfigurace?
Toto se nazývá rozdělení dat podle funkčnosti. Různé databáze mohou hostit data kategorizovaná podle různých funkcí, v případě potřeby lze výsledek agregovat v zadní vrstvě. Pomocí této techniky se můžete zaměřit na dobré škálování těch funkcí, které vyžadují vysoké read/write
žádosti. Ačkoli back-end nebo aplikační vrstva musí převzít odpovědnost za spojení výsledků, když je to nutné, což pravděpodobně povede k dalším změnám kódu.
Nyní si představte, že jste rozšířili své podnikání do celkem 20 měst ve vaší zemi a plánujete brzy expandovat do Austrálie. Vaše rostoucí poptávka po aplikaci vyžaduje rychlejší a rychlejší odezvu. Žádná z výše uvedených metod vám nyní nemůže pomoci do extrému. Svůj systém musíte škálovat takovým způsobem, aby rozšíření do jiných zemí/oblastí vždy nevyžadovalo časté změny inženýrství nebo architektury. Jak to uděláte?
Vzor 6 – Horizontální měřítko:
Hodně googlujete, hodně čtete o tom, jak problém vyřešily jiné společnosti – a dojdete k závěru, že potřebujete horizontální měřítko. Přidělíte řekněme 50 počítačů – všechny mají stejné schéma databáze, které zase obsahuje stejnou sadu tabulek. Všechny stroje uchovávají pouze část dat.
Protože všechny databáze obsahují stejnou sadu tabulek, můžete systém navrhnout tak, aby tam byla lokalita dat, tj. všechna související data přistanou na stejném stroji. Každý stroj může mít své vlastní repliky, repliky lze použít při obnově selhání. Každá z databází se nazývá shard
. Fyzický počítač může mít jeden nebo více shards
- záleží na vašem návrhu, jak chcete. Musíte se rozhodnout pro sharding key
takovým způsobem, že jeden sharding key
vždy odkazuje na stejný stroj. Můžete si tedy představit spoustu strojů, které všechny uchovávají související data ve stejné sadě tabulek, read/write
požadavky na stejný řádek nebo stejnou sadu zdrojů přistanou na stejném databázovém počítači.
Sharding je obecně těžký – alespoň to tvrdí inženýři z různých společností. Ale když obsluhujete miliony nebo miliardy žádostí, musíte učinit tak těžké rozhodnutí.
Budu diskutovat o sharding
podrobněji v mém dalším příspěvku, takže zadržuji pokušení diskutovat více v tomto příspěvku.
Nyní, když máte sharding na místě, jste si jisti, že můžete škálovat do mnoha zemí. Vaše podnikání se rozrostlo natolik, že vás investoři tlačí k rozšíření podnikání napříč kontinenty. Opět zde vidíte nějaký problém. Opět latence API. Vaše služba je hostována v USA a lidé z Vietnamu mají potíže s rezervací jízd. Proč? Co s tím uděláte?
Vzor 7 – Datové centrum Wise Partition:
Vaše podnikání roste v Americe, jižní Asii a v několika zemích v Evropě. Provádíte miliony rezervací denně s miliardami požadavků na váš server. Gratulujeme – toto je vrcholný okamžik pro vaše podnikání.
Ale protože požadavky z aplikace musí cestovat napříč kontinenty přes stovky nebo tisíce serverů na internetu, dochází ke zpoždění. Jak je to s distribucí provozu mezi datová centra? V Singapuru můžete zřídit datové centrum, které zpracuje všechny požadavky z jižní Asie, datové centrum v Německu zvládne všechny požadavky z evropských zemí a datové centrum v Kalifornii může zpracovat všechny požadavky z USA.
Také povolíte replikaci mezi datovými centry, která pomáhá při obnově po havárii. Pokud tedy kalifornské datové centrum provede replikaci do singapurského datového centra, v případě havárie kalifornského datového centra kvůli problémům s elektřinou nebo přírodní pohromou mohou všechny požadavky z USA vrátit datovému centru v Singapuru a tak dále.
Tato technika škálování je užitečná, když máte miliony zákazníků, které obsluhujete v různých zemích, a nemůžete se vyrovnat se ztrátou dat, musíte vždy udržovat dostupnost systému.
Toto jsou některé obecné techniky krok za krokem pro škálování databáze. Většina inženýrů sice nemá dostatek šancí tyto techniky implementovat, ale jako celek je lepší získat o takovém systému širší představu, která vám v budoucnu může pomoci k lepšímu navrhování systémů a architektury.
Ve svých dalších článcích se pokusím některé pojmy probrat podrobně. Neváhejte poskytnout vhodnou zpětnou vazbu k tomuto příspěvku, pokud existuje.
Článek je původně publikován na autorově médiu:https://medium.com/@kousiknath/understanding-database-scaling-patterns-ac24e5223522