HighLoad++, Mihhail Tyulenev (MongoDB): põhjuslik järjepidevus: teooriast praktikani

Järgmine HighLoad++ konverents peetakse 6. ja 7. aprillil 2020 Peterburis.
Üksikasjad ja piletid по ссылке. HighLoad++ Siber 2019. Hall "Krasnojarsk". 25. juuni kell 12. Teesid ja esitlus.

HighLoad++, Mihhail Tyulenev (MongoDB): põhjuslik järjepidevus: teooriast praktikani

Juhtub, et praktilised nõuded lähevad vastuollu teooriaga, kus kommertstoote jaoks olulisi aspekte ei võeta arvesse. See kõne tutvustab protsessi, kuidas valida ja kombineerida erinevaid lähenemisviise põhjusliku järjepidevuse komponentide loomiseks, mis põhinevad akadeemilistel uuringutel, mis põhinevad kaubandusliku toote nõuetele. Kuulajad saavad teada olemasolevatest teoreetilistest lähenemisviisidest loogilistele kelladele, sõltuvuse jälgimisele, süsteemi turvalisusele, kella sünkroonimisele ja miks MongoDB otsustas teatud lahenduste kasuks.

Mihhail Tyulenev (edaspidi MT): – Ma räägin põhjuslikust järjepidevusest – see on funktsioon, mille kallal MongoDB-s töötasime. Töötan hajutatud süsteemide rühmas, tegime seda umbes kaks aastat tagasi.

HighLoad++, Mihhail Tyulenev (MongoDB): põhjuslik järjepidevus: teooriast praktikani

Selle käigus pidin end kurssi viima paljude akadeemiliste uurimistöödega, sest seda omadust on päris hästi uuritud. Selgus, et ükski artikkel ei mahu tootmisandmebaasi nõutavasse väga spetsiifiliste nõuete tõttu, mis on tõenäoliselt igas tootmisrakenduses olemas.

Räägin sellest, kuidas meie, akadeemilise Teadustöö tarbijad, valmistame sellest midagi, mida saame siis oma kasutajatele esitleda valmistoiduna, mida on mugav ja ohutu kasutada.

Põhjuslik järjepidevus. Määratleme mõisted

Alustuseks tahan öelda üldiselt, mis on põhjuslik järjepidevus. Tegelasi on kaks – Leonard ja Penny (telesari "Suure paugu teooria"):

HighLoad++, Mihhail Tyulenev (MongoDB): põhjuslik järjepidevus: teooriast praktikani

Oletame, et Penny on Euroopas ja Leonard tahab korraldada talle üllatuspeo. Ja ta ei suuda välja mõelda midagi paremat, kui ta oma sõbralistist välja visata ja kõigile oma sõpradele voo kohta värskendusi saata: "Teeme Penny õnnelikuks!" (ta on Euroopas, magamise ajal ei näe ta seda kõike ega näe, sest teda pole seal). Lõpuks kustutab ta selle postituse, kustutab selle voost ja taastab juurdepääsu, et ta ei märkaks midagi ja ei tekiks skandaali.
See kõik on hea, kuid oletame, et süsteem on hajutatud ja asjad läksid veidi valesti. Näiteks võib juhtuda, et Penny juurdepääsupiirang tekkis pärast selle postituse ilmumist, kui sündmused pole põhjuse ja tagajärjega seotud. Tegelikult on see näide sellest, kui ärifunktsiooni (antud juhul) täitmiseks on vaja põhjuslikku järjepidevust.

Tegelikult on need andmebaasi üsna mittetriviaalsed omadused - väga vähesed inimesed toetavad neid. Liigume edasi mudelite juurde.

Järjepidevuse mudelid

Mis täpselt on järjepidevuse mudel andmebaasides? Need on mõned garantiid, mida hajutatud süsteem annab selle kohta, milliseid andmeid klient saab vastu võtta ja millises järjekorras.

Põhimõtteliselt taanduvad kõik järjepidevuse mudelid sellele, kui sarnane on hajutatud süsteem süsteemiga, mis töötab näiteks sülearvuti ühes sõlmes. Ja nii sarnaneb tuhandetel geograafiliselt hajutatud “sõlmedel” töötav süsteem sülearvutiga, milles kõik need omadused toimivad põhimõtteliselt automaatselt.

Seetõttu rakendatakse järjepidevuse mudeleid ainult hajutatud süsteemide puhul. Kõik süsteemid, mis varem eksisteerisid ja töötasid sama vertikaalse skaleerimisega, selliseid probleeme ei kogenud. Seal oli üks puhvri vahemälu ja sealt loeti alati kõike.

Mudel Tugev

Tegelikult on kõige esimene mudel Strong (või tõusuvõime joon, nagu seda sageli nimetatakse). See on järjepidevuse mudel, mis tagab, et iga muudatus, kui selle toimumine on kinnitatud, on nähtav kõigile süsteemi kasutajatele.

See loob kõigi andmebaasis olevate sündmuste globaalse järjestuse. See on väga tugeva konsistentsi omadus ja üldiselt väga kallis. Siiski on see väga hästi toetatud. See on lihtsalt väga kallis ja aeglane – seda kasutatakse lihtsalt harva. Seda nimetatakse tõusuvõimeks.

Mutrivõti toetab veel ühte tugevamat omadust – nimega väline järjepidevus. Räägime sellest veidi hiljem.

Põhjuslik

Järgmine on Causal, millest ma just rääkisin. Tugeva ja põhjusliku vahel on veel mitu alamtasandit, millest ma ei räägi, kuid need kõik taanduvad põhjuslikkusele. See on oluline mudel, kuna see on kõigist mudelitest tugevaim, kõige tugevam järjepidevus võrgu või vaheseinte olemasolul.

Põhjused on tegelikult olukord, kus sündmused on omavahel seotud põhjuse-tagajärje seosega. Väga sageli tajutakse neid kui õigusi lugeda kliendi vaatenurgast. Kui klient on jälginud mingeid väärtusi, ei saa ta näha väärtusi, mis olid minevikus. Ta on juba hakanud nägema eesliite näitu. Kõik taandub samale asjale.
Põhjuslikud seosed kui järjepidevuse mudel on sündmuste osaline järjestamine serveris, kus kõigi klientide sündmusi vaadeldakse samas järjestuses. Antud juhul Leonard ja Penny.

