HighLoad++, Mihhail Tšulenjev (MongoDB): Causal consistency: teooriast praktikani

Järgmine HighLoad++ konverents toimub 6. ja 7. aprillil 2020 Peterburis.
Üksikasjad ja piletid linki pidi. HighLoad++ Siberia 2019. Saal "Krasnojarsk". 25. juuni, 12:00. Teesid ja esitlus.

HighLoad++, Mihhail Tšulenjev (MongoDB): Causal consistency: teooriast praktikani

Juhtub, et praktilised nõuded on vastuolus teooriaga, kus ei ole arvesse võetud kaubandusliku toote jaoks olulisi aspekte. Selles ettekandes tutvustatakse erinevate lähenemisviiside valimise ja kombineerimise protsessi põhjusliku järjekindluse (Causal consistency) komponentide loomisel, tuginedes akadeemilistele uuringutele, lähtudes kaubandusliku toote nõuetest. Kuulajad saavad teada, milliseid teoreetilisi lähenemisviise on olemas loogiliste kellade, sõltuvuste jälgimise, süsteemi turvalisuse ja kellasünkroniseerimise osas ning miks MongoDB valis just teatud lahendused.

Mikhail Tyulenev (edaspidi – MT): – Räägin põhjuslikust järjekindlusest – see on funktsioon, mille kallal me töötasime MongoDBs. Töötan hajutatud süsteemide grupis, me jõudsime selleni umbes kaks aastat tagasi.

HighLoad++, Mihhail Tšulenjev (MongoDB): Causal consistency: teooriast praktikani

Protsessi käigus tuli tutvuda suure hulga akadeemilise uurimistööga, sest see funktsioon on üsna hästi uuritud. Selgus, et ükski artikkel ei vasta produktiivsuse nõuetele andmebaasi osas, millel on üsna spetsiifilised nõuded, mis esinevad tõenäoliselt igas tootmisrakenduses.

Räägin sellest, kuidas me, olles akadeemilise uurimistöö tarbijad, valmistame sellest midagi, mida saame seejärel meie kasutajatele serveerida valmisroana, mida on mugav ja ohutu kasutada.

Põhjuslik järjekindlus (Causal consistency). Määratleme mõisted

Esmalt tahan üldiselt rääkida, mis on põhjuslik järjekindlus. On kaks tegelast – Leonard ja Penny (sarjast "Teooria suurest plahvatusest"):

HighLoad++, Mihhail Tšulenjev (MongoDB): Causal consistency: teooriast praktikani

Oletame, et Penny on Euroopas, ja Leonard tahab talle üllatuse korraldada. Ja ta ei tule paremat välja kui eemaldada ta sõbralistist, saata kõigile sõpradele uuendus feed'is: "Küsimus, miks me ei üllata Penny'd!" (ta on Euroopas, magab hetkel, ei näe seda ja ei saa näha, kuna ta ei ole seal). Lõpuks kustutab ta selle postituse, kustutab "Feedi" ja taastab juurdepääsu, et ta ei märkaks midagi ja skandaali ei oleks.
See, это всё прекрасно, но представим, что система распределенная и события пошли чуть не так. Может случиться, что ограничение доступа для Пенни произошло после того, как этот пост уже появился, если события не связаны между собой причинно-следственными связями. Это пример случая, когда необходима причинная согласованность для выполнения бизнес-функции (в данном случае).

На самом деле это достаточно нетривиальные свойства баз данных – очень немногое их поддерживает. Давайте перейдем к моделям.

Модели согласованности (Consistency Models)

Что такое модель консистентности в базах данных? Это определенные гарантии, которые распределённая система предоставляет касательно того, какие данные и в каком порядке клиент может получить.

Существует множество моделей согласованности, которые сводятся к тому, насколько распределенная система похожа на такую, что работает, например, на одном узле на ноутбуке. И то, насколько система, работающая на тысячах геораспределённых узлов, похожа на ноутбук, в котором все эти свойства выполняются автоматически.

Поэтому модели согласованности применимы только к распределённым системам. Все системы, которые раньше существовали и работали на одном вертикальном масштабировании, таких проблем не испытывали. Там был один буферный кэш, и из него всё всегда читается.

Модель Strong

Собственно, первая модель – это Strong (или line of visibility, как её часто называют). Это модель согласованности, которая гарантирует, что каждое изменение, как только подтверждено, становится видно всем пользователям системы.

Это создает глобальный порядок всех событий в БД. Это очень сильное свойство согласованности, и оно весьма дорогое. Тем не менее, оно хорошо поддерживается. Просто это очень дорогое и медленное – им редко пользуются. Это называется line of visibility.

Существует ещё одно, более сильное свойство, которое поддерживается в «Spanner» – это External Consistency. Мы обсудим его чуть позже.

Causal

Järgmine on Causal, just see, millest ma rääkisin. Strongi ja Casual'i vahel on veel mõned alamastmed, millest ma ei hakka rääkima, kuid need kõik seonduvad Causal'iga. See on oluline mudel, kuna see on kõige tugevam kõigist mudelitest, kõige tugevam järjepidevus võrgu või osade kaudu.

Causals on tegelikult olukord, kus sündmused on omavahel seotud põhjuslikku seost. Väga tihti tajutakse neid kui Klientide õiguste lugemise visioonina. Kui klient on näinud mingisuguseid väärtusi, ei saa ta näha väärtusi, mis olid minevikus. Ta hakkab juba nägema prefiks lugemisi. See kõik seondub ühte ja sama.
Causals kui järjepidevuse mudel – osaline sündmuste järjestamine serveris, kus kõigi klientide sündmusi jälgitakse sama järjestusega. Antud juhul – Leonard ja Penny.

Eventual

Kolmas mudel on Eventual Consistency. See, mis toetab absoluutselt kõiki jaotatud süsteeme, minimaalne mudel, mis üldse mõtet omab. See tähendab järgmist: kui toimuvad mõned muudatused andmetes, siis mingil hetkel muutuvad need järjepidevaks.

