HighLoad++, Mikhail Tyulenev (MongoDB): Vzročna doslednost: od teorije do prakse

Naslednja konferenca HighLoad++ bo 6. in 7. aprila 2020 v St.
Podrobnosti in vstopnice по ссылке. HighLoad++ Siberia 2019. Dvorana "Krasnojarsk". 25. junij, 12:00. Teze in predstavitev.

HighLoad++, Mikhail Tyulenev (MongoDB): Vzročna doslednost: od teorije do prakse

Zgodi se, da so praktične zahteve v nasprotju s teorijo, kjer se ne upoštevajo vidiki, pomembni za komercialni izdelek. Ta govor predstavlja postopek izbire in kombiniranja različnih pristopov k ustvarjanju komponent vzročne doslednosti na podlagi akademskih raziskav, ki temeljijo na zahtevah komercialnega izdelka. Slušatelji se bodo seznanili z obstoječimi teoretičnimi pristopi k logičnim uram, sledenju odvisnosti, varnosti sistema, sinhronizaciji ure in zakaj se je MongoDB odločil za določene rešitve.

Mikhail Tyulenev (v nadaljevanju MT): – Govoril bom o vzročni doslednosti – to je funkcija, na kateri smo delali v MongoDB. Delam v skupini porazdeljenih sistemov, to smo storili pred približno dvema letoma.

HighLoad++, Mikhail Tyulenev (MongoDB): Vzročna doslednost: od teorije do prakse

Pri tem sem se moral seznaniti s številnimi akademskimi raziskavami, saj je bila ta lastnost precej dobro raziskana. Izkazalo se je, da niti en artikel ne ustreza zahtevam v produkcijski bazi podatkov zaradi zelo specifičnih zahtev, ki so verjetno prisotne v vsaki produkcijski aplikaciji.

Govoril bom o tem, kako mi kot potrošniki akademskih raziskav iz njih pripravimo nekaj, kar lahko nato uporabnikom predstavimo kot že pripravljeno jed, priročno in varno za uporabo.

Vzročna doslednost. Opredelimo pojme

Za začetek želim na splošno povedati, kaj je vzročna doslednost. Obstajata dva lika - Leonard in Penny (TV serija "Teorija velikega poka"):

HighLoad++, Mikhail Tyulenev (MongoDB): Vzročna doslednost: od teorije do prakse

Recimo, da je Penny v Evropi in ji želi Leonard prirediti zabavo presenečenja. In ne more si zamisliti nič boljšega, kot da jo vrže s svojega seznama prijateljev in vsem svojim prijateljem pošlje posodobitev v viru: "Osrečimo Penny!" (ona je v Evropi, medtem ko spi, vsega tega ne vidi in ne vidi, ker je ni). Na koncu izbriše to objavo, jo izbriše iz vira in obnovi dostop, tako da ne opazi ničesar in da ni škandala.
To je vse lepo in prav, vendar predpostavimo, da je sistem porazdeljen in da je šlo malo narobe. Lahko se na primer zgodi, da je do Pennyne omejitve dostopa prišlo po tem, ko se je pojavila ta objava, če dogodki niso vzročno in posledicno povezani. Pravzaprav je to primer, ko je vzročna doslednost potrebna za opravljanje poslovne funkcije (v tem primeru).

Pravzaprav so to precej netrivialne lastnosti baze podatkov - zelo malo ljudi jih podpira. Pojdimo k modelom.

Modeli doslednosti

Kaj točno je model konsistentnosti v bazah podatkov? To je nekaj jamstev, ki jih daje porazdeljeni sistem o tem, katere podatke lahko odjemalec prejme in v kakšnem zaporedju.

Načeloma se vsi modeli doslednosti zmanjšajo na to, kako podoben je porazdeljeni sistem sistemu, ki teče na primer na enem vozlišču na prenosnem računalniku. In tako je sistem, ki teče na tisočih geografsko porazdeljenih "vozliščih", podoben prenosniku, v katerem se vse te lastnosti načeloma izvajajo samodejno.

Zato se modeli konsistentnosti uporabljajo samo za porazdeljene sisteme. Vsi sistemi, ki so prej obstajali in delovali pri istem vertikalnem skaliranju, niso imeli takšnih težav. Obstajal je en vmesni pomnilnik in vse se je vedno prebralo iz njega.

Model Strong

Pravzaprav je prvi model Strong (ali linija sposobnosti dviga, kot se pogosto imenuje). To je model doslednosti, ki zagotavlja, da je vsaka sprememba, ko je potrjeno, da se je zgodila, vidna vsem uporabnikom sistema.

To ustvari globalni vrstni red vseh dogodkov v bazi podatkov. To je zelo močna lastnost konsistence in je na splošno zelo draga. Vendar je zelo dobro podprt. Je le zelo drag in počasen – le redko se uporablja. To se imenuje sposobnost dviga.

Obstaja še ena, močnejša lastnost, ki je podprta v Spannerju - imenovana zunanja doslednost. O tem bomo govorili malo kasneje.

Vzročna

Naslednji je Causal, o katerem sem govoril točno. Med Močno in Vzročno je še več podnivojev, o katerih ne bom govoril, a vse se skrčijo na Vzročno. To je pomemben model, ker je najmočnejši od vseh modelov, najmočnejša doslednost v prisotnosti omrežja ali particij.

Kavzale so pravzaprav situacije, v katerih so dogodki povezani z vzročno-posledično zvezo. Z vidika stranke jih zelo pogosto dojemajo kot Preberite svoje pravice. Če je stranka opazovala neke vrednosti, ne more videti vrednosti, ki so bile v preteklosti. Že vidi predpone. Vse se spušča na isto.
Kavzali kot konsistentni model so delno urejanje dogodkov na strežniku, pri katerem se dogodki vseh odjemalcev opazujejo v istem zaporedju. V tem primeru Leonard in Penny.