Lõpuks

Kolmas mudel on lõplik järjepidevus. Seda toetavad absoluutselt kõik hajutatud süsteemid, minimaalne mudel, mis on üldse mõttekas. See tähendab järgmist: kui meil on andmetes muudatusi, muutuvad need ühel hetkel järjepidevaks.

Sel hetkel ei ütle ta midagi, muidu muutuks ta väliseks järjekindluseks – see oleks hoopis teine ​​lugu. Sellest hoolimata on see väga populaarne mudel, kõige levinum. Vaikimisi kasutavad kõik hajutatud süsteemide kasutajad lõplikku järjepidevust.

Tahan tuua mõned võrdlevad näited:

HighLoad++, Mihhail Tyulenev (MongoDB): põhjuslik järjepidevus: teooriast praktikani

Mida need nooled tähendavad?

  • Latentsus. Järjepidevuse tugevuse kasvades muutub see arusaadavatel põhjustel suuremaks: peate tegema rohkem kirjeid, saama kinnitust kõigilt klastris osalevatelt hostidelt ja sõlmedelt, et andmed on juba olemas. Sellest tulenevalt on Eventual Consistency'il kiireim vastus, sest seal saate reeglina isegi mällu salvestada ja sellest põhimõtteliselt piisab.
  • Kättesaadavus. Kui mõistame seda kui süsteemi võimet reageerida võrgukatkestuste, partitsioonide või mingi rikke korral, suureneb tõrketaluvus järjepidevuse mudeli vähenedes, kuna meile piisab sellest, kui üks host elab ja samal ajal. aeg toodab teatud andmeid. Lõplik järjepidevus ei garanteeri andmete kohta üldse midagi – see võib olla ükskõik milline.
  • Anomaaliad. Samal ajal muidugi suureneb kõrvalekallete arv. Tugevas järjepidevuses ei tohiks neid peaaegu üldse eksisteerida, kuid lõplikus järjepidevuses võivad nad olla kõik. Tekib küsimus: miks valivad inimesed lõpliku järjepidevuse, kui see sisaldab kõrvalekaldeid? Vastus on, et lõpliku järjepidevuse mudelid on rakendatavad ja kõrvalekalded esinevad näiteks lühikese aja jooksul; viisardit on võimalik kasutada ühtsete andmete lugemiseks ja enam-vähem lugemiseks; Sageli on võimalik kasutada tugeva järjepidevuse mudeleid. Praktikas see toimib ja sageli on kõrvalekallete arv ajaliselt piiratud.

CAP teoreem

Kui näete sõnu järjepidevus, kättesaadavus – mis teile pähe tuleb? Täpselt nii – CAP teoreem! Nüüd tahan müüdi kummutada... See pole mina – see on Martin Kleppmann, kes kirjutas suurepärase artikli, imelise raamatu.

HighLoad++, Mihhail Tyulenev (MongoDB): põhjuslik järjepidevus: teooriast praktikani

CAP teoreem on 2000ndatel sõnastatud põhimõte, et järjepidevus, kättesaadavus, vaheseinad: võtke suvalised kaks ja te ei saa valida kolme. See oli kindel põhimõte. Mõni aasta hiljem tõestasid seda teoreemina Gilbert ja Lynch. Siis hakati seda kasutama mantrana – süsteeme hakati jagama CA-ks, CP-ks, AP-ks ja nii edasi.

Seda teoreemi tõestati tegelikult järgmistel juhtudel... Esiteks, Kättesaadavust ei peetud pidevaks väärtuseks nullist sadadeni (0 - süsteem on "surnud", 100 - reageerib kiiresti; oleme harjunud seda nii pidama) , kuid algoritmi omadusena, mis garanteerib, et see tagastab andmed kõigi täitmiste kohta.

Reaktsiooniajast pole sõnagi! On olemas algoritm, mis tagastab andmed 100 aasta pärast – täiesti suurepärane saadaolev algoritm, mis on osa CAP teoreemist.
Teiseks: teoreem tõestati sama võtme väärtuste muutuste kohta, hoolimata asjaolust, et neid muutusi saab muuta. See tähendab, et tegelikkuses neid praktiliselt ei kasutata, sest mudelid on erinevad Lõppkonsistents, Tugev konsistents (võib-olla).

Milleks see kõik? Pealegi pole ÜPP teoreem täpselt sellisel kujul, nagu see tõestati, praktiliselt rakendatav ja seda kasutatakse harva. Teoreetilises vormis piirab see kuidagi kõike. Selgub teatud põhimõte, mis on intuitiivselt õige, kuid üldiselt pole tõestatud.

Põhjuslik järjepidevus on tugevaim mudel

Praegu toimub see, et saate kõik kolm asja: järjepidevus, partitsioonide abil saadavus. Eelkõige on põhjuslik järjepidevus kõige tugevam järjepidevuse mudel, mis töötab ka partitsioonide (võrgu katkestuste) olemasolul. Seetõttu pakub see nii suurt huvi ja seepärast võtsime selle üles.

HighLoad++, Mihhail Tyulenev (MongoDB): põhjuslik järjepidevus: teooriast praktikani

Esiteks lihtsustab see rakenduste arendajate tööd. Eelkõige serveri suure toe olemasolu: kui kõik ühes kliendis esinevad kirjed jõuavad kindlasti teise kliendi juurde samas järjestuses. Teiseks peab see vastu vaheseintele.

MongoDB siseköök

Mäletades, et on lõuna, liigume kööki. Ma räägin teile süsteemi mudelist, nimelt sellest, mis on MongoDB neile, kes kuulevad sellisest andmebaasist esimest korda.

HighLoad++, Mihhail Tyulenev (MongoDB): põhjuslik järjepidevus: teooriast praktikani

HighLoad++, Mihhail Tyulenev (MongoDB): põhjuslik järjepidevus: teooriast praktikani