Sellisel hetkel ei räägi ta midagi, vastasel juhul muutuks see External Consistency'ks – see oleks täiesti teine lugu. Siiski on see väga populaarne mudel, kõige levinum. Vaikimisi kasutavad kõik jaotatud süsteemide kasutajad just Eventual Consistency't.

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

HighLoad++, Mihhail Tšulenjev (MongoDB): Causal consistency: teooriast praktikani

Mida need nooled tähendavad?

  • Latency. Järjepidevuse tugevuse suurenedes muutub see enamike arusaadavate põhjuste tõttu suuremaks: tuleb teha rohkem kirjeid, saada kinnitus kõigilt hostidelt ja nodidelt, mis osalevad klastris, et andmed seal juba on. Seetõttu on Eventual Consistency puhul kõige kiirem vastus, kuna seal võib isegi mälus teha ja see oleks põhimõtteliselt piisav.
  • Availability. Kui seda mõista kui süsteemi võimet vastata, kui on võrgu katkestusi, partitions või mingeid tõrkeid – tõrkekindlus suureneb järjepidevuse mudeli vähendamisega, kuna piisab sellest, et üks host elaks ja samal ajal mingisuguseid andmeid annaks. Eventual Consistency ei garanteeri üldse andmete kohta midagi – see võib olla mis tahes.
  • Anomalies. Sellega muidugi suureneb anomaaliate hulk. Tugevas kooskõlas ei tohiks neid peaaegu olemagi, samas kui lõppkokkuvõtte kooskõlas võivad need olla igasugused. Tekkib küsimus: miks inimesed valivad lõppkokkuvõtte kooskõla, kui see sisaldab anomaaliaid? Vastus peitub selles, et lõppkokkuvõtte mudelid on kasutatavad ja anomaaliad eksisteerivad näiteks lühikese ajavahemiku jooksul; on võimalus kasutada meistrit lugemiseks ja enam-vähem lugeda järjepidevaid andmeid; sageli on võimalus kasutada tugevaid kooskõla mudeleid. Praktikas see töötab ja anomaaliate hulk on sageli ajaliselt piiratud.

CAP teoreem

Kui näete sõnu kooskõla, saadavus – mis tuleb teile meelde? Õige – CAP teoreem! Praegu tahan ma müüti hajutada... See ei ole mina – see on Martin Kleppmann, kes kirjutas suurepärase artikli, suurepärase raamatu.

HighLoad++, Mihhail Tšulenjev (MongoDB): Causal consistency: teooriast praktikani

CAP teoreem on 2000ndatel formuleeritud põhimõte selle kohta, et Kooskõla, Saadavus, Jagunemised: vali ükskõik kaks, kuid ei saa valida kolme. See oli teatud põhimõte. Seda tõestati teoreemina mõni aasta hiljem, selle tegid Gilbert ja Lynch. See sai kasutusele võetud nagu mantra – süsteemid hakkasid jagunema CA, CP, AP jne.

See teoreem oli tegelikult tõestatud järgmiste juhtumite jaoks... Esiteks, Saadavust vaadeldi mitte kui pidevat väärtust nullist sajani (0 – süsteem on ‘surnud’, 100 – vastab kiiresti; oleme harjunud seda nii vaatama), vaid kui algoritmi omadust, mis tagab, et kõigi oma täitmiste korral tagastab ta andmed.

Vastuse aja kohta ei ole seal ühtegi sõna! On algoritm, mis tagastab andmed 100 aasta jooksul – täiesti suurepärane saadav algoritm, mis on osa CAP teoreemist.
Teiseks: teoreemi tõestati sama võtme väärtuste muutuste jaoks, olles need muutused samas suuruses. See tähendab, et neid ei kasutata sisuliselt, kuna teised mudelid on Lõppkokkuvõtte kooskõla, Tugev kooskõla (võib-olla).

Milleks see kõik? Selleks, et CAP teoreem just sellises vormis, nagu see on tõestatud, on praktiliselt rakendatav, harva kasutatav. Teoreetilises vormis piirab see kuidagi kõike. Tulemuseks on teatud põhimõte, mis on intuitiivselt tõene, kuid ei ole üldiselt tõestatud.

Kausaalne kooskõla – kõige tugevam mudel

Praegu toimuval on võimalik saavutada kolme asja: järjepidevus, kättesaadavus, kasutades partiisid. Eriti causaalne järjepidevus on kõige tugevam järjepidevuse mudel, mis töötab isegi partiide (võrkude katkestuste) korral. Seetõttu on see nii huvitav ja seetõttu oleme sellega tegelenud.

HighLoad++, Mihhail Tšulenjev (MongoDB): Causal consistency: teooriast praktikani

Esiteks lihtsustab see rakenduste arendajate tööd. Eriti serveri suur toe olemasolu: kui kõik kirjed, mis toimuvad ühe kliendi sees, jõuavad garanteeritult teisele kliendile kindlas järjekorras. Teiseks talub see katkestusi.

MongoDB siseköök

Mäletades, et on lõuna, liikumme kööki. Räägin süsteemi mudelist, nimelt – mis on MongoDB nende jaoks, kes kuulevad sellisest andmebaasist esmakordselt.

HighLoad++, Mihhail Tšulenjev (MongoDB): Causal consistency: teooriast praktikani

HighLoad++, Mihhail Tšulenjev (MongoDB): Causal consistency: teooriast praktikani

MongoDB (edaspidi – „MongoDB”) on jaotatud süsteem, mis toetab horisontaalset skaleerimist, see tähendab sharding’ut; ja iga shard’i sees toetab see ka andmete üleliigsust, see tähendab replikatsiooni.

Sharding „MongoDB-s” (mitte-relatsiooniline andmebaas) teostab automaatset tasakaalustamist, see tähendab, et iga dokumentide kogu (või „tabel” relatsiooniliste andmete terminoloogias) jaotatakse osadeks, ja server liigutab neid automaatselt shardi vahel.

