Ahojte všetci. Vladislav Rodin je v kontakte. V súčasnosti vediem kurzy softvérovej architektúry a vysokostresovej softvérovej architektúry na OTUS. V očakávaní začiatku nového prúdu kurzu
Úvod
Vzhľadom na to, že HDD dokáže vykonať len okolo 400-700 operácií za sekundu (čo je neporovnateľné s typickými rps na vysoko zaťaženom systéme), je klasická disková databáza prekážkou architektúry. Preto je potrebné venovať osobitnú pozornosť vzorom škálovania tohto úložiska.
V súčasnosti existujú 2 vzory škálovania databázy: replikácia a sharding. Zdieľanie vám umožňuje škálovať operáciu zápisu a v dôsledku toho znížiť rýchlosť otáčok na zápis na server vo vašom klastri. Replikácia vám umožňuje robiť to isté, ale s operáciami čítania. Práve tomuto vzoru je venovaný tento článok.
Replikácia
Ak sa pozriete na replikáciu na veľmi vysokej úrovni, je to jednoduchá vec: mali ste jeden server, boli na ňom údaje a tento server už nezvládal záťaž čítania týchto údajov. Pridáte niekoľko ďalších serverov, zosynchronizujete údaje na všetkých serveroch a používateľ môže čítať z ľubovoľného servera vo vašom klastri.
Napriek zjavnej jednoduchosti existuje niekoľko možností klasifikácie rôznych implementácií tejto schémy:
- Podľa rolí v klastri (master-master alebo master-slave)
- Podľa odoslaných objektov (riadkové, príkazové alebo zmiešané)
- Podľa mechanizmu synchronizácie uzlov
Dnes sa budeme zaoberať bodom 3.
Ako dôjde k potvrdeniu transakcie?
Táto téma priamo nesúvisí s replikáciou, dá sa o nej napísať samostatný článok, ale keďže ďalšie čítanie je zbytočné bez pochopenia mechanizmu potvrdenia transakcie, dovoľte mi pripomenúť najzákladnejšie veci. Potvrdenie transakcie prebieha v 3 fázach:
- Zaznamenávanie transakcie do denníka databázy.
- Použitie transakcie v databázovom stroji.
- Vrátenie potvrdenia klientovi, že transakcia bola úspešne použitá.
V rôznych databázach môže mať tento algoritmus nuansy: napríklad v motore InnoDB databázy MySQL sú 2 protokoly: jeden na replikáciu (binárny protokol) a druhý na udržiavanie ACID (protokol späť/znova), zatiaľ čo v PostgreSQL existuje jeden protokol, ktorý vykonáva obe funkcie (zápis dopredu = WAL). Ale to, čo je uvedené vyššie, je presne všeobecný koncept, ktorý umožňuje, aby sa takéto nuansy nezohľadňovali.
Synchrónna (synchronizovaná) replikácia
Pridajme logiku na replikáciu prijatých zmien do algoritmu potvrdenia transakcie:
- Zaznamenávanie transakcie do denníka databázy.
- Použitie transakcie v databázovom stroji.
- Odosielanie údajov do všetkých replík.
- Prijímanie potvrdenia od všetkých kópií, že transakcia na nich bola dokončená.
- Vrátenie potvrdenia klientovi, že transakcia bola úspešne použitá.
S týmto prístupom máme niekoľko nevýhod:
- klient čaká, kým sa zmeny aplikujú na všetky repliky.
- so zvyšujúcim sa počtom uzlov v klastri znižujeme pravdepodobnosť, že operácia zápisu bude úspešná.
Ak je s 1. bodom všetko viac-menej jasné, tak dôvody 2. bodu stoja za vysvetlenie. Ak počas synchrónnej replikácie nedostaneme odpoveď aspoň z jedného uzla, transakciu vrátime späť. Zvýšením počtu uzlov v klastri teda zvýšite pravdepodobnosť, že operácia zápisu zlyhá.
Môžeme čakať na potvrdenie len od určitého percenta uzlov, napríklad od 51 % (kvórum)? Áno, môžeme, ale v klasickej verzii je potrebné potvrdenie zo všetkých uzlov, pretože takto vieme zabezpečiť úplnú konzistenciu dát v klastri, čo je nepochybnou výhodou tohto typu replikácie.
Asynchrónna (asynchrónna) replikácia
Upravme predchádzajúci algoritmus. Údaje do kópií pošleme „niekedy neskôr“ a „niekedy neskôr“ sa zmeny použijú na repliky:
- Zaznamenávanie transakcie do denníka databázy.
- Použitie transakcie v databázovom stroji.
- Vrátenie potvrdenia klientovi, že transakcia bola úspešne použitá.
- Odosielanie údajov do kópií a uplatňovanie zmien v nich.
Tento prístup vedie k tomu, že klaster funguje rýchlo, pretože klienta nenecháme čakať, kým sa dáta dostanú k replikám a dokonca sa zaviažu.
Ale podmienka uloženia údajov na repliky „niekedy neskôr“ môže viesť k strate transakcie a k strate transakcie potvrdenej používateľom, pretože ak údaje nestihli replikovať, potvrdenie pre klienta o úspešnosti operácie bola odoslaná a uzol, do ktorého prišli zmeny, havaroval HDD, stratíme transakciu, čo môže viesť k veľmi nepríjemným následkom.
Polosynchronizovaná replikácia
Nakoniec sa dostávame k semisynchrónnej replikácii. Tento typ replikácie nie je veľmi známy alebo veľmi bežný, ale je veľmi zaujímavý, pretože môže kombinovať výhody synchrónnej aj asynchrónnej replikácie.
Skúsme spojiť 2 predchádzajúce prístupy. Klienta si nenecháme dlho, ale budeme vyžadovať, aby boli údaje replikované:
- Zaznamenávanie transakcie do denníka databázy.
- Použitie transakcie v databázovom stroji.
- Odosielanie údajov do replík.
- Prijatie potvrdenia z repliky, že zmeny boli prijaté (aplikujú sa „niekedy neskôr“).
- Vrátenie potvrdenia klientovi, že transakcia bola úspešne použitá.
Upozorňujeme, že s týmto algoritmom dôjde k strate transakcie iba vtedy, ak zlyhá uzol prijímajúci zmeny aj uzol repliky. Pravdepodobnosť takéhoto zlyhania sa považuje za nízku a tieto riziká sa akceptujú.
Ale pri tomto prístupe existuje možné riziko fantómového čítania. Predstavme si nasledujúci scenár: v kroku 4 sme nedostali potvrdenie od žiadnej repliky. Túto transakciu musíme vrátiť späť a nevracať klientovi potvrdenie. Keďže údaje boli aplikované v kroku 2, medzi koncom kroku 2 a vrátením transakcie je časová medzera, počas ktorej môžu paralelné transakcie vidieť zmeny, ktoré by nemali byť v databáze.
Polosynchrónna replikácia bez straty
Ak trochu premýšľate, môžete jednoducho obrátiť kroky algoritmu a vyriešiť problém fantómového čítania v tomto scenári:
- Zaznamenávanie transakcie do denníka databázy.
- Odosielanie údajov repliky.
- Prijatie potvrdenia z repliky, že zmeny boli prijaté (aplikujú sa „niekedy neskôr“).
- Použitie transakcie v databázovom stroji.
- Vrátenie potvrdenia klientovi, že transakcia bola úspešne použitá.
Teraz vykonáme zmeny, iba ak boli replikované.
Výkon
Ako vždy neexistujú ideálne riešenia, existuje súbor riešení, z ktorých každé má svoje výhody a nevýhody a je vhodné na riešenie rôznych tried problémov. To platí absolútne pre výber mechanizmu na synchronizáciu údajov v replikovanej databáze. Sada výhod, ktoré má semisynchrónna replikácia, je dostatočne solídna a zaujímavá, že ju možno považovať za hodnú pozornosti, napriek jej nízkej prevalencii.