Tere kõigile. Olen Vladislav Rodin. Praegu õpetan OTUS platvormil kursusi, mis käsitlevad tarkvaraarhitektuuri ja kõrge koormusega tarkvaraarhitektuuri. Uue kursuse rühma käivitamise eel. otsustasin kirjutada lühikese eksklusiivmaterjali, millega tahan teiega jagada.

Sissejuhatus
Kuna HDD-l saab sooritada vaid umbes 400-700 operatsiooni sekundis (mis on võrreldamatu tüüpiliste rps-idega, mis langevad kõrge koormusega süsteemile), on klassikaline diskibaas andmebaasi arhitektuuri kitsaskohaks. Seetõttu tuleb erilist tähelepanu pöörata selle salvestusruumi skaala mustritele.
Praegu on kaks andmebaasi skaleerimise mustrit: replikatsioon ja shardimine. Shardimine võimaldab skaleerida kirjutamisoperatsioone ning seeläbi vähendada rps-i, mis langeb ühe serveri mingsesse klastrisse. Replikatsioon võimaldab teha sama lugemisoperatsioonidega. Just sellele mustrile on pühendatud käesolev artikkel.
Replikatsioon
Kui vaadata replikatsiooni täiesti üldiselt, siis on see lihtne asi: teil oli üks server, kus olid andmed, ja siis see server lõpetas nende andmete lugemiseks koormuse talumise. Te lisate veel paar serverit, sünkroonite andmed kõigis serverites ja kasutaja saab lugeda teie klastrist mis tahes serverist.
Hoolimata näilisest lihtsusest on mitmeid variante, kuidas klassifitseerida erinevaid rakendusi sellele skeemile:
- Klastri rollide järgi (master-master või master-slave)
- Saadetavate objektide järgi (ridade põhjal, lause põhjal või segatud)
- Sõlmede sünkroonimismehhanismi järgi
Täna keskendume just kolmandale punktile.
Kuidas toimub tehingu kommitimine
See teema ei ole otseselt seotud replikatsiooniga, sellest võiks kirjutada eraldi artikli, kuid kuna tehingu kommitimise mehhanismi mõistmata on edasine lugemine kasutu, luban endale meenutada kõige olulisemaid aspekte. Tehingu kommitimine toimub kolmes etapis:
- Tehingu salvestamine andmebaasi žurnali.
- Tehingu rakendamine andmebaasi mootori poolt.
- Kliendile kinnituse saatmine tehingu eduka rakendamise kohta.
Erinevates andmetes võib selle algoritmi puhul esineda nüansse: näiteks MySQL InnoDB mootoris on 2 logifaili: üks replikatsiooni jaoks (binary log) ja teine ACIDi säilitamiseks (undo/red log), samas kui PostgreSQL-is on üks log, mis täidab mõlemat funktsiooni (write ahead log = WAL). Ülal on esitatud just üldine kontseptsioon, mis võimaldab selliseid nüansse mitte arvesse võtta.
Sünkroonne (sync) replikatsioon
Lisame tehingu kinnitamise algoritmi loogika muudatuste replikatsiooniks:
- Tehingu salvestamine andmebaasi žurnali.
- Tehingu rakendamine andmebaasi mootori poolt.
- Andmete saatmine kõigile repliikidele.
- Kinnituse saamine kõigilt repliikidelt tehingu täitmise kohta.
- Kliendile kinnituse saatmine tehingu eduka rakendamise kohta.
Selle lähenemise korral saame mitmeid puudusi:
- klient ootab muudatuste rakendamist kõigile repliikidele.
- nõlkude arvu suurenedes klastris vähendame tõenäosust, et kirjeoperatsioon õnnestub.
Kui esimese punktiga on kõik enam-vähem selge, siis teise punktiga seotud põhjuseid tasub selgitada. Kui sünkroonses replikatsioonis ei saa me vastust vähemalt ühe nodi kohta, tühistame tehingu. Niisiis, suurendades nodide arvu klastris, suurendate tõenäosust, et kirjeoperatsioon kukub läbi.
Kas saame oodata kinnitust vaid teatud osast sõlmedest, näiteks 51% (kvorum)? Jah, saame, kuid klassikalises variandis on vajalik kinnitus kõigilt sõlmedelt, kuna just nii suudame tagada andmete täieliku järjepidevuse klastris, mis on selle tüüpi replikatsiooni selge eelis.
Asünkrooniline (async) replikatsioon
Muudame eelmist algoritmi. Andmed replikatsioonide jaoks saadame „kunagi hiljem”, ning „kunagi hiljem” rakendatakse muudatused replikatsioonides:
- Tehingu salvestamine andmebaasi žurnali.
- Tehingu rakendamine andmebaasi mootori poolt.
- Kliendile kinnituse saatmine tehingu eduka rakendamise kohta.
- Andmete saatmine replikatsioonidele ja muudatuste rakendamine nende poolt.
See lähenemine tagab, et klaster töötab kiiresti, sest me ei hoia klienti ootamas, kuni andmed replikatsioonidele jõuavad ja seal kinni peetakse.
Kuid tingimus, et andmed saadetakse replikatsioonidele „kunagi hiljem”, võib viia tehingu kadumiseni, sealhulgas kinnitatud tehingu kadumiseni kasutajale, sest kui andmed ei jõudnud replikatsioonidesse, saadetakse kliendile kinnituseõnnestumise teade, kuid sõlmel, kuhu muudatused tulid, võib HDD maha kukkuda ning me kaotame tehingu, mis võib põhjustada väga ebameeldivaid tagajärgi.
Pool-sünkroonne (semisync) replikaat
Lõpuks oleme jõudnud pool-sünkroonse replikatsiooni juurde. See replikatsiooni tüüp ei ole eriti tuntud ega laialdaselt levinud, kuid see pakkub suurt huvi, kuna suudab kombineerida nii sünkroonse kui ka asünkroonse replikatsiooni eeliseid.
Proovime ühendada kahe eelneva lähenemise. Ei hoia klienti kaua, kuid nõuame, et andmed replitseeruksid:
- Tehingu salvestamine andmebaasi žurnali.
- Tehingu rakendamine andmebaasi mootori poolt.
- Andmete saatmine replikatele.
- Kinnituse saamine replikalt muudatuste vastuvõtu kohta (rakendatakse „kunagi hiljem“).
- Kliendile kinnituse saatmine tehingu eduka rakendamise kohta.
Pange tähele, et sellise algoritmi korral toimub tehingu kadu ainult juhul, kui niss, mis kuulab muudatusi, ja replikatsiooni niss kukuvad kokku. Sellise tõrke tõenäosus tunnistatakse madalaks ning andmed võtavad need riskid ette.
Kuid sellise lähenemise korral on võimalik fantoomlugemise risk. Kujutame ette järgmisi stsenaariume: sammude 4 puhul ei ole me saanud kinnitust üheltki koopiatelt. Me peame selle tehingu tagasi keerama, kuid kliendile ei tohi kinnitust saata. Kuna andmed on rakendatud sammude 2 puhul, tekib ajavahemik sammude 2 lõpetamise ja tehingu tagasivõtmise vahel, mille jooksul saavad paralleelsed tehingud näha neid muudatusi, mida andmebaasis ei tohiks olla.
Lose-less semisünkroonne replikatsioon
Kui veidi aega mõelda, siis saab lihtsalt vahetades algoritmi samme kohendada fantoomlugemise probleemi antud stsenaariumis:
- Tehingu salvestamine andmebaasi žurnali.
- Koopia andmete saatmine.
- Kinnituse saamine replikalt muudatuste vastuvõtu kohta (rakendatakse „kunagi hiljem“).
- Tehingu rakendamine andmebaasi mootori poolt.
- Kliendile kinnituse saatmine tehingu eduka rakendamise kohta.
Nüüd kinnitame muudatusi ainult siis, kui need on kopeeritud.
Kokkuvõte
Nagu alati, ideaalset lahendust ei ole, vaid on lahenduste kogum, kus igaühel on oma eelised ja puudused, mis sobivad erinevate ülesannete lahendamiseks. See kehtib ka replikeeritud andmebaasi andmete sünkroonimise mehhanismi valiku kohta. Pool-sünkroonsel replikatsioonil on piisavalt tugevaid ja huvitavaid eeliseid, et see väärib tähelepanu, vaatamata oma vähesele levikule.
Sellega on kõik. Kohtumiseni !
Allikas: habr.com