Küsimuste router, mis jaotab päringud, on kliendi jaoks teatud klient, mille kaudu ta töötab. Ta juba teab, kus ja milliseid andmeid leidub, suunab kõik päringud õigele shardile.

Veel üks oluline punkt: MongoDB on ühe peaga. On üks primaarne – ta saab vastu võtta kirjeid, mis toetavad neid võtmeid, mida ta endas sisaldab. Multi-master kirjutamist teha ei saa.

Oleme välja andnud versiooni 4.2 – seal on uusi huvitavaid asju. Eriti, oleme sisse viinud Lucene'i - otsingu - nimelt käideldava java otse „Mongo” sees, ja seal on nüüd võimalik otsida läbi Lucene, sama nagu „Elasticsearchis”.

Ja oleme teinud uue toote – Charts, see on samuti saadaval „Atlasel” (oma Mongo pilve). Neil on Free Tier – saab sellega katsetada. Charts meeldis mulle väga – andmete visualiseerimine, väga intuitiivne.

Causaalse järjepidevuse koostisosad

Olen lugenud umbes 230 artiklit, mis on sellel teemal avaldatud – Leslie Lampertilt. Praegu toimetan teieni mõningad osad nendest materjalidest oma mälust.

HighLoad++, Mihhail Tšulenjev (MongoDB): Causal consistency: teooriast praktikani

Kõik sai alguse Leslie Lamperti artiklist, mis kirjutati 1970. aastatel. Nagu näete, jätkatakse endiselt selle teema uurimist. Praegu elab Causal consistency huvi seoses jaotatud süsteemide arenguga.

Piirangud

Millised on piirangud? See on tegelikult üks peamisi punkte, kuna tootmissüsteemide kehtestatud piirangud erinevad oluliselt akadeemilistes artiklites esitatud piirangutest. Tihti on need piisavalt kunstlikud.

HighLoad++, Mihhail Tšulenjev (MongoDB): Causal consistency: teooriast praktikani

  • Esiteks, „MongoDB“ on üksikmeistriga, nagu ma juba ütlesin (see lihtsustab oluliselt).
  • Usume, et süsteem peaks toetama umbes 10 000 shard'i. Me ei saa teha mingeid arhitektuurilisi otsuseid, mis piiraksid selgelt seda väärtust.
  • Meil on pilv, kuid me arvestame, et inimesel peaks olema võimalus, kui ta allalaadib binaari, käivitada see oma sülearvutis ja et kõik töötaks hästi.
  • Me arvame, et teadustöös kasutatakse harva: välised kliendid saavad teha mida iganes. „MongoDB“ on avatud lähtekoodiga. Seega võivad kliendid olla piisavalt nutikad, pahatahtlikud – nad võivad soovida kõike hävitada. Arvestame, et võivad esineda Bütsantsi veaolukorrad.
  • Välistele klientidele, kes on perimeetri väljaspool – oluline piirang: kui see funktsioon on välja lülitatud, ei peaks olema mingeid jõudluse langusi.
  • Veel üks punkt – täiesti antiakadeemiline: varasemate ja tulevaste versioonide ühilduvus. Vanad draiverid peavad toetama uusi uuendusi ja andmebaas peab toetama vanu draivereid.

Üldiselt, kõik see kehtestab piirangud.

Causal consistency komponendid

Käin nüüd läbi mõned komponendid. Kui vaadata Causal consistency't laiemalt, saab eristada plokke. Valisime teosed, mis kuuluvad mingisse plokki: sõltuvuse jälgimine, kellade valik, kuidas neid kellasid omavahel sünkroniseerida, ning kuidas tagame turvalisuse – see on umbkaudne plaan, millest ma räägin:

HighLoad++, Mihhail Tšulenjev (MongoDB): Causal consistency: teooriast praktikani

Täielik sõltuvuse jälgimine (Full Dependency Tracking)

Miks see vajalik on? Selleks, et andmed replikeerimisel sisaldaks iga kirje, iga andme muudatus teavet, millest muudatused sõltuvad. Kõige esimene ja naiivne muudatus on see, et iga sõnum, mis sisaldab kirjet, sisaldab teavet eelnevate sõnumite kohta:

HighLoad++, Mihhail Tšulenjev (MongoDB): Causal consistency: teooriast praktikani

Käesolevas näites tähistavad sulgudes olevad numbrid kirjeid. Mõnikord edastatakse need kirjed koos väärtustega tervikuna, mõnikord edastatakse versioonid. Idee on selles, et iga muudatus sisaldab teavet eelneva kohta (see kannab seda endas).

Miks me otsustasime mitte kasutada sellist lähenemist (täielik jälgimine)? Ilmselgelt, sest see lähenemine on ebapraktiline: iga muudatus sotsiaalvõrgustikus sõltub kõikidest eelnevatest muudatustest selles võrgustikus, edastades näiteks "Facebooki" või "Vkontakte'i" igas uuenduses. Siiski on palju uuringuid, mis käsitlevad just Full Dependency Tracking’ut – see on enne sotsiaalvõrgustikke, teatud olukordades töötab see tõepoolest.

Selge sõltuvuse jälgimine (Explicit Dependency Tracking)

Järgmine – piiratum. Siin käsitletakse samuti teabe edastamist, kuid ainult selle, mis sõltub otseselt. Millest mis sõltub, määrab enamasti juba rakendus. Kui andmed replikeeritakse, siis antakse päringu tulemused ainult siis, kui eelnevad sõltuvused on rahuldatud, st näidatud. Just selles seisneb põhjuslik konsistentsus.

HighLoad++, Mihhail Tšulenjev (MongoDB): Causal consistency: teooriast praktikani

Ta näeb, et kirje 5 sõltub kirjete 1, 2, 3, 4-st – seega ootab ta, enne kui klient saab juurdepääsu muudatustele, mis on tehtud Penny juurdepääsu määrusega, kui kõik eelnevad muudatused on andmebaasis juba läbitud.