MongoDB (edaspidi "MongoDB") on hajutatud süsteem, mis toetab horisontaalset skaleerimist, st jagamist; ja iga killu sees toetab see ka andmete liiasust, st replikatsiooni.

Jagamine MongoDB-s (mitte relatsiooniandmebaasis) teostab automaatset tasakaalustamist, see tähendab, et iga dokumendikogu (või relatsiooniandmete "tabel") jagatakse tükkideks ja server liigutab need automaatselt kildude vahel.

Päringuruuter, mis jagab kliendi jaoks päringuid, on mõni klient, mille kaudu see töötab. See juba teab, kus ja millised andmed asuvad ning suunab kõik päringud õigele killule.

Veel üks oluline punkt: MongoDB on üksikjuht. On üks esmane – see võib võtta kirjeid, mis toetavad selles sisalduvaid võtmeid. Multi-master-kirjutamist ei saa teha.

Tegime versiooni 4.2 – sinna ilmus uusi huvitavaid asju. Eelkõige sisestasid nad Lucene'i - otsing - nimelt käivitatava java otse Mongosse ja seal sai võimalikuks Lucene'i kaudu otsinguid teha, sama mis Elasticas.

Ja nad tegid uue toote - Charts, see on saadaval ka Atlases (Mongo enda pilv). Neil on tasuta tase – saate sellega ringi mängida. Mulle väga meeldis Charts – andmete visualiseerimine, väga intuitiivne.

Koostisained Põhjuslik kooskõla

Lugesin kokku umbes 230 artiklit, mis on sellel teemal avaldatud – Leslie Lampertilt. Nüüd annan teile oma mälu järgi mõned osad neist materjalidest.

HighLoad++, Mihhail Tyulenev (MongoDB): põhjuslik järjepidevus: teooriast praktikani

Kõik sai alguse Leslie Lamperti artiklist, mis oli kirjutatud 1970. aastatel. Nagu näete, on selleteemalised uuringud veel pooleli. Nüüd tunneb põhjuslik järjepidevus seoses hajutatud süsteemide arendamisega huvi.

Piirangud

Millised piirangud on olemas? See on tegelikult üks põhipunkte, sest tootmissüsteemi seatud piirangud on väga erinevad akadeemilistes artiklites esinevatest piirangutest. Need on sageli üsna kunstlikud.

HighLoad++, Mihhail Tyulenev (MongoDB): põhjuslik järjepidevus: teooriast praktikani

  • Esiteks, nagu ma juba ütlesin, on MongoDB üksikjuht (see lihtsustab oluliselt).
  • Usume, et süsteem peaks toetama umbes 10 tuhat kildu. Me ei saa teha ühtegi arhitektuurilist otsust, mis seda väärtust selgesõnaliselt piiraks.
  • Meil on pilv olemas, kuid eeldame, et inimesel peaks siiski olema võimalus, kui ta binaarfaili alla laadib, oma sülearvutis jookseb ja kõik töötab suurepäraselt.
  • Eeldame midagi, mida Research harva eeldab: välised kliendid saavad teha, mida tahavad. MongoDB on avatud lähtekoodiga. Sellest lähtuvalt võivad kliendid olla nii targad ja vihased – nad võivad tahta kõike lõhkuda. Me oletame, et Bütsantsi Feilors võib pärineda.
  • Välisklientide puhul, mis asuvad väljaspool perimeetrit, on oluline piirang: kui see funktsioon on keelatud, ei tohiks jõudluse halvenemist täheldada.
  • Teine punkt on üldiselt antiakadeemiline: eelmiste ja tulevaste versioonide ühilduvus. Vanad draiverid peavad toetama uusi värskendusi ja andmebaas peab toetama vanu draivereid.

Üldiselt seab see kõik piirangud.

Põhjusliku järjepidevuse komponendid

Räägin nüüd mõnest komponendist. Kui arvestada põhjuslikku järjepidevust üldiselt, saame valida plokke. Valisime teatud plokki kuuluvate tööde hulgast: Sõltuvuse jälgimine, kellade valimine, kuidas neid kellasid omavahel sünkroniseerida ja kuidas me tagame turvalisuse – see on umbkaudne ülevaade sellest, millest ma räägin:

HighLoad++, Mihhail Tyulenev (MongoDB): põhjuslik järjepidevus: teooriast praktikani

Täielik sõltuvuse jälgimine

Miks seda vaja on? Nii et andmete kopeerimisel sisaldab iga kirje, iga andmemuudatus teavet selle kohta, millistest muudatustest need sõltuvad. Kõige esimene ja naiivne muudatus on see, kui iga kirjet sisaldav sõnum sisaldab teavet eelmiste sõnumite kohta:

HighLoad++, Mihhail Tyulenev (MongoDB): põhjuslik järjepidevus: teooriast praktikani

Selles näites on lokkis sulgudes olev number rekordnumbrid. Mõnikord kantakse need väärtustega kirjed üle isegi tervikuna, mõnikord kantakse üle mõned versioonid. Põhimõte on see, et iga muudatus sisaldab teavet eelmise kohta (ilmselgelt kannab see kõike endas).

Miks me otsustasime seda lähenemist (täielik jälgimine) mitte kasutada? Ilmselgelt sellepärast, et selline lähenemine on ebapraktiline: kõik sotsiaalvõrgustiku muudatused sõltuvad kõigist selle sotsiaalvõrgustiku varasematest muudatustest, näiteks Facebooki või VKontakte'i ülekandmine igas värskenduses. Sellegipoolest on täieliku sõltuvuse jälgimise kohta tehtud palju uuringuid – need on eelsotsiaalsed võrgustikud; mõnes olukorras see tõesti toimib.

Selgesõnaline sõltuvuse jälgimine

Järgmine on piiratum. Siin käsitletakse ka teabe edastamist, kuid ainult seda, mis on selgelt sõltuv. Mis oleneb millest, määrab reeglina Rakendus. Andmete kopeerimisel tagastab päring vastused ainult siis, kui eelmised sõltuvused on täidetud, st kuvatud. See on põhjusliku järjepidevuse olemus.

HighLoad++, Mihhail Tyulenev (MongoDB): põhjuslik järjepidevus: teooriast praktikani