Eventualno

Tretji model je morebitna konsistentnost. To podpirajo absolutno vsi porazdeljeni sistemi, minimalni model, ki je sploh smiseln. Pomeni naslednje: ko imamo nekaj sprememb v podatkih, na neki točki postanejo konsistentni.

V takem trenutku ne reče ničesar, sicer bi se spremenila v Zunanjo doslednost - to bi bila povsem druga zgodba. Kljub temu je to zelo priljubljen model, najpogostejši. Privzeto vsi uporabniki porazdeljenih sistemov uporabljajo Eventualno doslednost.

Želim dati nekaj primerjalnih primerov:

HighLoad++, Mikhail Tyulenev (MongoDB): Vzročna doslednost: od teorije do prakse

Kaj pomenijo te puščice?

  • Zakasnitev. Ko se moč skladnosti poveča, postane večja iz očitnih razlogov: narediti morate več zapisov, pridobiti potrditev od vseh gostiteljev in vozlišč, ki sodelujejo v gruči, da so podatki že tam. Skladno s tem ima Eventualna doslednost najhitrejši odgovor, saj ga tam praviloma lahko celo zapomniš in bo to načeloma dovolj.
  • Razpoložljivost. Če to razumemo kot sposobnost sistema, da se odzove ob prisotnosti prekinitev omrežja, particij ali kakršnih koli okvar, se toleranca na napake povečuje, ko se konsistentni model zmanjšuje, saj nam zadostuje, da en gostitelj živi in ​​hkrati čas proizvede nekaj podatkov. Eventualna doslednost ne zagotavlja ničesar o podatkih – lahko je karkoli.
  • Anomalije. Ob tem pa seveda narašča število anomalij. V močni doslednosti skoraj sploh ne bi smele obstajati, v morebitni doslednosti pa so lahko karkoli. Postavlja se vprašanje: zakaj ljudje izberejo Eventualno doslednost, če vsebuje anomalije? Odgovor je, da so modeli morebitne konsistentnosti uporabni in da obstajajo anomalije na primer v kratkem časovnem obdobju; s čarovnikom je mogoče brati in bolj ali manj brati konsistentne podatke; Pogosto je mogoče uporabiti modele močne konsistence. V praksi to deluje in pogosto je število anomalij časovno omejeno.

CAP izrek

Ko vidite besedi doslednost, razpoložljivost – kaj vam pride na misel? Tako je - CAP izrek! Zdaj bi rad razblinil mit ... Nisem jaz - Martin Kleppmann je, ki je napisal čudovit članek, čudovito knjigo.

HighLoad++, Mikhail Tyulenev (MongoDB): Vzročna doslednost: od teorije do prakse

Teorem CAP je načelo, oblikovano v 2000-ih, da doslednost, razpoložljivost, razdelitve: vzemite katera koli dva in ne morete izbrati treh. Bilo je določeno načelo. Gilbert in Lynch sta ga nekaj let pozneje dokazala kot izrek. Potem se je to začelo uporabljati kot mantra – sisteme so začeli deliti na CA, CP, AP itd.

Ta izrek je bil dejansko dokazan za naslednje primere ... Prvič, Razpoložljivost ni bila obravnavana kot neprekinjena vrednost od nič do stotin (0 - sistem je "mrtev", 100 - se hitro odziva; navajeni smo tako obravnavati) , temveč kot lastnost algoritma, ki zagotavlja, da za vse svoje izvedbe vrne podatke.

O odzivnem času sploh ni niti besede! Obstaja algoritem, ki vrne podatke po 100 letih – absolutno čudovit razpoložljiv algoritem, ki je del izreka CAP.
Drugič: izrek je bil dokazan za spremembe vrednosti istega ključa, kljub dejstvu, da je te spremembe mogoče spreminjati. To pomeni, da se v resnici praktično ne uporabljajo, ker so modeli različni Eventualna doslednost, močna doslednost (morda).

Čemu je vse to? Poleg tega izrek CAP v natanko takšni obliki, kot je bil dokazan, praktično ni uporaben in se redko uporablja. V teoretični obliki nekako vse omejuje. Izkazalo se je določeno načelo, ki je intuitivno pravilno, vendar na splošno ni bilo dokazano.

Vzročna doslednost je najmočnejši model

Zdaj se dogaja, da lahko dobite vse tri stvari: doslednost, razpoložljivost z uporabo particij. Zlasti vzročna konsistentnost je najmočnejši konsistentni model, ki še vedno deluje ob prisotnosti particij (prekinitev omrežja). Zato je tako velik interes in zato smo se ga lotili.

HighLoad++, Mikhail Tyulenev (MongoDB): Vzročna doslednost: od teorije do prakse

Prvič, poenostavi delo razvijalcev aplikacij. Zlasti prisotnost velike podpore s strani strežnika: ko je zagotovljeno, da bodo vsi zapisi, ki se pojavijo znotraj enega odjemalca, prispeli v istem zaporedju na drugega odjemalca. Drugič, vzdrži predelne stene.

Notranja kuhinja MongoDB

Ko se spomnimo, da je kosilo, se premaknemo v kuhinjo. Povedal vam bom o modelu sistema, in sicer kaj je MongoDB za tiste, ki prvič slišijo za takšno bazo podatkov.

HighLoad++, Mikhail Tyulenev (MongoDB): Vzročna doslednost: od teorije do prakse

HighLoad++, Mikhail Tyulenev (MongoDB): Vzročna doslednost: od teorije do prakse

MongoDB (v nadaljevanju »MongoDB«) je porazdeljen sistem, ki podpira vodoravno skaliranje, to je sharding; in znotraj vsakega sharda podpira tudi redundanco podatkov, to je replikacijo.