See ei sobi meile samuti, kuna teavet on ikkagi liiga palju ja see aeglustab. On teine lähenemine...

Lamporti kell (Lamport Clock)

Need on väga vanad. Lamporti kell tähendab, et need sõltuvused koondatakse skalaarsesse funktsiooni, mida nimetatakse Lamporti kellaks.

Skalaarfunktsioon on teatud abstraktne number. Tihti nimetatakse seda loogiliseks ajaks. Iga sündmuse korral see counter suureneb. Counter, mis hetkel on protsessile tuntud, saadab iga sõnumi. On selge, et protsessid võivad olla desünhroniseeritud, neil võib olla täiesti erinev aeg. Sellegipoolest tasakaalustab süsteem sellise sõnumivahetuse kaudu kellasid. Mis juhtub sellisel juhul?

Ma jagasin selle suure shard'i kaheks, et oleks aru saada: Friends võivad elada samas noodis, mis sisaldab osa kogumist, ja Feed – täiesti teises noodis, kus on osa sellest kogumist. Kuidas nad siis võivad mitte ootele jääda? Esiteks ütleb Feed: „Replitseeritud”, seejärel – Friends. Kui süsteem ei taga mingit garantiid, et Feed ei kuvatakse enne, kui Friends'i kogumi sõltuvused on samuti toimetatud, siis tekib see olukord, millest ma mainisin.

Näete, kuidas loogiliselt counter Feed’is suureneb:

HighLoad++, Mihhail Tšulenjev (MongoDB): Causal consistency: teooriast praktikani

Seega on Lamporti kella ja kausaalse järjepidevuse (mida on selgitatud Lamporti kella kaudu) põhijoon järgmine: kui meil on sündmused A ja B ning sündmus B sõltub sündmusest A *, siis sellest järeldub, et Loogiline Aeg sündmusele A on väiksem kui Loogiline Aeg sündmusele B.

* Mõnikord öeldakse ka, et A juhtus enne B, st A juhtus enne B – see on teatud suhe, mis osaliselt järjestab kogu sündmuste hulga, mis kunagi juhtunud on.

Tagurpidi ei pea see paika. See on tegelikult üks peamisi puudusi Lamporti kella – osaline järjestus. Seal on mõisted samasugustest sündmustest, st sündmustest, kus ei (A happened before B) ega (B happened before A). Näiteks võib tuua paralleelse Lisa, kellele Leonardi sõbraks tegemine on kellegi teise (isegi mitte Leonardi, vaid näiteks Sheldoni) poolt.
See on omadus, mida sageli kasutatakse Lamporti kellade töös: vaatakse just funktsiooni ja sellest tehakse järeldus – need sündmused võivad olla sõltuvad. Sest ühes suunas see kehtib: kui Loogiline Aeg A on väiksem kui Loogiline Aeg B, siis B ei saa juhtuda enne A; kui see on rohkem, siis võib olla.

Vektorikellad (Vector Clock)

Lamporti kellade loogiline areng on Vektorikellad. Need erinevad seetõttu, et iga siin olev nood sisaldab oma, eraldi kella, ja need edastatakse vektorina.
Antud juhul näete, et vektori nullindeks vastutab Feed'i eest, samas kui esimene indeks vastutab Friends'i eest (igaüks neist nodest). Ja need hakkavad nüüd suurenema: nullindeks "Feed" suureneb, kui see salvestatakse – 1, 2, 3:

HighLoad++, Mihhail Tšulenjev (MongoDB): Causal consistency: teooriast praktikani

Miks on vektorikellad paremad? Kuna nad võimaldavad mõista, millised sündmused on samaaegsed ja millal nad erinevates nodedes toimuvad. See on väga oluline sharding-süsteemi jaoks, nagu "MongoDB". Kuid me ei valinud seda, kuigi see on suurepärane asi, töötab suurepäraselt ja oleks meile tõenäoliselt sobinud...

Kui meil on 10 000 shard'i, ei saa me edastada 10 000 komponenti, isegi kui me komprimeerime või mõtleme midagi muud välja – kasulik koormus jääb ikkagi palju väiksemaks kui kogu selle vektori maht. Seetõttu, südame ja hammaste krigistamisega, loobusime sellest lähenemisest ja läksime edasi teise.

Spanner TrueTime. Aatomikellad

Ma rääkisin, et tulemas on jutt "Spannerist". See on äge asi, justkui XXI sajand: aatomikellad, GPS-sünkroniseerimine.

Mis on idee? "Spanner" on Google'i süsteem, mis hiljuti muutus isegi inimeste jaoks kergesti kättesaadavaks (nad lisasid sellele SQL-i). Igal tehingul on seal teatud ajatemperatuur. Kuna aeg on sünkroniseeritud*, saab igale sündmusele määrata kindla ajatemperatuur – aatomikelladel on ooteaeg, mille möödudes toimub garantiiga juba mingi muu aeg.

HighLoad++, Mihhail Tšulenjev (MongoDB): Causal consistency: teooriast praktikani

Seega, lihtsalt andmebaasi kirjutades ja oodates teatud aja, garanteeritakse automaatselt sündmuse Serializability. Neil on kõige tugevam Consistency mudel, mida üldse ette kujutada saab – see on External Consistency.

* See on peamine probleem Lamporti kelladega – nad ei ole kunagi sünkroonis jaotatud süsteemides. Nad võivad töödelda isegi NTP puhul mitte väga hästi. "Spanner" on varustatud aatomikellade ja sünkroniseerimisega, tundub, et mikrosekundite täpsusega.

Miks me seda ei valinud? Me ei eelda, et meie kasutajatel on olemas sisse ehitatud aatomikellad. Kui need oleksid olemas, korralikult igasse sülearvutisse integreeritud, oleks seal mingi superäge GPS-sünkroniseerimine – siis jah... Siiski, hetkel on parim, mis võimalik – "Amazon", Base Stations – fanaatikute jaoks... Seetõttu kasutasime teisi kelli.