Ta näeb, et kirje 5 sõltub kirjetest 1, 2, 3, 4 – vastavalt sellele ootab ta, enne kui klient pääseb ligi Penny juurdepääsuotsusega tehtud muudatustele, kui kõik varasemad muudatused on juba andmebaasist läbi käinud.

See ei sobi ka meile, sest teavet on endiselt liiga palju ja see aeglustab tegevust. On ka teine ​​lähenemine...

Lamporti kell

Nad on väga vanad. Lamporti kell tähendab, et need sõltuvused on kokku pandud skalaarfunktsiooniks, mida nimetatakse Lamporti kellaks.

Skalaarfunktsioon on mingi abstraktne arv. Seda nimetatakse sageli loogiliseks ajaks. Iga sündmusega see loendur suureneb. Loendur, mis on protsessile hetkel teada, saadab iga sõnumi. Selge see, et protsessid võivad olla sünkroonist väljas, neil võivad olla täiesti erinevad ajad. Sellest hoolimata tasakaalustab süsteem kella sellise sõnumivahetusega kuidagi. Mis sel juhul juhtub?

Jagasin selle suure killu kaheks, et oleks selge: sõbrad võivad elada ühes sõlmes, mis sisaldab osa kogust, ja Feed võib elada teises sõlmes, mis sisaldab osa sellest kogust. Kas on selge, kuidas nad rivist välja saavad? Esimene voog ütleb: „Replicated” ja seejärel Sõbrad. Kui süsteem ei anna mingit garantiid, et voogu ei kuvata enne, kui ka Sõprade kogus olevad sõltuvused on kohale toimetatud, siis on meil täpselt selline olukord, nagu mainisin.

Näete, kuidas voo loenduri aeg loogiliselt suureneb:

HighLoad++, Mihhail Tyulenev (MongoDB): põhjuslik järjepidevus: teooriast praktikani

Seega on selle Lamporti kella ja põhjusliku järjepidevuse põhiomadus (selgitatud Lamporti kella kaudu) järgmine: kui meil on sündmused A ja B ning sündmus B sõltub sündmusest A*, siis sellest järeldub, et sündmuse A loogiline aeg on väiksem kui Loogiline aeg sündmusest B.

* Mõnikord öeldakse ka, et A juhtus enne B-d, st A juhtus enne B-d - see on teatud seos, mis korraldab osaliselt kogu üldiselt toimunud sündmuste komplekti.

Vastupidine on vale. See on tegelikult Lamport Clocki üks peamisi puudusi – osaline tellimus. On olemas mõiste samaaegsete sündmuste kohta, st sündmuste kohta, milles ei (A juhtus enne B) ega (A juhtus enne B). Näiteks võib Leonardi paralleelselt lisada sõbraks kellegi teise (isegi mitte Leonardi, vaid näiteks Sheldoni).
Seda omadust kasutatakse sageli Lamporti kelladega töötamisel: nad vaatavad konkreetselt funktsiooni ja järeldavad sellest, et võib-olla on need sündmused sõltuvad. Sest üks viis on tõsi: kui loogiline aeg A on väiksem kui loogiline aeg B, siis B ei saa juhtuda enne A; ja kui rohkem, siis võib-olla.

Vektorkell

Lamporti kella loogiline areng on vektorkell. Need erinevad selle poolest, et iga siin olev sõlm sisaldab oma eraldi kella ja neid edastatakse vektorina.
Sel juhul näete, et vektori nullindeks vastutab voo eest ja vektori esimene indeks on sõprade jaoks (igaüks neist sõlmedest). Ja nüüd need suurenevad: "Sööda" nullindeks suureneb kirjutamisel - 1, 2, 3:

HighLoad++, Mihhail Tyulenev (MongoDB): põhjuslik järjepidevus: teooriast praktikani

Miks on vektorkell parem? Kuna need võimaldavad teil välja selgitada, millised sündmused on samaaegsed ja millal need toimuvad erinevates sõlmedes. See on väga oluline sellise jaotussüsteemi jaoks nagu MongoDB. Kuid me ei valinud seda, kuigi see on suurepärane asi ja see töötab suurepäraselt ja meile see ilmselt sobiks...

Kui meil on 10 tuhat killu, ei saa me 10 tuhat komponenti üle kanda, isegi kui me selle kokku surume või midagi muud välja mõtleme - kasulik koormus on ikkagi mitu korda väiksem kui kogu selle vektori maht. Seetõttu, südant ja hambaid krigistades, loobusime sellest lähenemisest ja läksime teise juurde.

Mutrivõti TrueTime. Aatomkell

Ma ütlesin, et seal tuleb lugu Spannerist. See on lahe asi, otse XNUMX. sajandist: aatomkellad, GPS-i sünkroniseerimine.

Mis on idee? “Spanner” on Google’i süsteem, mis sai hiljuti isegi inimestele kättesaadavaks (nad lisasid sellele SQL-i). Igal seal tehtaval tehingul on ajatempel. Kuna aeg on sünkroonitud*, siis saab igale sündmusele määrata kindla aja – aatomkelladel on ooteaeg, mille järel on garanteeritud teistsugune aeg.

HighLoad++, Mihhail Tyulenev (MongoDB): põhjuslik järjepidevus: teooriast praktikani

Seega, lihtsalt andmebaasi kirjutades ja teatud aja oodates, on sündmuse serialiseeritavus automaatselt tagatud. Neil on kõige tugevam järjepidevuse mudel, mida põhimõtteliselt võib ette kujutada – see on Väline järjepidevus.

* See on Lamparti kellade põhiprobleem – hajutatud süsteemides pole need kunagi sünkroonsed. Need võivad lahkneda; isegi NTP-ga ei tööta need ikkagi eriti hästi. "Spanneril" on aatomkell ja sünkroniseerimine näib olevat mikrosekundites.

Miks me ei valinud? Me ei eelda, et meie kasutajatel on sisseehitatud aatomkell. Kui need ilmuvad, on igasse sülearvutisse sisse ehitatud, toimub mingi ülilahe GPS-i sünkroniseerimine - siis jah... Aga praegu on parim, mis võimalik on Amazon, Base Stations - fanaatikutele... Nii et kasutasime teisi kellasid .