Sharding v MongoDB (ne relacijski bazi podatkov) izvaja samodejno uravnoteženje, to pomeni, da je vsaka zbirka dokumentov (ali »tabela« v smislu relacijskih podatkov) razdeljena na dele, strežnik pa jih samodejno premika med drobci.

Query Router, ki distribuira zahteve, je za odjemalca nek odjemalec, preko katerega deluje. Že ve, kje in kateri podatki se nahajajo, ter vse zahteve usmeri na pravi shard.

Še ena pomembna točka: MongoDB je en sam master. Obstaja en primarni - lahko zajema zapise, ki podpirajo ključe, ki jih vsebuje. Ne morete izvajati večglavnega pisanja.

Naredili smo izdajo 4.2 - tam so se pojavile nove zanimive stvari. Predvsem v Mongo so vstavili Lucene - search - namreč izvršljivo javo neposredno in tam je bilo mogoče iskati prek Lucene, enako kot v Elastici.

Pa so naredili nov produkt - Charts, na voljo je tudi na Atlasu (Mongov lastni oblak). Imajo brezplačno stopnjo - lahko se igrate z njo. Grafikoni so mi bili zelo všeč - vizualizacija podatkov, zelo intuitivna.

Sestavine Vzročna doslednost

Preštel sem približno 230 člankov, ki so bili objavljeni na to temo - od Leslie Lampert. Zdaj vam bom po spominu posredoval nekaj delov teh materialov.

HighLoad++, Mikhail Tyulenev (MongoDB): Vzročna doslednost: od teorije do prakse

Vse se je začelo s člankom Leslie Lampert, ki je nastal v sedemdesetih letih prejšnjega stoletja. Kot lahko vidite, nekatere raziskave na to temo še vedno potekajo. Zdaj vzročna konsistentnost doživlja zanimanje v povezavi z razvojem porazdeljenih sistemov.

Omejitve

Kakšne omejitve obstajajo? To je pravzaprav ena od glavnih točk, saj se omejitve, ki jih nalaga produkcijski sistem, zelo razlikujejo od omejitev, ki obstajajo v akademskih člankih. Pogosto so precej umetne.

HighLoad++, Mikhail Tyulenev (MongoDB): Vzročna doslednost: od teorije do prakse

  • Prvič, »MongoDB« je en sam master, kot sem že rekel (to močno poenostavlja).
  • Menimo, da naj bi sistem podpiral okoli 10 tisoč shardov. Ne moremo sprejemati nobenih arhitekturnih odločitev, ki bi izrecno omejile to vrednost.
  • Oblak imamo, a predvidevamo, da bi moral imeti človek še vedno možnost, ko si naloži binarno datoteko, jo požene na prenosniku in vse deluje super.
  • Predvidevamo nekaj, kar raziskave redko domnevajo: zunanje stranke lahko počnejo, kar hočejo. MongoDB je odprtokoden. V skladu s tem so stranke lahko tako pametne in jezne - lahko želijo vse pokvariti. Špekuliramo, da morda izvirajo iz bizantinskih feilorjev.
  • Za zunanje odjemalce, ki so zunaj obsega, obstaja pomembna omejitev: če je ta funkcija onemogočena, ne sme biti opaziti poslabšanja zmogljivosti.
  • Druga točka je na splošno antiakademska: združljivost prejšnjih različic in prihodnjih. Stari gonilniki morajo podpirati nove posodobitve, zbirka podatkov pa mora podpirati stare gonilnike.

Na splošno vse to nalaga omejitve.

Komponente vzročne doslednosti

Zdaj bom govoril o nekaterih komponentah. Če upoštevamo vzročno doslednost na splošno, lahko izberemo bloke. Izbirali smo med deli, ki spadajo v določen blok: Sledenje odvisnosti, izbira ur, kako se te ure lahko sinhronizirajo med seboj in kako zagotavljamo varnost - to je grobi oris tega, o čemer bom govoril:

HighLoad++, Mikhail Tyulenev (MongoDB): Vzročna doslednost: od teorije do prakse

Popolno sledenje odvisnosti

Zakaj je to potrebno? Tako, da pri podvajanju podatkov vsak zapis, vsaka sprememba podatkov vsebuje informacije o tem, od katerih sprememb je odvisna. Prva in naivna sprememba je, ko vsako sporočilo, ki vsebuje zapis, vsebuje podatke o prejšnjih sporočilih:

HighLoad++, Mikhail Tyulenev (MongoDB): Vzročna doslednost: od teorije do prakse

V tem primeru so številke v zavitih oklepajih zapisane številke. Včasih se ti zapisi z vrednostmi prenesejo celo v celoti, včasih se prenesejo nekatere različice. Bistvo je, da vsaka sprememba vsebuje informacije o prejšnji (očitno nosi vse to v sebi).

Zakaj smo se odločili, da ne bomo uporabili tega pristopa (polno sledenje)? Očitno zato, ker je ta pristop nepraktičen: vsaka sprememba družbenega omrežja je odvisna od vseh predhodnih sprememb tega družbenega omrežja, prenosa, recimo, Facebooka ali VKontakte pri vsaki posodobitvi. Kljub temu obstaja veliko raziskav o sledenju popolne odvisnosti – to so predsocialna omrežja; v nekaterih situacijah resnično deluje.

Eksplicitno sledenje odvisnosti

Naslednji je bolj omejen. Tu se upošteva tudi prenos informacij, a le tisti, ki je očitno odvisen. Kaj je odvisno od tega, kaj praviloma določa aplikacija. Ko se podatki podvojijo, poizvedba vrne odgovore le, ko so bile prejšnje odvisnosti izpolnjene, to je prikazane. To je bistvo delovanja vzročne doslednosti.

HighLoad++, Mikhail Tyulenev (MongoDB): Vzročna doslednost: od teorije do prakse