Hübriidkell (Hybrid Clock)

See, mis see tõukab «MongoDB» Causal consistency'i tagamiseks. Kuidas need hübriidsed on? Hübriid on skalaarsed väärtused, kuid need koosnevad kahest komponendist:

HighLoad++, Mihhail Tšulenjev (MongoDB): Causal consistency: teooriast praktikani

  • Esimene on unix'i ajajoon (kui palju sekundeid on möödunud «arvutimaailma algusest»).
  • Teine on teatud inkrement, samuti 32-bitine unsigned int.

See ongi kõik. On olemas lähenemine: osa, mis vastutab aja eest, sünkroniseeritakse pidevalt kelladega; iga kord, kui toimub värskendus, sünkroniseeritakse see osa kelladega ja tulemusena on aeg alati enam-vähem õige, samas kui inkrement võimaldab eristada sündmusi, mis juhtusid samal ajal.

Miks see on «MongoDB» jaoks oluline? Sest see võimaldab teha varukoopiaid teatud ajahetkel, see tähendab, et sündmus indekseeritakse ajaks. See on oluline, kui on vaja mõningaid sündmusi; andmebaasi jaoks on sündmused need muudatused andmebaasis, mis toimusid teatud ajahetkedel.

Ma ütlen teile ainult peamise põhjuse (palun, ärge rääkige seda kellelegi)! Me tegime seda nii, kuna just nii näevad välja korraldatud, indekseeritud andmed MongoDB OpLog'is. OpLog on andmestruktuur, mis sisaldab kõiki muudatusi andmebaasis: need satuvad esmalt OpLog'i ja siis rakendatakse need juba andmesalvestamisele, kui tegemist on replikatsiooniandmete või shard'iga.

See oli peamine põhjus. Siiski on olemas ka praktilised nõudmised andmebaasi arendusele, mis tähendab, et see peab olema lihtne – vähem koodi, võimalikult vähe purunenud asju, mida tuleks ümber kirjutada ja testida. See, et meie op-logid osutusid indekseeritud hübriidsete kelladega, aitas palju ja võimaldas teha õige valiku. See tõesti õigustas end ja töötas kuidagi maagiliselt, juba esimeses prototüübis. Oli väga äge!

Kellade sünkroniseerimine

On mitmeid viise sünkroonimiseks, nagu on kirjeldatud teaduslikus kirjanduses. Ma räägin sünkroonimisest, kui meil on kaks erinevat shard'i. Kui on olemas vaid üks replika-grupp, ei ole sünkroonimine vajalik: see on 'üks-ise-juhtiv'; meil on OpLog, kuhu kõik muudatused jõuavad – sellisel juhul on kõik juba järjekorras 'OpLogis'. Kuid kui meil on kaks erinevat shard'i, on siin ajasünkroonimise tähtsus suur. Just siin aitasid vektorkellad rohkem! Aga meil neid pole.

HighLoad++, Mihhail Tšulenjev (MongoDB): Causal consistency: teooriast praktikani

Teine sobiv variant on 'Südamelöögid' (Heartbeats). Saame vahetada teatud signaale, mis toimuvad iga ajavahemiku järel. Kuid 'Südamelöögid' on liiga aeglased, me ei saa klientidele tagada madalat latentsust.

Tõeline aeg – muidugi, see on suurepärane asi. Kuid jälle, see on ilmselt tulevik... Kuigi 'Atlas' võimaldab seda juba, on olemas kiired 'Amazon'i aegade sünkroonijad. Kuid see ei ole kõigile kergesti ligipääsetav.

Kossipimine (Gossiping) – see on siis, kui kõik sõnumid sisaldavad aega. See on umbes see, mida me kasutame. Iga sõnum node'ide vahel, draiver, andmete node'i ruuter – absoluutselt kõik 'MongoDB' jaoks – on mingid elemendid, andmebaasi komponendid, mis sisaldavad kelli, mis tiksuvad. Neil kõigil on hübriidse aja väärtus, see edastatakse. 64 bitti? See on lubatud, see on võimalik.

Kuidas kõik see koos töötab?

Siin vaatlen ühte replika-gruppi, et see oleks veidi lihtsam. On olemas Primaarne ja Sekundaarne. Sekundaarne teostab replikatsiooni ja ei ole alati täielikult sünkroonitud Primaarsega.

Toimub sisestamine (insert) 'Primaaris' koos mingi ajaväärtusega. See sisestamine suurendab siseselt loendurit 11 võrra, kui see on maksimaalne. Või see kontrollib kellade väärtusi ja sünkroonib kellade järgi, kui kellade väärtused on suuremad. See võimaldab aega järjestada.

Pärast seda, kui ta teeb kirje, toimub oluline moment. Kellad 'MongoDB's' ja inkrementeeritakse ainult kirje tegemise korral 'Oplogis'. See on see sündmus, mis muudab süsteemi olekut. Absoluutselt kõigis klassikalistes artiklites peetakse sündmuseks sõnumi jõudmist node'isse: sõnum on saabunud – see tähendab, et süsteem muutis oma olekut.

See, when studying this, it's not entirely clear how this message will be interpreted. We know for sure that if it is not reflected in the 'OpLog', it will not be interpreted at all, and changing the state of the system is only a record in the 'OpLog'. This simplifies everything for us: both the model is simplified, and it allows for ordering within a single replica set, along with many other useful things.

The value that has already been recorded in the 'OpLog' is returned – we know this value is in the 'OpLog', and its time is 12. Now, let's say reading starts from another node (Secondary), and it already transmits afterClusterTime in the message. It says: 'I need everything that happened at least after 12 or at twelve' (see the figure above).

This is what is called Causal and consistent (CAT). There is a concept in theory that this is some slice of time that is consistent in itself. In this case, we can say that this is the state of the system that was observed at the time of 12.