Hübriidkell

See on tegelikult see, mis MongoDB-s põhjusliku järjepidevuse tagamisel tiksub. Kuidas nad on hübriidsed? Hübriid on skalaarväärtus, kuid sellel on kaks komponenti:

HighLoad++, Mihhail Tyulenev (MongoDB): põhjuslik järjepidevus: teooriast praktikani

  • Esimene on Unixi ajastu (mitu sekundit on möödunud "arvutimaailma algusest").
  • Teine on mõningane juurdekasv, samuti 32-bitine märgita int.

See on tegelikult kõik. On selline lähenemine: aja eest vastutav osa sünkroniseeritakse kogu aeg kellaga; iga uuenduse toimumisel sünkroniseeritakse see osa kellaga ja selgub, et kell on alati enam-vähem õige ning inkrement võimaldab eristada sündmusi, mis toimusid samal ajahetkel.

Miks on see MongoDB jaoks oluline? Sest see võimaldab teatud ajahetkel teha mingisuguseid varurestorane ehk sündmust indekseeritakse aja järgi. See on oluline, kui on vaja teatud sündmusi; Andmebaasi puhul on sündmused muudatused andmebaasis, mis toimusid teatud ajavahemike järel.

Ma ütlen teile kõige olulisema põhjuse ainult teile (palun, ärge rääkige kellelegi)! Tegime seda seetõttu, et korraldatud, indekseeritud andmed näevad MongoDB OpLogis välja sellised. OpLog on andmestruktuur, mis sisaldab absoluutselt kõiki muudatusi andmebaasis: need lähevad esmalt OpLogi ja seejärel rakendatakse neid salvestusruumile endale juhul, kui tegemist on kopeeritud kuupäeva või killukesega.

See oli peamine põhjus. Siiski on andmebaasi arendamisel ka praktilised nõuded, mis tähendab, et see peaks olema lihtne - vähe koodi, võimalikult vähe katkisi asju, mis vajavad ümberkirjutamist ja testimist. See, et meie oploge indekseerisid hübriidkellad, aitas palju kaasa ja võimaldas meil teha õige valiku. See tasus end tõesti ära ja töötas kuidagi võluväel kõige esimese prototüübi kallal. Väga lahe oli!

Kella sünkroonimine

Teaduskirjanduses on kirjeldatud mitmeid sünkroniseerimismeetodeid. Ma räägin sünkroonimisest, kui meil on kaks erinevat kildu. Kui on üks koopiakomplekt, pole sünkroonimist vaja: see on "üksik master"; meil on OpLog, millesse kõik muudatused langevad - sel juhul on kõik juba järjestikuses järjekorras "Oplogis" endas. Aga kui meil on kaks erinevat kildu, on aja sünkroniseerimine siin oluline. Siin aitas vektorkell rohkem! Aga meil pole neid.

HighLoad++, Mihhail Tyulenev (MongoDB): põhjuslik järjepidevus: teooriast praktikani

Teine sobib - see on “Heartbeats”. On võimalik vahetada mõningaid signaale, mis esinevad iga ajaühiku kohta. Kuid südamelöögid on liiga aeglased, me ei saa oma kliendile latentsusaega pakkuda.

Tõeline aeg on muidugi imeline asi. Aga see on jällegi ilmselt tulevik... Kuigi Atlases saab seda juba teha, on kiired “Amazoni” ajasünkronisaatorid juba olemas. Kuid see ei ole kõigile kättesaadav.

Lobisemine on siis, kui kõik sõnumid sisaldavad aega. See on umbes see, mida me kasutame. Iga sõnum sõlmede, draiveri, andmesõlme ruuteri ja absoluutselt kõik MongoDB jaoks on mingi element, andmebaasi komponent, mis sisaldab töötavat kella. Neil on kõikjal hübriidaja tähendus, see kandub edasi. 64 bitti? See võimaldab, see on võimalik.

Kuidas see kõik koos toimib?

Siin ma vaatan ühte koopiakomplekti, et see oleks veidi lihtsam. Seal on esmane ja sekundaarne. Sekundaarne teeb replikatsiooni ja pole alati primaarsega täielikult sünkroonitud.

Sisestamine toimub teatud ajaväärtusega "Algusesse". See lisa suurendab sisemist arvu 11 võrra, kui see on maksimaalne. Või kontrollib kella väärtusi ja sünkroonib kellaga, kui kella väärtused on suuremad. See võimaldab teil aja järgi korraldada.

Pärast salvestuse tegemist saabub oluline hetk. Kell on "MongoDB"-s ja seda suurendatakse ainult "Oplogi" kirjutamise korral. See on sündmus, mis muudab süsteemi olekut. Absoluutselt kõigis klassikalistes artiklites loetakse sündmuseks sõnumi tabamist sõlme: sõnum on saabunud, mis tähendab, et süsteem on oma olekut muutnud.

Selle põhjuseks on asjaolu, et uurimistöö käigus pole päris selge, kuidas seda sõnumit tõlgendatakse. Teame kindlalt, et kui see “Oplogis” ei kajastu, siis seda ei tõlgendata ka kuidagi ja süsteemi oleku muutus on vaid kirje “Oplogis”. See lihtsustab meie jaoks kõike: mudel lihtsustab seda ja võimaldab meil korraldada selle ühes koopiakomplektis ja palju muud kasulikku.

Tagatakse väärtus, mis on juba “Oplog”-i kirjutatud – me teame, et “Oplog” juba sisaldab seda väärtust ja selle aeg on 12. Nüüd, näiteks, algab lugemine teisest sõlmest (Secondary) ja see edastab pärastClusterTime sõnum. Ta ütleb: "Mul on vaja kõike, mis juhtus vähemalt pärast kella 12 või kaheteistkümne ajal" (vt ülemist pilti).

Seda nimetatakse kausaalseks järjekindlaks (CAT). Teoorias on selline kontseptsioon, et see on mingi ajalõik, mis on iseenesest järjepidev. Sel juhul võime öelda, et see on süsteemi olek, mida täheldati ajal 12.