Vidi, da je zapis 5 odvisen od zapisov 1, 2, 3, 4 - v skladu s tem počaka, preden ima odjemalec dostop do sprememb, ki jih je naredila odločitev o dostopu Penny, ko so vse prejšnje spremembe že prešle skozi bazo podatkov.

Tudi to nam ne ustreza, ker je še vedno preveč informacij in bo to upočasnilo stvari. Obstaja še en pristop ...

Lamportova ura

So zelo stari. Lamportova ura pomeni, da so te odvisnosti zložene v skalarno funkcijo, ki se imenuje Lamportova ura.

Skalarna funkcija je neko abstraktno število. Pogosto se imenuje logični čas. Z vsakim dogodkom se ta števec poveča. Števec, ki je trenutno znan procesu, pošlje vsako sporočilo. Jasno je, da so procesi lahko nesinhronizirani, lahko imajo popolnoma različne čase. Kljub temu sistem s takim sporočanjem nekako uravnava uro. Kaj se zgodi v tem primeru?

Ta veliki drobec sem razdelil na dvoje, da bi bilo jasno: Prijatelji lahko živijo v enem vozlišču, ki vsebuje del zbirke, Feed pa lahko živi v drugem vozlišču, ki vsebuje del te zbirke. Je jasno, kako se lahko izognejo? Prvi vir bo rekel: "Podvojeno", nato pa Prijatelji. Če sistem ne zagotavlja neke vrste jamstva, da vir ne bo prikazan, dokler ne bodo dostavljene tudi odvisnosti prijateljev v zbirki prijateljev, bomo imeli natanko to situacijo, kot sem jo omenil.

Vidite, kako se čas števca na viru logično poveča:

HighLoad++, Mikhail Tyulenev (MongoDB): Vzročna doslednost: od teorije do prakse

Torej je glavna lastnost te Lamportove ure in vzročne konsistentnosti (razložena z Lamportovo uro) naslednja: če imamo dogodka A in B in je dogodek B odvisen od dogodka A*, potem sledi, da je logični čas dogodka A manjši od Logični čas od dogodka B.

* Včasih pravijo tudi, da se je A zgodil pred B, torej A se je zgodil pred B - to je določena relacija, ki delno ureja celoten niz dogodkov, ki so se zgodili na splošno.

Nasprotno je napačno. Pravzaprav je to ena glavnih pomanjkljivosti Lamportove ure – delni red. Obstaja koncept simultanih dogodkov, torej dogodkov, pri katerih se niti (A ni zgodilo pred B) niti (A se ni zgodilo pred B). Primer bi bil Leonardovo vzporedno dodajanje nekoga drugega kot prijatelja (niti ne Leonarda, ampak Sheldona, na primer).
To je lastnost, ki se pogosto uporablja pri delu z Lamportovimi urami: pogledajo posebej na funkcijo in iz tega sklepajo, da so morda ti dogodki odvisni. Ker en način velja: če je LogicalTime A manjši od LogicalTime B, potem se B ne more zgoditi pred A; in če več, potem morda.

Vektorska ura

Logičen razvoj Lamportove ure je Vector Clock. Razlikujejo se po tem, da vsako vozlišče, ki je tukaj, vsebuje svojo ločeno uro in se prenašajo kot vektor.
V tem primeru vidite, da je ničelni indeks vektorja odgovoren za vir, prvi indeks vektorja pa za prijatelje (vsako od teh vozlišč). In zdaj se bodo povečali: ničelni indeks "Feed" se poveča pri pisanju - 1, 2, 3:

HighLoad++, Mikhail Tyulenev (MongoDB): Vzročna doslednost: od teorije do prakse

Zakaj je Vector Clock boljši? Ker vam omogočajo, da ugotovite, kateri dogodki so sočasni in kdaj se zgodijo na različnih vozliščih. To je zelo pomembno za sistem razdeljevanja, kot je MongoDB. Tega pa se nismo odločili, čeprav je krasna zadeva, deluje odlično in bi nam verjetno prav prišlo...

Če imamo 10 tisoč drobcev, ne moremo prenesti 10 tisoč komponent, tudi če jih stisnemo ali si izmislimo kaj drugega - koristna obremenitev bo še vedno nekajkrat manjša od prostornine tega celotnega vektorja. Zato smo stiskajoč srce in zobe ta pristop opustili in prešli na drugega.

Spanner TrueTime. Atomska ura

Rekel sem, da bo zgodba o Spannerju. To je kul stvar, naravnost iz XNUMX. stoletja: atomske ure, GPS sinhronizacija.

Kakšna je ideja? “Spanner” je Googlov sistem, ki je pred kratkim postal dostopen celo ljudem (dodali so mu SQL). Vsaka transakcija ima določen časovni žig. Ker je čas sinhroniziran*, je mogoče vsakemu dogodku dodeliti določen čas - atomske ure imajo čakalni čas, po katerem se garantirano "zgodi" drug čas.

HighLoad++, Mikhail Tyulenev (MongoDB): Vzročna doslednost: od teorije do prakse

Tako je z enostavnim pisanjem v bazo podatkov in čakanjem nekaj časa samodejno zagotovljena serializabilnost dogodka. Imajo najmočnejši model doslednosti, ki si ga načeloma lahko zamislimo – to je zunanja doslednost.

* To je glavna težava Lampartovih ur - nikoli niso sinhrone v porazdeljenih sistemih. Lahko se razlikujejo; tudi z NTP še vedno ne delujejo dobro. "Spanner" ima atomsko uro in zdi se, da je sinhronizacija mikrosekund.

Zakaj nismo izbrali? Ne predvidevamo, da imajo naši uporabniki vgrajeno atomsko uro. Ko se bodo pojavile, saj bodo vgrajene v vsak prenosnik, bo tam nekakšna super kul GPS sinhronizacija - potem ja ... Ampak za zdaj je najboljše, kar je mogoče, Amazon, Base Stations - za fanatike ... Zato smo uporabili druge ure .