Currently, there's nothing here yet because it simulates a situation where the Secondary needs to replicate data from the Primary. It's waiting... And then the data arrives – it returns these values back.

HighLoad++, Mihhail Tšulenjev (MongoDB): Causal consistency: teooriast praktikani

This is roughly how it works. Almost.

What does 'almost' mean? Let's assume there is a person who read and understood how it all works. They understood that every time there is a ClusterTime, it updates the internal logical clocks, and then the next record increments by one. This function takes 20 lines. Suppose this person transmits the largest possible 64-bit number, minus one.

Why 'minus one'? Because the internal clocks will be substituted into this value (obviously, this is the largest possible, greater than the current time), then a record will be made in the 'OpLog', and the clocks will increment by one more – and it will already be the maximum value (there are just all ones, there’s nowhere to go, unsigned ints).

It's clear that after this, the system becomes absolutely unavailable for anything. It can only be unloaded, cleaned – a lot of manual work. Full availability:

HighLoad++, Mihhail Tšulenjev (MongoDB): Causal consistency: teooriast praktikani

Kuna see replitseerub kuhugi mujale, siis kukub kogu klaster lihtsalt kokku. Absoluutselt vastuvõetamatu olukord, mille iga inimene saab kiiresti ja lihtsalt korraldada! Seetõttu pidasime seda aspekti üheks olulisemaks. Kuidas seda ennetada?

Meie tee on allkirjastada clusterTime

Nii edastatakse see sõnumis (sinise teksti all). Kuid me hakkasime ka genereerima allkirja (sinine tekst):

HighLoad++, Mihhail Tšulenjev (MongoDB): Causal consistency: teooriast praktikani

Allkiri genereeritakse võtme abil, mis on salvestatud andmebaasi, kaitstud perimeetris; see genereeritakse ja uuendatakse (kasutajad ei näe sellest midagi). Genereeritakse hash, ja iga sõnum allkirjastatakse loomise ajal ning vastuvõtmise ajal valideeritakse.
Tõenäoliselt tekib inimestel küsimus: „Kui palju see kõike aeglustab?” Ma ütlesin, et see peaks kiiresti töötama, eriti ilma selle funktsioonita.

Mida tähendab Causal consistency kasutamine antud juhul? See näitab afterClusterTime parameetrit. Ilma selleta edastab see väärtusi igal juhul. Gossiping töötab alates versioonist 3.6 alati.

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

Tee seda kiiresti!

Vihtsasti lihtne asi, aga trikk on huvitav – jagan, võib-olla kellelegi on kasulik.
Meil on hash, milles on allkirjastatud andmed. Kõik andmed lähevad läbi cache'i. Cache allkirjastab mitte konkreetselt aja, vaid Rangi. Kui tuleb mingi väärtus, genereerime Rangi, maskeerime viimased 16 bitti ja seda väärtust me allkirjastame:

HighLoad++, Mihhail Tšulenjev (MongoDB): Causal consistency: teooriast praktikani

Saades sellise allkirja, kiirendame süsteemi (tinglikult) 65 tuhat korda. See töötab suurepäraselt: katsetades - seal on tõeliselt 10 tuhande võrra aega vähenenud, kui meil on järjepidev uuendus. Ilmselgelt, kui need on segaduses, ei toimi see. Kuid enamikes praktilistes olukordades see töötab. Allkirja Rangi kombinatsioon koos allkirjaga aitas lahendada turvalisuse probleemi.

Selge on, et iga teenus püüab vältida seisakuid. Meie puhul usume, et hiljutised katkestused aitasid teha quay.io paremaks. Meie jaoks tõime välja mitmed peamised õppetunnid, mida soovime jagada:

Õppetunnid, mille me sellest õppisime:

  • Materjale, lugusid ja artikleid tuleb lugeda, kuna meil on palju huvitavat. Kui me töötame mingi funktsiooni kallal (eriti praegu, kui oleme teinud tehingute osas jne), siis tuleb lugeda ja mõista. See võtab aega, kuid see on tegelikult väga kasulik, kuna selgub, kus me oleme. Me ei ole midagi uut välja mõelnud – lihtsalt võtsime koostisosad.

    Koosolekute korral, nagu näiteks akadeemilised konverentsid („Sigmon”), on mõtlemises kindel erinevus – seal keskenduvad kõik uutele ideedele. Kus on meie algoritmi uuenduslikkus? Siin uut pole. Uuendus seisneb pigem selles, kuidas me segasime kokku olemasolevaid lähenemisviise. Seepärast tuleb kõigepealt lugeda klassikuid, alustades Lamportist.

  • Tootmises on nõudmised täiesti teised. Olen kindel, et paljud teist ei puutu kokku „sfääriliste” andmebaasidega abstraktses vaakumis, vaid normaalses, reaalses maailmas, kus esinevad kättesaadavuse, latentsuse ja talitluse järjepidevuse probleemid.
  • Viimase asjana pidime arvestama erinevaid ideid ja kombineerima mitmest täiesti erinevast artiklist ühe lähenemise. Näide allkirjastamisest tuli täiesti artiklist, mis käsitles Paxosi protokolli, mis on mõeldud mitte-byzantia aluste ebaõnnestumiseks autoriseerimisprotokollis, byzantiaalsete jaoks aga selle piiridest väljas... Ühesõnaga, see on just see, mida me lõpuks tegime.

    Siin pole absoluutselt midagi uut! Kuid kui me kõik selle kokku segasime... On sama, mis öelda, et Olivier salati retsept on vale, kuna munad, majonees ja kurk on juba välja mõeldud... See on umbes sama lugu.

HighLoad++, Mihhail Tšulenjev (MongoDB): Causal consistency: teooriast praktikani

Sellega lõpetan. Aitäh!

Küsimused