Nüüd pole siin veel midagi, sest see simuleerib olukorda, kui peate esmase andmete kopeerimiseks sekundaarset. Ta ootab... Ja nüüd on andmed saabunud – ta tagastab need väärtused tagasi.

HighLoad++, Mihhail Tyulenev (MongoDB): põhjuslik järjepidevus: teooriast praktikani

Umbes nii see kõik toimib. Peaaegu.

Mida tähendab "peaaegu"? Oletame, et mõni inimene on lugenud ja aru saanud, kuidas see kõik toimib. Sain aru, et iga kord, kui ClusterTime ilmneb, värskendab see sisemist loogilist kella ja seejärel suureneb järgmine kirje ühe võrra. See funktsioon võtab 20 rida. Oletame, et see inimene edastab suurima 64-bitise arvu, millest on maha arvatud üks.

Miks "miinus üks"? Kuna sisemine kell asendatakse selle väärtusega (ilmselgelt on see suurim võimalik ja suurem kui praegune kellaaeg), siis toimub kirje "Oplog" ja kella suurendatakse teise ühiku võrra - ja juba olema maksimaalne väärtus (seal on lihtsalt kõik ühikud, pole kuhugi mujale minna) , unsaint ints).

On selge, et pärast seda muutub süsteem absoluutselt millegi jaoks kättesaamatuks. Seda saab ainult maha laadida ja puhastada – palju käsitsitööd. Täielik saadavus:

HighLoad++, Mihhail Tyulenev (MongoDB): põhjuslik järjepidevus: teooriast praktikani

Veelgi enam, kui seda korratakse kusagil mujal, kukub kogu klaster lihtsalt alla. Täiesti lubamatu olukord, mida igaüks saab väga kiiresti ja lihtsalt korraldada! Seetõttu pidasime seda hetke üheks kõige olulisemaks. Kuidas seda ennetada?

Meie viis on allkirjastada clusterTime

Nii edastatakse see sõnumis (enne sinist teksti). Kuid hakkasime ka allkirja genereerima (sinine tekst):

HighLoad++, Mihhail Tyulenev (MongoDB): põhjuslik järjepidevus: teooriast praktikani

Allkirja genereerib võti, mis on salvestatud andmebaasi turvalises perimeetris; ise luuakse ja värskendatakse (kasutajad ei näe selle kohta midagi). Räsi luuakse ja iga sõnum allkirjastatakse loomisel ja kinnitatakse vastuvõtmisel.
Tõenäoliselt tekib inimeste peas küsimus: "Kui palju see aeglustab?" Ütlesin teile, et see peaks kiiresti töötama, eriti selle funktsiooni puudumisel.

Mida tähendab antud juhul põhjusliku järjepidevuse kasutamine? See on parameetri afterClusterTime kuvamiseks. Ilma selleta edastab see väärtusi niikuinii. Lobisemine, alates versioonist 3.6, töötab alati.

Kui jätame pideva allkirjade genereerimise, aeglustab see süsteemi isegi funktsiooni puudumisel, mis ei vasta meie lähenemistele ja nõuetele. Mida me siis tegime?

Tehke seda kiiresti!

See on üsna lihtne asi, aga nipp on huvitav – ma jagan seda, äkki keegi tunneb huvi.
Meil on räsi, mis salvestab allkirjastatud andmed. Kõik andmed liiguvad läbi vahemälu. Vahemälu ei allkirjasta konkreetset aega, vaid vahemikku. Kui mingi väärtus saabub, genereerime vahemiku, maskeerime viimased 16 bitti ja allkirjastame selle väärtuse:

HighLoad++, Mihhail Tyulenev (MongoDB): põhjuslik järjepidevus: teooriast praktikani

Sellise allkirja saamisega kiirendame süsteemi (suhteliselt) 65 tuhat korda. See töötab suurepäraselt: katsete tegemisel vähenes aeg tegelikult 10 tuhat korda, kui meil oli järjestikune värskendus. On selge, et kui nad on vastuolus, siis see ei tööta. Kuid enamikul praktilistel juhtudel see töötab. Range signatuuri ja allkirja kombinatsioon lahendas turvaprobleemi.

Mida me õppisime?

Sellest õppisime:

  • Peame lugema materjale, lugusid, artikleid, sest meil on palju huvitavat. Kui töötame mõne funktsiooni kallal (eriti praegu, kui tegime tehinguid jne), peame lugema ja aru saama. See võtab aega, aga on tegelikult väga kasulik, sest teeb selgeks, kus me asume. Me ei paistnud midagi uut välja pakkuvat – võtsime lihtsalt koostisosad.

    Üldiselt on teatud erinevus mõtlemises, kui on akadeemiline konverents (Sigmon näiteks) - kõik keskenduvad uutele ideedele. Mis on meie algoritmis uut? Midagi eriti uut siin pole. Uudsus seisneb pigem selles, kuidas me olemasolevaid lähenemisviise omavahel segasime. Seetõttu on esimene asi lugeda klassikat, alustades Lampartist.

  • Tootmises on nõuded hoopis teised. Olen kindel, et paljud teist ei seisa silmitsi "sfääriliste" andmebaasidega abstraktses vaakumis, vaid tavaliste, reaalsete asjadega, millel on probleeme saadavuse, latentsuse ja tõrketaluvusega.
  • Viimane asi on see, et pidime kaaluma erinevaid ideid ja kombineerima mitu täiesti erinevat artiklit üheks lähenemisviisiks. Idee allkirjastamise kohta tuli näiteks üldiselt ühest artiklist, mis käsitles Paxose protokolli, mis mitte-Bütsantsi jaoks on autoriseerimisprotokolli sees, Bütsantsi jaoks - väljaspool autoriseerimisprotokolli... Üldiselt on see täpselt see, mida me tegin lõpuks.

    Siin pole absoluutselt midagi uut! Aga niipea, kui me selle kõik kokku segasime... See on sama, mis öelda, et Olivieri salati retsept on jama, sest munad, majonees ja kurgid on juba leiutatud... See on umbes sama lugu.