Hibridna ura

To je pravzaprav tisto, kar v MongoDB deluje pri zagotavljanju vzročne doslednosti. Kako so hibridni? Hibrid je skalarna vrednost, vendar ima dve komponenti:

HighLoad++, Mikhail Tyulenev (MongoDB): Vzročna doslednost: od teorije do prakse

  • Prva je doba Unixa (koliko sekund je minilo od »začetka računalniškega sveta«).
  • Drugi je nekaj prirastka, prav tako 32-bitni nepredznačeni int.

To je pravzaprav vse. Obstaja ta pristop: del, ki je odgovoren za čas, je ves čas sinhroniziran z uro; vsakič, ko pride do posodobitve, se ta del sinhronizira z uro in izkaže se, da je čas vedno bolj ali manj pravilen, inkrement pa omogoča razlikovanje med dogodki, ki so se zgodili v istem trenutku.

Zakaj je to pomembno za MongoDB? Ker vam omogoča, da naredite neke vrste rezervne restavracije v določenem trenutku, to je, da je dogodek indeksiran s časom. To je pomembno, ko so potrebni določeni dogodki; Za bazo podatkov so dogodki spremembe v bazi podatkov, ki so se zgodile v določenih časovnih intervalih.

Najpomembnejši razlog vam bom povedal samo vam (prosim, ne povejte nikomur)! To smo storili, ker tako izgledajo organizirani, indeksirani podatki v MongoDB OpLog. OpLog je podatkovna struktura, ki vsebuje absolutno vse spremembe v bazi: najprej gredo v OpLog, nato pa se uporabijo v samem Storageu v primeru, ko gre za repliciran datum ali šard.

To je bil glavni razlog. Kljub temu obstajajo tudi praktične zahteve za razvoj baze podatkov, kar pomeni, da mora biti preprosta - malo kode, čim manj pokvarjenih stvari, ki jih je treba prepisati in testirati. Dejstvo, da so bili naši oplogi indeksirani s hibridnimi urami, je veliko pomagalo in nam omogočilo, da smo naredili pravo izbiro. Res se je izplačalo in nekako čarobno je delovalo že na prvem prototipu. Bilo je zelo kul!

Sinhronizacija ure

V znanstveni literaturi je opisanih več metod sinhronizacije. Govorim o sinhronizaciji, ko imamo dva različna sharda. Če obstaja en niz replik, ni potrebe po kakršni koli sinhronizaciji: to je "enotni glavni"; imamo OpLog, v katerega spadajo vse spremembe - v tem primeru je vse zaporedno urejeno že v samem "Oplogu". Če pa imamo dva različna sharda, je tu pomembna časovna sinhronizacija. Tukaj je vektorska ura bolj pomagala! Ampak jih nimamo.

HighLoad++, Mikhail Tyulenev (MongoDB): Vzročna doslednost: od teorije do prakse

Drugi je primeren - to je "Srčni utripi". Možna je izmenjava nekaterih signalov, ki se pojavijo vsako časovno enoto. Vendar so srčni utripi prepočasni, naši stranki ne moremo zagotoviti zakasnitve.

Resnični čas je seveda čudovita stvar. Ampak, spet, to je verjetno prihodnost ... Čeprav se to že da narediti v Atlasu, že obstajajo hitri "Amazonovi" časovni sinhronizatorji. Vendar ne bo na voljo vsem.

Ogovarjanje je, ko vsa sporočila vključujejo čas. To je približno tisto, kar uporabljamo. Vsako sporočilo med vozlišči, gonilnik, usmerjevalnik podatkovnega vozlišča, absolutno vse za MongoDB je neke vrste element, komponenta baze podatkov, ki vsebuje uro, ki teče. Povsod imajo pomen hibridnega časa, se prenaša. 64 bitov? To omogoča, to je mogoče.

Kako vse skupaj deluje?

Tukaj gledam en komplet replik, da bo malo lažje. Obstajata primarni in sekundarni. Sekundarni izvaja podvajanje in ni vedno popolnoma sinhroniziran s primarnim.

V »Primery« pride do vstavitve z določeno časovno vrednostjo. Ta vložek poveča notranje število za 11, če je to največje število. Ali pa bo preveril vrednosti ure in se sinhroniziral z uro, če so vrednosti ure višje. To vam omogoča časovno organizacijo.

Ko posname, nastopi pomemben trenutek. Ura je v "MongoDB" in se poveča samo v primeru pisanja v "Oplog". To je dogodek, ki spremeni stanje sistema. V absolutno vseh klasičnih člankih se za dogodek šteje, ko sporočilo zadene vozlišče: sporočilo je prispelo, kar pomeni, da je sistem spremenil stanje.

To je posledica dejstva, da med raziskavo ni povsem jasno, kako bo to sporočilo interpretirano. Zagotovo vemo, da če se ne odraža v »Oplogu«, potem ne bo razloženo na noben način, sprememba stanja sistema pa je le vnos v »Oplog«. To nam vse poenostavi: model poenostavi in ​​nam omogoča, da ga organiziramo znotraj enega kompleta replik in še marsikaj uporabnega.

Vrne se vrednost, ki je že zapisana v »Oplog« - vemo, da »Oplog« že vsebuje to vrednost in je njegov čas 12. Zdaj, recimo, se branje začne iz drugega vozlišča (Sekundarnega) in posreduje afterClusterTime v sporočilo. Pravi: »Potrebujem vse, kar se je zgodilo vsaj po 12 ali med dvanajsto« (glej sliko zgoraj).

To je tisto, kar se imenuje vzročno dosledno (CAT). V teoriji obstaja koncept, da je to nek odsek časa, ki je sam po sebi skladen. V tem primeru lahko rečemo, da je to stanje sistema, ki smo ga opazili v času 12.