Küsimus saalist (edasi - K): – Aitäh, Mihhail, et esitlesite! Aeg on huvitav teema. Te kasutate Gossiping'ut. Ütlesite, et kõigil on oma aeg, kõik teavad oma kohalikku aega. Olen aru saanud, et meil on draiver – kliente ja draivereid võib olla palju, samuti query-planner'eid, shard'e, neid on samuti palju... Kuidas süsteem sellisel juhul käitub, kui äkki tekib lahknevus: keegi arvab, et ta on minuti ees, keegi – minuti taga? Kuhu me jääme?

MT: – Suurepärane küsimus! Ma tahtsin just shardidest rääkida. Kui ma õigesti küsimusest aru saan, siis meil on selline olukord: on shard 1 ja shard 2, lugemine toimub nende kahe shardiga – neil on erinevus, nad ei suhtle omavahel, kuna aeg, mida nad tunnevad, on erinev, eriti aeg, mil nad eksisteerivad oplogides.
Oletame, et shard 1 tegi miljon kirjet, shard 2 ei teinud midagi, ja päring tuli kahte shardi. Ja esimesel on afterClusterTime rohkem kui miljon. Sellises olukorras, nagu ma selgitasin, shard 2 kunagi ei vasta.

K: – Soovisin teada, kuidas nad sünkroniseeruvad ja valivad ühe loogilise aja?

MT: – Need sünkroniseeruvad väga lihtsalt. Shard, kui talle tuleb afterClusterTime ja ta ei leia aega „Oplogist” – algatab no approved. See tähendab, et ta tõstab ise oma aega sellele väärtusele. See tähendab, et tal ei ole sündmusi, mis vastavad sellele päringule. Ta loob selle sündmuse kunstlikult ja muutub seega Causal Consistent.

K: – Ja kui talle pärast seda saabuvad veel mingid sündmused, mis kuskil võrgus kaotsi läksid?

MT: – Shard on nii ehitatud, et need ei saabu enam, kuna see on üksik master. Kui ta on juba kirja pannud, siis need ei saabu enam, vaid jäävad hiljem. Ei saa nii olla, et kuskil midagi jääb seisma, siis ta teeb no write, ja seejärel need sündmused saabuvad – ja Causal consistency on rikutud. Kui ta teeb no write, peavad nad kõik edasi saabuma (ta ootab neid).

HighLoad++, Mihhail Tšulenjev (MongoDB): Causal consistency: teooriast praktikani

K: – Mul on mõned küsimused järjekordade kohta. Causal consistency eeldab, et on olemas teatud tegevuste järjekord, mis tuleb teostada. Mis juhtub, kui meil kaob üks pakett? Siis läks 10., 11... 12. kaduma, aga kõik teised ootavad, kuni see täidetakse. Ja äkki on meie masin surnud, me ei saa midagi teha. Kas on mingi maksimaalne järjekorra pikkus, mis koguneb, enne kui see täidetakse? Mis on fataalne rike, mis juhtub ühe staatuse kaotamisel? Eriti kui me salvestame, et on mingi eelmine seisund, siis peaksime justkui sellest lähtuma? Aga me ei saanudki lähtuda!

MT: – Samuti suurepärane küsimus! Mida me teeme? MongoDB-s on kvorumkirjete ja kvorumlugemise mõisted. Millal sõnum võib kaduda? Kui teadmine ei ole kvorum või kui lugemine ei ole kvorum (võib tekkida mingi prügi).
Seoses Causal consistency teostasime ulatusliku eksperimentaalse kontrolli, mille tulemuseks oli, et siis, kui salvestamine ja lugemine on mitte-kvoorumlikud, esinevad Causal consistency rikkumised. Just nii, nagu te räägite!

Meie soovitus: kasutage vähemalt kvoorumlikku lugemist Causal consistency rakendamisel. Sel juhul ei kaota te midagi, isegi kui kvoorumlik salvestamine peaks kaduma... See on ortogonaalne olukord: kui kasutaja ei soovi, et andmed kaoksid, tuleb kasutada kvoorumlikku salvestamist. Causal consistency ei anna püsivuse tagatist. Püsivuse tagatist annab replikaator ja replikatsiooniga seotud mehhanism.

K: – Kui me loome instantsi, mis tegeleb shardimisega (mitte master, vaid slave vastavalt), toetub see enda masina unix-ajal või «maistri» ajale; kas see sünkroniseeritakse esmakordselt või perioodiliselt?

MT: – Selgitan hetkel. Shard (st horisontaalne partitsioon) – seal on alati Primaarne. Ja shardis võib olla «maaster» ning replikad. Kuid shard toetab alati salvestamist, sest see peab toetama mingit domeeni (shardis on Primaarne).

K: – Kas see tähendab, et kõik sõltub ainult «maistrist»? Kas alati kasutatakse «maistri» aega?

MT: – Jah. Kujundlikult öeldes: kellad tikuvad, kui salvestamine toimub «maistris», «Oplogis».

K: – Meil on klient, kes ühendub ja ei pea ajast midagi teadma?

MT: – Üldse mitte midagi ei pea teadma! Kui rääkida, kuidas see kliendi poolel töötab: kliendil, kui ta tahab kasutada Causal consistency, tuleb avada sessioon. Seal on kõik: nii sessioonis olevad tehingud kui ka õiguste hankimine… Sessioon on loogiliste sündmuste järjestamine, mis juhtuvad kliendiga.

Kui ta avab selle sessiooni ja ütleb, et tahab Causal consistency (kui sessioon toetab vaikimisi Causal consistency), toimib kõik automaatselt. Draiver mäletab seda aega ja suurendab seda, kui saab uue sõnumi. Ta mäletab, millise vastuse eelmine server andis, mis andmed tagastas. Järgmine päring sisaldab afterCluster («aeg suurem kui see»).