HighLoad++, Mihhail Tyulenev (MongoDB): põhjuslik järjepidevus: teooriast praktikani

Ma lõpetan sellega. Aitäh!

küsimused

Küsimus publikult (edaspidi B): – Aitäh, Mihhail, raporti eest! Aja teema on huvitav. Kasutate Gossipingit. Nad ütlesid, et igaühel on oma aeg, kõik teavad oma kohalikku aega. Nagu ma aru saan, on meil juht olemas – draiveritega kliente võib olla palju, päringuplaneerijaid ka, killukesi ka... Ja milleks see süsteem taandub, kui äkki tekib lahknevus: keegi otsustab, et see on mõeldud minut ees, keegi minut maha? Kuhu me välja jõuame?

MT: – Tõesti suurepärane küsimus! Tahtsin lihtsalt kildudest rääkida. Kui ma küsimusest õigesti aru saan, on meil järgmine olukord: on kild 1 ja kild 2, lugemine toimub nendest kahest killust - neil on lahknevus, nad ei suhtle üksteisega, kuna nende teada olev aeg on erinev, eriti aega, mil need oplogides eksisteerivad.
Oletame, et shard 1 tegi miljon plaati, shard 2 ei teinud üldse midagi ja taotlus tuli kahele killule. Ja esimesel on afterClusterTime üle miljoni. Sellises olukorras, nagu ma selgitasin, ei reageeri shard 2 kunagi üldse.

Sisse: – Tahtsin teada, kuidas nad sünkroonivad ja valivad ühe loogilise aja?

MT: - Väga lihtne sünkroonida. Killuke, kui afterClusterTime tuleb tema juurde ja ta ei leia “Oplogist” aega, ei algata heakskiitu. See tähendab, et ta tõstab oma aega kätega selle väärtuseni. See tähendab, et sellel pole päringule vastavaid sündmusi. Ta loob selle sündmuse kunstlikult ja muutub seega põhjuslikuks järjekindlaks.

Sisse: – Mis siis, kui pärast seda jõuavad temani veel mõned sündmused, mis kuhugi võrku kaduma läksid?

MT: – Killud on loodud nii, et neid enam ei tuleks, kuna tegemist on ühe meistriga. Kui ta on juba kirja pannud, siis nad ei tule, vaid tulevad hiljem. Ei saa juhtuda, et midagi jääb kuhugi kinni, siis ta ei kirjuta ja siis need sündmused saabuvad – ja põhjuslik järjepidevus katkeb. Kui ta ei kirjuta, peaksid nad kõik järgmisena tulema (ta ootab neid).

HighLoad++, Mihhail Tyulenev (MongoDB): põhjuslik järjepidevus: teooriast praktikani

Sisse: – Mul on järjekordade kohta mitu küsimust. Põhjuslik järjepidevus eeldab, et on olemas konkreetne järjekord toimingutest, mida tuleb teha. Mis juhtub, kui üks meie pakkidest kaob? Siin tuleb 10., 11.... 12. on kadunud ja kõik teised ootavad, et see teoks saaks. Ja äkki suri meie auto välja, me ei saa midagi teha. Kas enne täitmist koguneval järjekorral on maksimaalne pikkus? Milline saatuslik rike juhtub siis, kui mõni olek kaob? Pealegi, kui panna kirja, et mingi eelnev olek on, siis peaks sellest kuidagi lähtuma? Kuid nad ei tõrjunud teda eemale!

MT: – Samuti suurepärane küsimus! Mida me teeme? MongoDB-l on kvoorumi kirjutamise, kvoorumi lugemise kontseptsioon. Millistel juhtudel võib sõnum kaduma minna? Kui kirjutamine ei ole kvoorum või kui lugemine ei ole kvoorum (mingi prügi võib ka külge jääda).
Põhjusliku järjepidevuse osas viidi läbi suur eksperimentaalne test, mille tulemuseks oli see, et juhul, kui kirjutamine ja lugemine on ebakvoorumiline, ilmnevad põhjusliku järjepidevuse rikkumised. Täpselt see, mida sa ütled!

Meie nõuanne: põhjusliku järjepidevuse kasutamisel kasutage vähemalt kvoorumi lugemist. Sel juhul ei lähe midagi kaotsi, isegi kui kvoorumi kirje kaob... See on ortogonaalne olukord: kui kasutaja ei soovi andmete kadumist, on tal vaja kasutada kvoorumikirjet. Põhjuslik järjepidevus ei taga vastupidavust. Vastupidavuse tagavad replikatsioon ja replikatsiooniga seotud masinad.

Sisse: – Kui loome eksemplari, mis teostab shardingi meie eest (vastavalt mitte ülem, vaid alam), tugineb see oma masina Unixi ajale või "ülema" ajale; Kas see sünkroonitakse esimest korda või perioodiliselt?

MT: — Ma täpsustan nüüd. Killuke (st horisontaalne partitsioon) – seal on alati esmane. Ja killul võib olla "meister" ja seal võivad olla koopiad. Kuid kild toetab alati salvestamist, sest see peab toetama mõnda domeeni (kilul on esmane).

Sisse: – Nii et kõik sõltub puhtalt "meistrist"? Kas meistri aega kasutatakse alati?

MT: - Jah. Piltlikult võib öelda: kell tiksub siis, kui toimub sisenemine “peremehesse”, “Oplogisse”.

Sisse: – Meil ​​on klient, kes ühendab ja ei pea kellaajast midagi teadma?

MT: — Sa ei pea üldse midagi teadma! Kui me räägime sellest, kuidas see kliendi peal töötab: kui klient soovib kasutada põhjuslikku järjepidevust, peab ta avama seansi. Nüüd on kõik olemas: tehingud seansis ja õiguste hankimine... Seanss on kliendiga toimuvate loogiliste sündmuste järjestamine.

Kui ta avab selle seansi ja ütleb seal, et soovib põhjuslikku järjepidevust (kui seanss toetab vaikimisi põhjuslikku järjepidevust), toimib kõik automaatselt. Juht jätab selle aja meelde ja suurendab seda uue sõnumi saamisel. See jätab meelde, millise vastuse andis eelmine andmeid tagastanud serverilt. Järgmine päring sisaldab afterCluster("aeg suurem kui see").