Zdaj tukaj še ni ničesar, ker to nekako simulira situacijo, ko potrebujete sekundarno za repliciranje podatkov iz primarne. Čaka ... In zdaj so podatki prispeli - te vrednosti vrne nazaj.

HighLoad++, Mikhail Tyulenev (MongoDB): Vzročna doslednost: od teorije do prakse

Približno tako vse deluje. Skoraj.

Kaj pomeni "skoraj"? Recimo, da obstaja nekdo, ki je prebral in razumel, kako vse to deluje. Ugotovil sem, da vsakič, ko se pojavi ClusterTime, posodobi notranjo logično uro, nato pa se naslednji vnos poveča za eno. Ta funkcija zavzame 20 vrstic. Recimo, da ta oseba odda največje 64-bitno število, minus ena.

Zakaj "minus ena"? Ker bo notranja ura zamenjana s to vrednostjo (očitno je to največja možna in večja od trenutnega časa), se bo zgodil vnos v »Oplog« in ura se bo povečala za drugo enoto - in že bo biti največja vrednost (preprosto so vse enote, ni kam drugam) , unsaint ints).

Jasno je, da po tem sistem postane popolnoma nedostopen za karkoli. Lahko se samo raztovori in očisti - veliko ročnega dela. Popolna razpoložljivost:

HighLoad++, Mikhail Tyulenev (MongoDB): Vzročna doslednost: od teorije do prakse

Poleg tega, če se to ponovi nekje drugje, potem celoten grozd preprosto pade. Absolutno nesprejemljiva situacija, ki si jo lahko zelo hitro in enostavno organizira vsak! Zato smo ta trenutek ocenili kot enega najpomembnejših. Kako to preprečiti?

Naš način je, da podpišemo clusterTime

Tako je posredovano v sporočilu (pred modrim besedilom). Začeli pa smo ustvarjati tudi podpis (modro besedilo):

HighLoad++, Mikhail Tyulenev (MongoDB): Vzročna doslednost: od teorije do prakse

Podpis se ustvari s ključem, ki je shranjen v bazi podatkov, znotraj varnega perimetra; se ustvari in posodobi (uporabniki ne vidijo ničesar o tem). Ustvari se zgoščena vrednost in vsako sporočilo je podpisano, ko je ustvarjeno, in potrjeno, ko je prejeto.
Verjetno se v glavah ljudi poraja vprašanje: "Koliko to upočasni stvari?" Rekel sem vam, da bi moralo delovati hitro, še posebej, če te funkcije ni.

Kaj v tem primeru pomeni uporaba vzročne doslednosti? To je za prikaz parametra afterClusterTime. Brez tega bo tako ali tako preprosto posredoval vrednosti. Ogovarjanje, od različice 3.6, vedno deluje.

Če pustimo stalno generiranje podpisov, bo to upočasnilo sistem tudi v odsotnosti funkcije, ki ne ustreza našim pristopom in zahtevam. Torej, kaj smo storili?

Naredi to hitro!

To je dokaj preprosta stvar, vendar je trik zanimiv - bom delil, morda bo koga zanimalo.
Imamo zgoščeno vrednost, ki hrani podpisane podatke. Vsi podatki gredo skozi predpomnilnik. Predpomnilnik ne podpisuje določenega časa, ampak obseg. Ko prispe neka vrednost, ustvarimo obseg, zamaskiramo zadnjih 16 bitov in podpišemo to vrednost:

HighLoad++, Mikhail Tyulenev (MongoDB): Vzročna doslednost: od teorije do prakse

S prejemom takšnega podpisa sistem pohitrimo (relativno) 65 tisočkrat. Deluje odlično: ko smo izvajali poskuse, se je čas dejansko zmanjšal za 10 tisočkrat, ko smo imeli zaporedno posodobitev. Jasno je, da ko sta sprta, to ne gre. Toda v večini praktičnih primerov deluje. Kombinacija podpisa Range skupaj s podpisom je rešila varnostni problem.

Kaj smo se naučili?

Lekcije, ki smo se jih naučili iz tega:

  • Prebrati moramo gradiva, zgodbe, članke, saj imamo veliko zanimivih stvari. Ko delamo na neki funkciji (zlasti zdaj, ko smo opravili transakcije itd.), moramo brati in razumeti. Potrebuje čas, a je pravzaprav zelo koristno, saj jasno pove, kje smo. Zdi se, da nismo prišli do ničesar novega - vzeli smo le sestavine.

    Nasploh je določena razlika v razmišljanju, ko je akademska konferenca (Sigmon, na primer) – vsi se osredotočajo na nove ideje. Kaj je novega pri našem algoritmu? Tu ni nič posebej novega. Novost je bolj v tem, kako smo združili obstoječe pristope. Zato je prva stvar branje klasike, začenši z Lampartom.

  • V proizvodnji so zahteve popolnoma drugačne. Prepričan sem, da se mnogi od vas ne soočate s "sferičnimi" bazami podatkov v abstraktnem vakuumu, temveč z običajnimi, resničnimi stvarmi, ki imajo težave z razpoložljivostjo, zakasnitvijo in toleranco na napake.
  • Zadnja stvar je, da smo morali pogledati različne ideje in združiti več popolnoma različnih člankov v en pristop, skupaj. Ideja o podpisovanju, na primer, je na splošno izhajala iz članka, ki je upošteval protokol Paxos, ki je za nebizantinske Failors znotraj avtorizacijskega protokola, za bizantinske - zunaj avtorizacijskega protokola ... Na splošno je to točno tisto, kar smo končal s tem.

    Tukaj ni čisto nič novega! A ko smo vse skupaj zmešali ... To je enako, kot če bi rekli, da je recept za solato Olivier nesmisel, saj so jajca, majonezo in kumare že izumili ... Približno ista zgodba.