Klient ei pea teadma täpselt midagi! See on tema jaoks täiesti läbipainev. Kui inimesed kasutavad neid funktsioone, siis mis see võimaldab? Esiteks saab turvaliselt lugeda sekundaarseid: saab kirjutada Primaarsele ja lugeda geograafiliselt replitseeritud sekundaarsetelt ning olla kindel, et see töötab. Samal ajal saab Primaarsele kirjutatud sessioone edastada isegi Sekundaarsele, st saab kasutada mitut sessiooni.

K: – Töötlusteadusest on tihedalt seotud uus plaan, milleks on CRDT (Conflict-free Replicated Data Types) andmetüübid. Kas olete kaalunud nende andmetüüpide integreerimist andmebaasi ja mida saate selle kohta öelda?

MT: – Heal küsimuse! CRDT-l on mõtet kirjutamisvaidluste korral: MongoDB-s on see üksikmeistrina.

K: – Mul on dev-opsidelt küsimus. Tõelises maailmas esinevad sellised keerulised olukorrad, kus toimub Bütsantsi rike, ja halvad inimesed kaitstud perimeetri sees hakkavad protokolli nuhkima, saates spetsiaalselt valmistatud pakette?

HighLoad++, Mihhail Tšulenjev (MongoDB): Causal consistency: teooriast praktikani

MT: – Halvad inimesed perimeetri sees on nagu troojalane! Halvad inimesed perimeetri sees saavad teha palju halbu asju.

K: – Loomulikult ei ole õige jätta serverisse, ütleme, auku, mille kaudu saab suur elevant sisse suruda ja kogu klastrit igaveseks kokku kukutada... See nõuab käsitsi taastamiseks aega... See on, pehmelt öeldes, vale. Teiselt poolt, huvitav on see, et reaalses elus, praktikas esinevad sellised olukorrad, kus tõeliselt aset leidnud sisesed rünnakud juhtuvad?

MT: – Kuna ma ei puutu elus sageli kokku turvalisuse rikkumisega, ei saa ma öelda - võib-olla need ikkagi juhtuvad. Aga kui rääkida arendustfilosoofiast, siis arvame nii: meil on perimeeter, mis tagab need, kes tegelevad turvalisusega - see on lukustusemüür; ja perimeetri sees võib teha kõike, mida iganes. On selge, et on kasutajad, kes saavad ainult vaadata, ja on kasutajad, kellel on võimalus katalooge kustutada.

Sõltuvalt õigustest võib kasutajate tekitatud kahju olla hiire või isegi elevandi tase. Selge on, et täielike õigustega kasutaja võib teha absoluutselt kõike. Kasutaja, kellel on piiratud õigused, võib tekitada oluliselt vähem kahju. Eriti ei saa ta süsteemi purustada.

K: – Suletud perimeetris püüab keegi serveri jaoks ootamatuid protokolle koostada, et serverit alandada ja ehk isegi kogu klastrit… Kas see võib olla nii "hea"?

MT: – Ma pole kunagi sellistest asjadest kuulnud. Et serverit saab sel viisil tõrjuda – see ei ole saladus. Tõrjumine seestpoolt, olles protokollis, olles autoriseeritud kasutaja, kes suudab sõnumisse midagi kirjutada… Tegelikult ei saa, sest see verifitseeritakse ikkagi. On võimalus keelata see autentimine kasutajatele, kes seda ei soovi – see on siis nende probleem; nad on nagu omal käel seinu purustanud ja sinna elevandi toppida, mis kõik purustab… Aga tegelikult, võib remondimehena riides tulla ja välja tõmmata!

K: – Aitäh ettekande eest. Sergei ("Yandex"). "Mongos" on konstant, mis piirab hääletavate liikmete arvu Replica Set’is, ja see konstant on 7 (seitsme). Miks see on konstant? Miks mitte mõni parameter?

MT: – Replica Set’id võivad meil olla ka 40 node’iga. Seal on alati enamuse reegel. Ma ei tea, mis versioon see on…

K: – Replica Set’is võib hääletamata liikmeid käivitada, aga hääletavaid – maksimaalselt 7. Kuidas sel juhul taluda katkestust, kui meie Replica Set on kolme andmekeskuse vahel? Üks andmekeskus võib üsna lihtsalt välja lülituda ja veel üks masin võib kaduda.

MT: – See on juba veidi väljaspool ettekannet. See on üldine küsimus. Võib-olla räägin sellest hiljem.

HighLoad++, Mihhail Tšulenjev (MongoDB): Causal consistency: teooriast praktikani

Mängi videot

Veidi reklaami 🙂

Aitäh, et olete meiega. Kas teile meeldivad meie artiklid? Kas soovite näha rohkem huvitavat sisu? Toetage meid, tellides teenuse või soovitades meid tuttavatele. Pilve VPS arendajatele alates $4.99, ainulaadne entry-level serverite analoog, mille oleme teie jaoks välja mõelnud: Kogu tõde VPS (KVM) E5-2697 v3 (6 Cores) 10GB DDR4 480GB SSD 1Gbps alates $19 või kuidas jagada serverit õigesti? (saadaval RAID1 ja RAID10 variandid, kuni 24 tuuma ja kuni 40GB DDR4).

Dell R730xd on Equinixi Tier IV andmekeskuses Amsterdamis kaks korda odavam? Ainult meie juures 2 x Intel TetraDeca-Core Xeon 2x E5-2697v3 2.6GHz 14C 64GB DDR4 4x960GB SSD 1Gbps 100 TB alates $199 Hollandis! Dell R420 — 2x E5-2430 2.2Ghz 6C 128GB DDR3 2x960GB SSD 1Gbps 100TB — alates $99! Lugege sellest Kuidas luua ettevõtte tasemel infrastruktuuri, kasutades Dell R730xd E5-2650 v4 servereid, mille hind on 9000 eurot, taskukohase hinna eest?

Allikas: habr.com

Osta usaldusväärne hostimine veebilehtede jaoks DDoS-i kaitsega, VPS VDS serverid 🔥 Osta usaldusväärne hostimine veebilehtede jaoks DDoS-i kaitsega, VPS VDS serverid | ProHoster