Klient ei pea absoluutselt midagi teadma! See on talle täiesti läbipaistmatu. Kui inimesed neid funktsioone kasutavad, mida nad saavad teha? Esiteks saate ohutult lugeda sekundaarseid materjale: saate kirjutada esmasesse ja lugeda geograafiliselt paljundatud sekundaarseid materjale ning olla kindel, et see töötab. Samal ajal saab esmasel salvestatud seansse isegi teisejärguliseks üle kanda, st saate kasutada mitte ühte, vaid mitut seanssi.

Sisse: – Arvutusteaduse uus kiht – CRDT (Conflict-free Replicated Data Types) andmetüübid – on tugevalt seotud lõpliku järjepidevuse teemaga. Kas olete mõelnud seda tüüpi andmete integreerimisele andmebaasi ja mida saate selle kohta öelda?

MT: - Hea küsimus! CRDT on kirjutuskonfliktide jaoks mõistlik: MongoDB-s üks juht.

Sisse: – Mul on devopsilt küsimus. Reaalses maailmas on selliseid jesuiitlikke olukordi, kui toimub Bütsantsi ebaõnnestumine ja kaitstud perimeetri sees olevad kurjad inimesed hakkavad protokolli torkima, erilisel viisil käsitööpakke saatma?

HighLoad++, Mihhail Tyulenev (MongoDB): põhjuslik järjepidevus: teooriast praktikani

MT: - Kurjad inimesed perimeetri sees on nagu Trooja hobune! Kurjad inimesed perimeetri sees võivad teha palju halba.

Sisse: – Selge on see, et jättes serverisse laias laastus augu, mille kaudu saab panna elevantide loomaaia ja kogu klastri igaveseks kokku variseda... Käsitsi taastamine võtab aega... See pehmelt öeldes on vale. Teisest küljest on see huvitav: päriselus, praktikas, tuleb ette olukordi, kus loomulikult tekivad sarnased sisemised rünnakud?

MT: – Kuna puutun turvarikkumistega päriselus kokku harva, ei oska ma öelda, kas neid juhtub. Aga kui me räägime arendusfilosoofiast, siis mõtleme nii: meil on perimeeter, mis tagab turvalisusega tegelevatele meestele – see on loss, müür; ja perimeetri sees võid teha mida tahad. On selge, et on kasutajaid, kellel on võimalus ainult vaadata, ja on kasutajaid, kellel on võimalus kataloogi kustutada.

Olenevalt õigustest võivad kasutajad kahjustada hiirt või elevanti. Selge see, et täisõigustega kasutaja võib üldse midagi teha. Piiratud õigustega kasutaja võib oluliselt vähem kahju tekitada. Eelkõige ei saa see süsteemi rikkuda.

Sisse: – Kaitstud perimeetris üritas keegi luua serverile ootamatuid protokolle, et server täielikult hävitada ja kui veab, siis kogu klaster... Kas see läheb kunagi nii hästi?

MT: "Ma pole kunagi sellistest asjadest kuulnud." Asjaolu, et saate sellisel viisil serveri krahhi teha, pole saladus. Fail inside, olles protokollist, olles volitatud kasutaja, kes saab sõnumisse midagi sellist kirjutada... Tegelikult on see võimatu, sest see kontrollitakse ikkagi. Seda autentimist on võimalik keelata kasutajatel, kes seda ei soovi – siis on see nende probleem; nad jämedalt öeldes lõhkusid ise müürid ära ja sinna saab lükata elevandi, kes tallab... Aga üldiselt võib ju remondimeheks riietuda, tule tõmba välja!

Sisse: – Tänan raporti eest. Sergei (Yandex). Mongis on konstant, mis piirab hääleõiguslike liikmete arvu koopiakomplektis ja see konstant on 7 (seitse). Miks see on konstant? Miks see ei ole mingisugune parameeter?

MT: – Meil ​​on 40 sõlmega koopiakomplektid. Alati on enamus. Ma ei tea, milline versioon...

Sisse: – Replica Set'is saate käivitada hääleõiguseta liikmeid, kuid hääleõiguslikke liikmeid on maksimaalselt 7. Kuidas saame sel juhul seiskamise üle elada, kui meie koopiakomplekt asub kolmes andmekeskuses? Üks andmekeskus võib kergesti välja lülituda ja teine ​​masin võib välja kukkuda.

MT: – See on juba veidi väljaspool raporti ulatust. See on üldine küsimus. Võib-olla saan sellest teile hiljem rääkida.

HighLoad++, Mihhail Tyulenev (MongoDB): põhjuslik järjepidevus: teooriast praktikani

Mõned reklaamid 🙂

Täname, et jäite meiega. Kas teile meeldivad meie artiklid? Kas soovite näha huvitavamat sisu? Toeta meid, esitades tellimuse või soovitades sõpradele, pilve VPS arendajatele alates 4.99 dollarist, algtaseme serverite ainulaadne analoog, mille me teie jaoks leiutasime: Kogu tõde VPS (KVM) E5-2697 v3 (6 tuuma) 10GB DDR4 480GB SSD 1Gbps kohta alates 19 dollarist või kuidas serverit jagada? (saadaval RAID1 ja RAID10, kuni 24 tuuma ja kuni 40 GB DDR4-ga).

Dell R730xd 2x odavam Amsterdami Equinixi Tier IV andmekeskuses? Ainult siin 2 x Intel TetraDeca-Core Xeon 2x E5-2697v3 2.6 GHz 14C 64GB DDR4 4x960GB SSD 1Gbps 100 telerit alates 199 dollarist Hollandis! Dell R420 – 2x E5-2430 2.2Ghz 6C 128GB DDR3 2x960GB SSD 1Gbps 100TB – alates 99 dollarist! Millegi kohta lugema Kuidas ehitada infrastruktuuri ettevõtet. klassis koos Dell R730xd E5-2650 v4 serverite kasutusega 9000 eurot senti?

Allikas: www.habr.com

Lisa kommentaar