HighLoad++, Mikhail Tyulenev (MongoDB): Vzročna doslednost: od teorije do prakse

Končal bom s tem. Hvala vam!

vprašanja

Vprašanje iz občinstva (v nadaljevanju B): – Hvala, Mikhail, za poročilo! Zanimiva je tema o času. Uporabljate Ogovarjanje. Rekli so, da ima vsak svoj čas, vsak pozna svoj lokalni čas. Kolikor razumem, imamo gonilnik - odjemalcev z gonilniki je lahko veliko, tudi načrtovalci poizvedb, tudi drobci ... In na kaj se sistem spusti, če nenadoma pride do neskladja: nekdo se odloči, da je za minuto naprej, nekdo minuto zadaj? Kje bomo končali?

MT: – Res super vprašanje! Želel sem samo govoriti o drobcih. Če prav razumem vprašanje, imamo naslednjo situacijo: obstajata shard 1 in shard 2, branje poteka iz teh dveh shardov - imata neskladje, ne delujeta drug z drugim, ker je čas, ki ga poznata, drugačen, predvsem čas, ko obstajajo v oplogih.
Recimo, da je shard 1 naredil milijon zapisov, shard 2 ni naredil ničesar, zahteva pa je prišla na dva sharda. In prvi ima afterClusterTime več kot milijon. V takšni situaciji, kot sem pojasnil, se shard 2 sploh ne bo nikoli odzval.

V: – Zanima me, kako se sinhronizirajo in izberejo en logični čas?

MT: - Zelo enostavno za sinhronizacijo. Shard, ko pride do njega afterClusterTime in ne najde časa v »Oplogu«, sproži neodobreno. To pomeni, da dvigne svoj čas z rokami na to vrednost. To pomeni, da nima dogodkov, ki bi ustrezali tej zahtevi. Ta dogodek ustvari umetno in tako postane vzročno dosleden.

V: – Kaj pa, če mu po tem pridejo drugi dogodki, ki so bili izgubljeni nekje v omrežju?

MT: – Shard je zasnovan tako, da ne bodo več prišli, saj gre za enega samega mojstra. Če se je že prijavil, potem ne bodo prišli, ampak bodo prišli kasneje. Ne more se zgoditi, da se nekje nekaj zatakne, potem ne piše, potem pa pridejo ti dogodki - in Vzročna konsistenca je porušena. Ko ne piše, naj pridejo vsi naslednji (počakal jih bo).

HighLoad++, Mikhail Tyulenev (MongoDB): Vzročna doslednost: od teorije do prakse

V: – Imam več vprašanj glede čakalnih vrst. Vzročna doslednost predpostavlja, da obstaja določena vrsta dejanj, ki jih je treba izvesti. Kaj se zgodi, če eden od naših paketov izgine? Prihaja 10., 11. ... 12. je izginil, vsi ostali pa čakajo, da se uresniči. In nenadoma nam je umrl avto, ne moremo storiti ničesar. Ali obstaja največja dolžina čakalne vrste, ki se nabere pred izvedbo? Kakšna usodna napaka se zgodi, ko se izgubi katero koli stanje? Še več, če zapišemo, da obstaja neko prejšnje stanje, potem bi morali nekako izhajati iz tega? Vendar ga niso odrinili!

MT: – Tudi odlično vprašanje! Kaj počnemo? MongoDB ima koncept kvoruma piše, kvorum bere. V katerih primerih se lahko sporočilo izgubi? Ko pisanje ni sklepčno ali ko branje ni sklepčno (prilepi se lahko tudi kakšna smeti).
V zvezi z vzročno konsistentnostjo je bil izveden velik eksperimentalni test, katerega rezultat je bil, da v primeru, ko sta pisanja in branja nesklepčna, prihaja do kršitev vzročne konsistentnosti. Točno to, kar pravite!

Naš nasvet: pri uporabi vzročne doslednosti uporabite vsaj branje sklepčnosti. V tem primeru se nič ne izgubi, tudi če se izgubi zapis kvoruma ... To je ortogonalna situacija: če uporabnik ne želi izgube podatkov, mora uporabiti zapis kvoruma. Vzročna doslednost ne zagotavlja trajnosti. Trajnost je zagotovljena z replikacijo in stroji, povezanimi z replikacijo.

V: – Ko ustvarimo instanco, ki za nas izvaja razrez (ne master, ampak slave), se zanaša na čas Unix svojega lastnega stroja ali na čas "master"; Ali se sinhronizira prvič ali občasno?

MT: – zdaj bom razjasnil. Shard (tj. horizontalna particija) – tam je vedno primarni. In delček ima lahko "glavnega" in lahko obstajajo replike. Ampak shard vedno podpira snemanje, ker mora podpirati neko domeno (shard ima Primary).

V: – Torej je vse odvisno čisto od »gospodarja«? Ali je glavni čas vedno uporabljen?

MT: - Da. Lahko figurativno rečemo: ura tiktaka, ko pride do vstopa v »mojstra«, v »Oplog«.

V: – Imamo stranko, ki se povezuje in ji ni treba vedeti ničesar o času?

MT: – Sploh vam ni treba vedeti ničesar! Če govorimo o tem, kako deluje na odjemalcu: ko želi odjemalec uporabiti vzročno doslednost, mora odpreti sejo. Zdaj je vse na voljo: transakcije v seji in pridobivanje pravic ... Seja je vrstni red logičnih dogodkov, ki se zgodijo s stranko.

Če odpre to sejo in tam reče, da želi vzročno doslednost (če seja privzeto podpira vzročno doslednost), vse deluje samodejno. Voznik si ta čas zapomni in ga poveča, ko prejme novo sporočilo. Zapomni si, kakšen odgovor je prejšnji vrnil s strežnika, ki je vrnil podatke. Naslednja zahteva bo vsebovala afterCluster("čas, večji od tega").

Stranki ni treba vedeti popolnoma ničesar! To je zanj popolnoma nepregledno. Če ljudje uporabljajo te funkcije, kaj lahko storijo? Prvič, lahko varno berete sekundarje: lahko pišete v primarni in berete iz geografsko podvojenih sekundarjev in ste prepričani, da deluje. Hkrati je mogoče seje, ki so bile posnete na primarni, celo prenesti na sekundarno, tj. ne uporabite ene seje, ampak več.

V: – Nova plast računalništva – tipi podatkov CRDT (replicirani podatkovni tipi brez konfliktov) – je močno povezan s temo morebitne konsistentnosti. Ali ste razmišljali o vključitvi tovrstnih podatkov v bazo podatkov in kaj lahko rečete o tem?

MT: - Dobro vprašanje! CRDT je ​​smiseln za konflikte pisanja: v MongoDB, en sam glavni.

V: – Imam vprašanje od devopsa. V resničnem svetu obstajajo takšne jezuitske situacije, ko pride do bizantinskega neuspeha in zlobni ljudje znotraj zaščitenega perimetra začnejo vtikati v protokol, pošiljajo obrtne pakete na poseben način?

HighLoad++, Mikhail Tyulenev (MongoDB): Vzročna doslednost: od teorije do prakse

MT: – Zlobni ljudje znotraj perimetra so kot trojanski konj! Zlobni ljudje znotraj perimetra lahko naredijo veliko slabega.

V: – Jasno je, da pustite, grobo rečeno, luknjo v strežniku, skozi katero lahko spravite živalski vrt slonov in za vedno zrušite celotno gručo ... Potreben bo čas za ročno obnovitev ... To je, milo rečeno, narobe. Po drugi strani pa je to zanimivo: v resničnem življenju, v praksi, obstajajo situacije, ko pride do naravno podobnih notranjih napadov?

MT: – Ker v resničnem življenju redko naletim na kršitve varnosti, ne morem reči, ali se zgodijo. Če pa govorimo o razvojni filozofiji, razmišljamo takole: imamo obod, ki zagotavlja fantom, ki delajo varnost – to je grad, zid; in znotraj perimetra lahko počneš kar hočeš. Jasno je, da obstajajo uporabniki z možnostjo samo ogledovanja in uporabniki z možnostjo brisanja imenika.

Odvisno od pravic je lahko škoda, ki jo uporabniki naredijo, miška, lahko pa tudi slon. Jasno je, da lahko uporabnik s polnimi pravicami počne sploh karkoli. Uporabnik z omejenimi pravicami lahko povzroči bistveno manj škode. Zlasti ne more zlomiti sistema.

V: – V varovanem perimetru je nekdo poskušal ustvariti nepričakovane protokole za strežnik, da bi popolnoma uničil strežnik, in če imate srečo, celotno gručo ... Ali pride kdaj tako »dobro«?

MT: "Še nikoli nisem slišal za take stvari." Dejstvo, da lahko na ta način zrušite strežnik, ni skrivnost. Fail notri, ker si iz protokola, ker si pooblaščen uporabnik, ki lahko kaj takega napiše v sporočilo ... Pravzaprav je to nemogoče, ker bo še preverjeno. Uporabnikom, ki tega ne želijo, je možno onemogočiti to avtentikacijo – potem je to njihov problem; oni so, grobo rečeno, sami uničili zidove in tja lahko potisnete slona, ​​ki bo poteptal ... Na splošno pa se lahko oblečete v serviserja, pridite in ga izvlecite!

V: – Hvala za poročilo. Sergej (Yandex). V Mongu obstaja konstanta, ki omejuje število glasovalnih članov v naboru replik, in ta konstanta je 7 (sedem). Zakaj je to stalnica? Zakaj to ni nekakšen parameter?

MT: – Imamo komplete replik s 40 vozlišči. Vedno je večina. Ne vem katera verzija...

V: – V naboru replik lahko izvajate člane brez glasovalne pravice, vendar je članov z glasovalno pravico največ 7. Kako lahko v tem primeru preživimo zaustavitev, če je naš nabor replik razpršen v 3 podatkovnih centrih? En podatkovni center se lahko enostavno izklopi, drug stroj pa lahko izpade.

MT: – To že malo presega obseg poročila. To je splošno vprašanje. Mogoče ti lahko o tem povem kasneje.

HighLoad++, Mikhail Tyulenev (MongoDB): Vzročna doslednost: od teorije do prakse

Nekaj ​​oglasov 🙂

Hvala, ker ste ostali z nami. So vam všeč naši članki? Želite videti več zanimivih vsebin? Podprite nas tako, da oddate naročilo ali priporočite prijateljem, oblak VPS za razvijalce od 4.99 $, edinstven analog začetnih strežnikov, ki smo ga izumili za vas: Vsa resnica o VPS (KVM) E5-2697 v3 (6 jeder) 10 GB DDR4 480 GB SSD 1 Gbps od 19 USD ali kako deliti strežnik? (na voljo z RAID1 in RAID10, do 24 jeder in do 40 GB DDR4).

Dell R730xd dvakrat cenejši v podatkovnem centru Equinix Tier IV v Amsterdamu? Samo tukaj 2 x Intel TetraDeca-Core Xeon 2x E5-2697v3 2.6 GHz 14C 64 GB DDR4 4 x 960 GB SSD 1 Gbps 100 TV od 199 $ na Nizozemskem! Dell R420 - 2x E5-2430 2.2 Ghz 6C 128 GB DDR3 2x960 GB SSD 1 Gbps 100 TB - od 99 $! Preberite o Kako zgraditi infrastrukturo Corp. razreda z uporabo strežnikov Dell R730xd E5-2650 v4 v vrednosti 9000 evrov za drobiž?

Vir: www.habr.com

Dodaj komentar