HighLoad++, Mikhail Tyulenev (MongoDB): Årsakskonsistens: fra teori til praksis

Den neste HighLoad++-konferansen holdes 6. og 7. april 2020 i St. Petersburg.
Detaljer og billetter по ссылке. HighLoad++ Sibir 2019. Hall "Krasnoyarsk". 25. juni, 12:00. Avhandlinger og presentasjon.

HighLoad++, Mikhail Tyulenev (MongoDB): Årsakskonsistens: fra teori til praksis

Det hender at praktiske krav kommer i konflikt med teori, der aspekter som er viktige for et kommersielt produkt ikke tas i betraktning. Denne foredraget presenterer en prosess for å velge ut og kombinere ulike tilnærminger for å skape årsakssammenhengende komponenter basert på akademisk forskning basert på kravene til et kommersielt produkt. Lyttere vil lære om eksisterende teoretiske tilnærminger til logiske klokker, avhengighetssporing, systemsikkerhet, klokkesynkronisering, og hvorfor MongoDB slo seg på bestemte løsninger.

Mikhail Tyulenev (heretter referert til som MT): – Jeg skal snakke om årsakssammenheng – dette er en funksjon vi har jobbet med i MongoDB. Jeg jobber i en gruppe med distribuerte systemer, vi gjorde det for omtrent to år siden.

HighLoad++, Mikhail Tyulenev (MongoDB): Årsakskonsistens: fra teori til praksis

I prosessen måtte jeg sette meg inn i mye akademisk forskning, fordi denne funksjonen har blitt studert ganske godt. Det viste seg at ikke en eneste artikkel passer inn i det som kreves i en produksjonsdatabase på grunn av helt spesifikke krav som sannsynligvis er tilstede i enhver produksjonsapplikasjon.

Jeg skal snakke om hvordan vi, som forbrukere av akademisk forskning, tilbereder noe av den som vi så kan presentere for brukerne våre som en ferdigrett som er praktisk og trygg å bruke.

Årsaksmessig konsistens. La oss definere begrepene

Til å begynne med vil jeg si generelt hva kausal konsistens er. Det er to karakterer - Leonard og Penny (TV-serien "The Big Bang Theory"):

HighLoad++, Mikhail Tyulenev (MongoDB): Årsakskonsistens: fra teori til praksis

La oss si at Penny er i Europa og Leonard vil arrangere en overraskelsesfest til henne. Og han kan ikke tenke seg noe bedre enn å kaste henne av vennelisten sin og sende alle vennene sine en oppdatering på feeden: «La oss gjøre Penny glad!» (hun er i Europa, mens hun sover, hun ser ikke alt dette og kan ikke se det, fordi hun ikke er der). Til syvende og sist sletter hun dette innlegget, sletter det fra feeden og gjenoppretter tilgangen slik at hun ikke merker noe og det er ingen skandale.
Dette er vel og bra, men la oss anta at systemet er distribuert og at det gikk litt galt. Det kan for eksempel skje at Pennys tilgangsbegrensning skjedde etter at dette innlegget dukket opp, hvis hendelsene ikke er relatert til årsak og virkning. Egentlig er dette et eksempel på når årsakssammenheng er nødvendig for å utføre en forretningsfunksjon (i dette tilfellet).

Faktisk er dette ganske ikke-trivielle egenskaper ved databasen - svært få mennesker støtter dem. La oss gå videre til modellene.

Konsistensmodeller

Hva er egentlig en konsistensmodell i databaser? Dette er noen av garantiene som et distribuert system gir om hvilke data klienten kan motta og i hvilken rekkefølge.

I prinsippet kommer alle konsistensmodeller ned på hvor likt et distribuert system er et system som kjører for eksempel på én node på en bærbar datamaskin. Og dette er hvor likt et system som kjører på tusenvis av geo-distribuerte "Noder" til en bærbar datamaskin, der alle disse egenskapene i prinsippet utføres automatisk.

Derfor brukes konsistensmodeller kun på distribuerte systemer. Alle systemer som tidligere eksisterte og opererte med samme vertikale skalering opplevde ikke slike problemer. Det var én bufferbuffer, og alt ble alltid lest fra den.

Modell Sterk

Egentlig er den aller første modellen Strong (eller rise ability line, som den ofte kalles). Dette er en konsistensmodell som sikrer at hver endring, når den er bekreftet at den har skjedd, er synlig for alle brukere av systemet.

Dette skaper en global rekkefølge av alle hendelser i databasen. Dette er en veldig sterk konsistensegenskap, og den er generelt veldig dyr. Det er imidlertid veldig godt støttet. Det er bare veldig dyrt og tregt - det er bare sjelden brukt. Dette kalles stigeevne.

Det er en annen, sterkere egenskap som støttes i Spanner - kalt External Consistency. Vi snakker om det litt senere.

årsaks

Den neste er Causal, som er akkurat det jeg snakket om. Det er flere undernivåer mellom Strong og Causal som jeg ikke skal snakke om, men de koker alle ned til Causal. Dette er en viktig modell fordi den er den sterkeste av alle modeller, den sterkeste konsistensen i nærvær av et nettverk eller partisjoner.

Årsakssammenheng er faktisk en situasjon der hendelser er forbundet med et årsak-virkningsforhold. Svært ofte blir de oppfattet som Les dine rettigheter fra kundens synspunkt. Hvis klienten har observert noen verdier, kan han ikke se verdier som var i fortiden. Han begynner allerede å se prefiksavlesninger. Det hele kommer ned til det samme.
Årsakssammenheng som en konsistensmodell er en delvis rekkefølge av hendelser på serveren, der hendelser fra alle klienter blir observert i samme sekvens. I dette tilfellet, Leonard og Penny.

Endelig

Den tredje modellen er Eventuell konsistens. Dette er hva absolutt alle distribuerte systemer støtter, den minimale modellen som i det hele tatt gir mening. Det betyr følgende: når vi har noen endringer i dataene, blir de på et tidspunkt konsistente.

I et slikt øyeblikk sier hun ingenting, ellers ville hun bli til ekstern konsistens - det ville vært en helt annen historie. Likevel er dette en veldig populær modell, den vanligste. Som standard bruker alle brukere av distribuerte systemer Eventuell konsistens.

Jeg vil gi noen komparative eksempler:

HighLoad++, Mikhail Tyulenev (MongoDB): Årsakskonsistens: fra teori til praksis

Hva betyr disse pilene?

  • Ventetid. Etter hvert som konsistensstyrken øker, blir den større av åpenbare grunner: du må lage flere poster, få bekreftelse fra alle verter og noder som deltar i klyngen om at dataene allerede er der. Følgelig har Eventual Consistency det raskeste svaret, fordi der, som regel, kan du til og med forplikte det til minnet, og dette vil i prinsippet være nok.
  • Tilgjengelighet. Hvis vi forstår dette som systemets evne til å reagere i nærvær av nettverksbrudd, partisjoner eller en eller annen form for feil, øker feiltoleransen ettersom konsistensmodellen reduseres, siden det er nok for oss at én vert lever og samtidig tiden produserer noen data. Eventuell konsistens garanterer ikke noe om dataene i det hele tatt - det kan være hva som helst.
  • Anomalier. Samtidig øker selvfølgelig antallet anomalier. I Strong Consistency burde de nesten ikke eksistere i det hele tatt, men i Eventual Consistency kan de være hva som helst. Spørsmålet oppstår: hvorfor velger folk Eventuell konsistens hvis den inneholder anomalier? Svaret er at Eventual Consistency-modeller er anvendelige og uregelmessigheter eksisterer for eksempel i løpet av kort tid; det er mulig å bruke veiviseren til å lese og mer eller mindre lese konsistente data; Det er ofte mulig å bruke sterke konsistensmodeller. I praksis fungerer dette, og ofte er antall anomalier begrenset i tid.

CAP-teorem

Når du ser ordene konsistens, tilgjengelighet – hva tenker du på? Det stemmer - CAP-teorem! Nå vil jeg avlive myten... Det er ikke meg - det er Martin Kleppmann, som skrev en fantastisk artikkel, en fantastisk bok.

HighLoad++, Mikhail Tyulenev (MongoDB): Årsakskonsistens: fra teori til praksis

CAP-teoremet er et prinsipp formulert på 2000-tallet om at konsistens, tilgjengelighet, partisjoner: ta hvilke som helst to, og du kan ikke velge tre. Det var et visst prinsipp. Det ble bevist som et teorem noen år senere av Gilbert og Lynch. Så begynte dette å bli brukt som et mantra - systemer begynte å bli delt inn i CA, CP, AP og så videre.

Dette teoremet ble faktisk bevist for følgende tilfeller... For det første ble tilgjengelighet ikke ansett som en kontinuerlig verdi fra null til hundrevis (0 - systemet er "dødt", 100 - reagerer raskt; vi er vant til å betrakte det slik) , men som en egenskap til algoritmen , som garanterer at den returnerer data for alle utførelsene.

Det står ikke et ord om responstid i det hele tatt! Det finnes en algoritme som returnerer data etter 100 år – en helt fantastisk tilgjengelig algoritme, som er en del av CAP-teoremet.
For det andre: teoremet ble bevist for endringer i verdiene til den samme nøkkelen, til tross for at disse endringene kan endres. Dette betyr at de i realiteten praktisk talt ikke brukes, fordi modellene er forskjellige Eventuell konsistens, sterk konsistens (kanskje).

Hva er alt dette til for? Dessuten er CAP-teoremet i nøyaktig den formen det ble bevist i praktisk talt ikke anvendelig og brukes sjelden. I teoretisk form begrenser det liksom alt. Det viser seg et visst prinsipp som er intuitivt korrekt, men som generelt ikke er bevist.

Årsakskonsistens er den sterkeste modellen

Det som skjer nå er at du kan få alle tre tingene: Konsistens, Tilgjengelighet ved å bruke partisjoner. Spesielt er årsakssammenheng den sterkeste konsistensmodellen, som fortsatt fungerer i nærvær av partisjoner (brudd i nettverket). Derfor er det av så stor interesse, og det er derfor vi tok det opp.

HighLoad++, Mikhail Tyulenev (MongoDB): Årsakskonsistens: fra teori til praksis

For det første forenkler det arbeidet til applikasjonsutviklere. Spesielt tilstedeværelsen av god støtte fra serveren: når alle poster som forekommer inne i en klient er garantert å ankomme i samme sekvens på en annen klient. For det andre tåler den skillevegger.

MongoDB innvendig kjøkken

Husker at det er lunsj, og flytter til kjøkkenet. Jeg skal fortelle deg om systemmodellen, nemlig hva MongoDB er for de som hører om en slik database for første gang.

HighLoad++, Mikhail Tyulenev (MongoDB): Årsakskonsistens: fra teori til praksis

HighLoad++, Mikhail Tyulenev (MongoDB): Årsakskonsistens: fra teori til praksis

MongoDB (heretter referert til som "MongoDB") er et distribuert system som støtter horisontal skalering, det vil si sharding; og innenfor hvert shard støtter den også dataredundans, det vil si replikering.

Sharding i MongoDB (ikke en relasjonsdatabase) utfører automatisk balansering, det vil si at hver samling av dokumenter (eller "tabell" når det gjelder relasjonsdata) er delt inn i biter, og serveren flytter dem automatisk mellom shards.

Query Router, som distribuerer forespørsler, for en klient er en klient som den fungerer gjennom. Den vet allerede hvor og hvilke data som finnes og sender alle forespørsler til riktig shard.

Et annet viktig poeng: MongoDB er en enkelt mester. Det er én Primær - den kan ta poster som støtter nøklene den inneholder. Du kan ikke skrive multi-master.

Vi laget utgivelse 4.2 - nye interessante ting dukket opp der. Spesielt satte de inn Lucene – søk – nemlig kjørbar java direkte i Mongo, og der ble det mulig å utføre søk gjennom Lucene, det samme som i Elastica.

Og de laget et nytt produkt - Charts, det er også tilgjengelig på Atlas (Mongos egen Cloud). De har et gratis nivå - du kan leke med det. Jeg likte diagrammer - datavisualisering, veldig intuitivt.

Ingredienser Årsakssammenheng

Jeg telte rundt 230 artikler som har blitt publisert om dette emnet – fra Leslie Lampert. Nå fra mitt minne vil jeg formidle noen deler av disse materialene til deg.

HighLoad++, Mikhail Tyulenev (MongoDB): Årsakskonsistens: fra teori til praksis

Det hele startet med en artikkel av Leslie Lampert, som ble skrevet på 1970-tallet. Som du kan se, pågår fortsatt noe forskning på dette emnet. Nå opplever Causal konsistens interesse i forbindelse med utvikling av distribuerte systemer.

Restriksjoner

Hvilke begrensninger er det? Dette er faktisk et av hovedpoengene, for restriksjonene som et produksjonssystem pålegger er svært forskjellige fra begrensningene som finnes i akademiske artikler. De er ofte ganske kunstige.

HighLoad++, Mikhail Tyulenev (MongoDB): Årsakskonsistens: fra teori til praksis

  • For det første er "MongoDB" en enkelt mester, som jeg allerede sa (dette forenkler betraktelig).
  • Vi mener at systemet bør støtte rundt 10 tusen shards. Vi kan ikke ta noen arkitektoniske beslutninger som eksplisitt vil begrense denne verdien.
  • Vi har en sky, men vi antar at en person fortsatt skal ha muligheten når han laster ned binær, kjører den på sin bærbare datamaskin, og alt fungerer utmerket.
  • Vi antar noe som Research sjelden antar: eksterne kunder kan gjøre hva de vil. MongoDB er åpen kildekode. Følgelig kan klienter være så smarte og sinte - de kan ønske å bryte alt. Vi spekulerer i at bysantinske feilors kan stamme.
  • For eksterne klienter som er utenfor perimeteren, er det en viktig begrensning: hvis denne funksjonen er deaktivert, bør ingen ytelsesforringelse observeres.
  • Et annet poeng er generelt anti-akademisk: kompatibiliteten til tidligere versjoner og fremtidige. Gamle drivere må støtte nye oppdateringer, og databasen må støtte gamle drivere.

Generelt setter alt dette begrensninger.

Årsaksmessige konsistenskomponenter

Jeg vil nå snakke om noen av komponentene. Hvis vi vurderer årsakssammenheng generelt, kan vi velge blokker. Vi valgte blant verk som tilhører en bestemt blokk: Dependency Tracking, valg av klokker, hvordan disse klokkene kan synkroniseres med hverandre, og hvordan vi sikrer sikkerhet - dette er en grov skisse av hva jeg skal snakke om:

HighLoad++, Mikhail Tyulenev (MongoDB): Årsakskonsistens: fra teori til praksis

Full avhengighetssporing

Hvorfor trengs det? Slik at når data blir replikert, inneholder hver post, hver dataendring informasjon om hvilke endringer den avhenger av. Den aller første og naive endringen er når hver melding som inneholder en post inneholder informasjon om tidligere meldinger:

HighLoad++, Mikhail Tyulenev (MongoDB): Årsakskonsistens: fra teori til praksis

I dette eksemplet er tallet i krøllete parentes rekordtallene. Noen ganger blir disse postene med verdier til og med overført i sin helhet, noen ganger overføres noen versjoner. Poenget er at hver endring inneholder informasjon om den forrige (selvfølgelig bærer alt dette i seg selv).

Hvorfor bestemte vi oss for å ikke bruke denne tilnærmingen (full sporing)? Selvfølgelig, fordi denne tilnærmingen er upraktisk: enhver endring i et sosialt nettverk avhenger av alle tidligere endringer i det sosiale nettverket, overføring av for eksempel Facebook eller VKontakte i hver oppdatering. Likevel er det mye forskning på Full Dependency Tracking – dette er pre-sosiale nettverk; for noen situasjoner fungerer det virkelig.

Eksplisitt avhengighetssporing

Den neste er mer begrenset. Overføring av informasjon vurderes også her, men kun det som er klart avhengig. Hva som avhenger av hva, bestemmes som regel av Søknaden. Når data replikeres, returnerer spørringen kun svar når tidligere avhengigheter er tilfredsstilt, det vil si vist. Dette er essensen av hvordan kausal konsistens fungerer.

HighLoad++, Mikhail Tyulenev (MongoDB): Årsakskonsistens: fra teori til praksis

Hun ser at post 5 avhenger av post 1, 2, 3, 4 - følgelig venter hun før klienten får tilgang til endringene gjort av Pennys tilgangsbeslutning, når alle tidligere endringer allerede har gått gjennom databasen.

Dette passer ikke oss heller, fordi det fortsatt er for mye informasjon, og det vil bremse ting. Det er en annen tilnærming...

Lamport klokke

De er veldig gamle. Lamport Clock betyr at disse avhengighetene er foldet inn i en skalarfunksjon, som kalles Lamport Clock.

En skalarfunksjon er et abstrakt tall. Det kalles ofte logisk tid. For hver hendelse øker denne telleren. Teller, som for øyeblikket er kjent for prosessen, sender hver melding. Det er klart at prosesser kan være ute av synkronisering, de kan ha helt andre tider. Likevel balanserer systemet på en eller annen måte klokken med slike meldinger. Hva skjer i dette tilfellet?

Jeg delte den store skåren i to for å gjøre det klart: Venner kan bo i én node, som inneholder en del av samlingen, og Feed kan bo i en annen node, som inneholder en del av denne samlingen. Er det klart hvordan de kan komme ut av linjen? First Feed vil si: "Replisert", og deretter Friends. Hvis systemet ikke gir noen form for garanti for at feeden ikke vises før venneavhengighetene i vennesamlingen også er levert, vil vi ha akkurat den situasjonen som jeg nevnte.

Du ser hvordan tellertiden på Feed logisk øker:

HighLoad++, Mikhail Tyulenev (MongoDB): Årsakskonsistens: fra teori til praksis

Så hovedegenskapen til denne Lamport-klokken og årsakskonsistensen (forklart gjennom Lamport-klokken) er denne: hvis vi har hendelser A og B, og hendelse B avhenger av hendelse A*, så følger det at den logiske tiden for hendelse A er mindre enn enn LogicalTime fra hendelse B.

* Noen ganger sier de også at A skjedde før B, det vil si at A skjedde før B - dette er en viss relasjon som delvis ordner hele settet med hendelser som skjedde generelt.

Det motsatte er feil. Dette er faktisk en av de største ulempene med Lamport Clock - delvis rekkefølge. Det er et konsept om samtidige hendelser, det vil si hendelser der verken (A skjedde før B) eller (A skjedde før B). Et eksempel kan være Leonards parallelle tillegg av noen andre som venn (ikke engang Leonard, men Sheldon, for eksempel).
Dette er egenskapen som ofte brukes når man jobber med Lamport-klokker: de ser spesifikt på funksjonen og fra dette konkluderer de med at kanskje disse hendelsene er avhengige. Fordi én måte er sann: hvis LogicalTime A er mindre enn LogicalTime B, kan ikke B skje før A; og hvis mer, så kanskje.

Vektor klokke

Den logiske utviklingen av Lamport-klokken er Vector Clock. De er forskjellige ved at hver node som er her inneholder sin egen separate klokke, og de overføres som en vektor.
I dette tilfellet ser du at den nullte indeksen til vektoren er ansvarlig for Feed, og den første indeksen til vektoren er for Friends (hver av disse nodene). Og nå vil de øke: nullindeksen til "Feed" øker når du skriver - 1, 2, 3:

HighLoad++, Mikhail Tyulenev (MongoDB): Årsakskonsistens: fra teori til praksis

Hvorfor er Vector Clock bedre? Fordi de lar deg finne ut hvilke hendelser som er samtidige og når de oppstår på forskjellige noder. Dette er veldig viktig for et sønderdelingssystem som MongoDB. Vi valgte imidlertid ikke dette, selv om det er en fantastisk ting, og det fungerer utmerket, og det ville nok passe oss...

Hvis vi har 10 tusen shards, kan vi ikke overføre 10 tusen komponenter, selv om vi komprimerer det eller kommer på noe annet - nyttelasten vil fortsatt være flere ganger mindre enn volumet til hele denne vektoren. Derfor, mens vi biter hjerter og tenner, forlot vi denne tilnærmingen og gikk videre til en annen.

Spanner TrueTime. Atomklokke

Jeg sa at det ville være en historie om Spanner. Dette er en kul ting, rett ut av det XNUMX. århundre: atomklokker, GPS-synkronisering.

Hva er ideen? "Spanner" er et Google-system som nylig til og med ble tilgjengelig for folk (de la til SQL til det). Hver transaksjon der har et tidsstempel. Siden tiden er synkronisert*, kan hver hendelse tildeles en bestemt tid - atomklokker har en ventetid, hvoretter en annen tid er garantert å "skje".

HighLoad++, Mikhail Tyulenev (MongoDB): Årsakskonsistens: fra teori til praksis

Dermed, ved ganske enkelt å skrive til databasen og vente i en viss periode, garanteres serialisering av arrangementet automatisk. De har den sterkeste konsistensmodellen som kan tenkes i prinsippet – det er ekstern konsistens.

* Dette er hovedproblemet med Lampart-klokker - de er aldri synkrone på distribuerte systemer. De kan avvike; selv med NTP fungerer de fortsatt ikke veldig bra. "Spanner" har en atomklokke og synkronisering, ser det ut til, er mikrosekunder.

Hvorfor valgte vi ikke? Vi antar ikke at våre brukere har innebygd atomklokke. Når de dukker opp, som er innebygd i hver bærbar PC, vil det være en slags superkul GPS-synkronisering - så ja... Men foreløpig er det beste som er mulig Amazon, basestasjoner - for fanatikere... Så vi brukte andre klokker .

Hybrid klokke

Dette er faktisk det som tikker av i MongoDB når man sikrer årsakssammenheng. Hvordan er de hybride? Hybrid er en skalarverdi, men den har to komponenter:

HighLoad++, Mikhail Tyulenev (MongoDB): Årsakskonsistens: fra teori til praksis

  • Den første er Unix-epoken (hvor mange sekunder har gått siden "begynnelsen av dataverdenen").
  • Den andre er en økning, også en 32-bits usignert int.

Det er alt, faktisk. Det er denne tilnærmingen: delen som er ansvarlig for tiden er synkronisert med klokken hele tiden; hver gang en oppdatering skjer, synkroniseres denne delen med klokken og det viser seg at tiden alltid er mer eller mindre riktig, og inkrement lar deg skille mellom hendelser som har skjedd på samme tidspunkt.

Hvorfor er dette viktig for MongoDB? Fordi det lar deg lage en slags backup-restauranter på et bestemt tidspunkt, det vil si at hendelsen indekseres etter tid. Dette er viktig når det er behov for visse hendelser; For en database er hendelser endringer i databasen som skjedde med bestemte tidsintervaller.

Jeg vil fortelle deg den viktigste grunnen bare til deg (vær så snill, ikke fortell noen)! Vi gjorde dette fordi det er slik organiserte, indekserte data ser ut i MongoDB OpLog. OpLog er en datastruktur som inneholder absolutt alle endringer i databasen: de går først til OpLog, og deretter brukes de på selve Storage i tilfelle det er en replikert dato eller shard.

Dette var hovedårsaken. Likevel stilles det også praktiske krav til å utvikle en database, som gjør at den skal være enkel – lite kode, så få ødelagte ting som mulig som må skrives om og testes. Det faktum at oploggene våre ble indeksert av hybridklokker hjalp mye og tillot oss å ta det riktige valget. Det lønnet seg virkelig og fungerte på en magisk måte på den aller første prototypen. Det var veldig kult!

Klokkesynkronisering

Det er flere synkroniseringsmetoder beskrevet i vitenskapelig litteratur. Jeg snakker om synkronisering når vi har to forskjellige skår. Hvis det er ett replikasett, er det ikke behov for noen synkronisering: dette er en "single master"; vi har en OpLog, som alle endringer faller inn i - i dette tilfellet er alt allerede sekvensielt bestilt i selve "Oplog". Men hvis vi har to forskjellige skår, er tidssynkronisering viktig her. Det var her vektorklokken hjalp mer! Men vi har dem ikke.

HighLoad++, Mikhail Tyulenev (MongoDB): Årsakskonsistens: fra teori til praksis

Den andre passer - dette er "Heartbeats". Det er mulig å utveksle noen signaler som oppstår hver tidsenhet. Men hjerteslag er for sakte, vi kan ikke gi ventetid til vår klient.

Sann tid er selvfølgelig en fantastisk ting. Men igjen, dette er sannsynligvis fremtiden... Selv om det allerede kan gjøres i Atlas, finnes det allerede raske "Amazon"-tidssynkronisatorer. Men det vil ikke være tilgjengelig for alle.

Sladder er når alle meldinger inkluderer tid. Dette er omtrent det vi bruker. Hver melding mellom noder, en driver, en datanoderuter, absolutt alt for MongoDB er en slags element, en databasekomponent som inneholder en klokke som kjører. De har betydningen av hybridtid overalt, den overføres. 64 biter? Dette tillater, dette er mulig.

Hvordan fungerer det hele sammen?

Her ser jeg på ett replikasett for å gjøre det litt enklere. Det er primær og sekundær. Secondary replikerer og er ikke alltid helt synkronisert med Primær.

En innsetting skjer i "Primery" med en viss tidsverdi. Dette innlegget øker det interne antallet med 11, hvis dette er maksimum. Eller den vil sjekke klokkeverdiene og synkronisere med klokken hvis klokkeverdiene er større. Dette lar deg organisere etter tid.

Etter at han har gjort innspillingen, inntreffer et viktig øyeblikk. Klokken er i "MongoDB" og økes kun ved skriving til "Oplog". Dette er hendelsen som endrer tilstanden til systemet. I absolutt alle klassiske artikler anses en hendelse å være når en melding treffer en node: meldingen har kommet, noe som betyr at systemet har endret tilstand.

Dette skyldes at det under forskning ikke er helt klart hvordan dette budskapet vil bli tolket. Vi vet med sikkerhet at hvis det ikke reflekteres i "Oplog", så vil det ikke bli tolket på noen måte, og en endring i systemets tilstand er bare en oppføring i "Oplog". Dette forenkler alt for oss: modellen forenkler det, og lar oss organisere det i ett replikasett, og mange andre nyttige ting.

Verdien som allerede er skrevet til "Oplog" blir returnert - vi vet at "Oplog" allerede inneholder denne verdien, og tiden er 12. Nå begynner for eksempel lesing fra en annen node (Sekundær), og den overfører afterClusterTime i meldingen. Han sier: "Jeg trenger alt som skjedde minst etter 12 eller i løpet av tolv" (se bildet over).

Dette er det som kalles Causal a consistent (CAT). Det er et slikt konsept i teorien at dette er en del av tiden, som er konsistent i seg selv. I dette tilfellet kan vi si at dette er tilstanden til systemet som ble observert på tidspunkt 12.

Nå er det ingenting her ennå, fordi denne typen simulerer situasjonen når du trenger sekundæren for å replikere data fra primæren. Han venter ... Og nå har dataene kommet - han returnerer disse verdiene tilbake.

HighLoad++, Mikhail Tyulenev (MongoDB): Årsakskonsistens: fra teori til praksis

Det er omtrent slik det hele fungerer. Nesten.

Hva betyr "nesten"? La oss anta at det er en person som har lest og forstått hvordan alt dette fungerer. Jeg innså at hver gang ClusterTime oppstår, oppdaterer den den interne logiske klokken, og deretter øker den neste oppføringen med én. Denne funksjonen tar 20 linjer. La oss si at denne personen overfører det største 64-bits nummeret, minus én.

Hvorfor "minus en"? Fordi den interne klokken vil bli erstattet med denne verdien (selvfølgelig er dette størst mulig og større enn gjeldende klokkeslett), så vil en oppføring skje i "Oplog", og klokken vil økes med en annen enhet - og det vil allerede være en maksimal verdi (det er rett og slett alle enheter, det er ingen andre steder å gå), unsaint ints).

Det er klart at systemet etter dette blir absolutt utilgjengelig for noe. Den kan bare losses og rengjøres - mye manuelt arbeid. Full tilgjengelighet:

HighLoad++, Mikhail Tyulenev (MongoDB): Årsakskonsistens: fra teori til praksis

Dessuten, hvis dette replikeres et annet sted, faller hele klyngen rett og slett ned. En absolutt uakseptabel situasjon som alle kan organisere veldig raskt og enkelt! Derfor betraktet vi dette øyeblikket som et av de viktigste. Hvordan forhindre det?

Vår måte er å signere clusterTime

Slik overføres det i meldingen (før den blå teksten). Men vi begynte også å generere en signatur (blå tekst):

HighLoad++, Mikhail Tyulenev (MongoDB): Årsakskonsistens: fra teori til praksis

Signaturen genereres av en nøkkel som er lagret inne i databasen, innenfor en sikker perimeter; i seg selv genereres og oppdateres (brukere ser ikke noe om det). En hash genereres, og hver melding signeres når den opprettes og valideres når den mottas.
Spørsmålet dukker sannsynligvis opp i folks sinn: "Hvor mye bremser dette ting?" Jeg fortalte deg at det burde fungere raskt, spesielt i fravær av denne funksjonen.

Hva betyr det å bruke årsakssammenheng i dette tilfellet? Dette er for å vise afterClusterTime-parameteren. Uten dette vil den ganske enkelt passere verdier uansett. Sladder, fra og med versjon 3.6, fungerer alltid.

Hvis vi forlater den konstante genereringen av signaturer, vil det bremse systemet selv i fravær av en funksjon, som ikke oppfyller våre tilnærminger og krav. Så hva gjorde vi?

Gjør det raskt!

Det er en ganske enkel ting, men trikset er interessant - jeg deler det, kanskje noen vil være interessert.
Vi har en hash som lagrer de signerte dataene. Alle data går gjennom cachen. Cachen signerer ikke den spesifikke tiden, men Range. Når en verdi kommer, genererer vi et område, maskerer de siste 16 bitene, og vi signerer denne verdien:

HighLoad++, Mikhail Tyulenev (MongoDB): Årsakskonsistens: fra teori til praksis

Ved å motta en slik signatur øker vi systemet (relativt) 65 tusen ganger. Det fungerer bra: når vi utførte eksperimenter, ble tiden faktisk redusert med 10 tusen ganger når vi hadde en sekvensiell oppdatering. Det er klart at når de er uenige, så fungerer ikke dette. Men i de fleste praktiske tilfeller fungerer det. Kombinasjonen av Range-signaturen sammen med signaturen løste sikkerhetsproblemet.

Hva har vi lært?

Lærdom vi har lært av dette:

  • Vi trenger å lese materialer, historier, artikler, fordi vi har mye interessant. Når vi jobber med en funksjon (spesielt nå, når vi gjorde transaksjoner osv.), må vi lese og forstå. Det tar tid, men det er faktisk veldig nyttig fordi det tydeliggjør hvor vi er. Vi så ikke ut til å komme med noe nytt – vi tok bare ingrediensene.

    Generelt er det en viss forskjell i tankegangen når det er en akademisk konferanse (Sigmon, for eksempel) – alle fokuserer på nye ideer. Hva er nytt med algoritmen vår? Det er ikke noe spesielt nytt her. Nyheten ligger snarere i måten vi blandet eksisterende tilnærminger sammen. Derfor er det første å lese klassikerne, og starter med Lampart.

  • I produksjonen er kravene helt andre. Jeg er sikker på at mange av dere ikke står overfor "sfæriske" databaser i et abstrakt vakuum, men med normale, virkelige ting som har problemer med tilgjengelighet, latens og feiltoleranse.
  • Det siste er at vi måtte se på forskjellige ideer og kombinere flere helt forskjellige artikler til en tilnærming, sammen. Ideen om å signere, for eksempel, kom generelt sett fra en artikkel som tok for seg Paxos-protokollen, som for ikke-bysantinske feil er innenfor autorisasjonsprotokollen, for bysantinske - utenfor autorisasjonsprotokollen... Generelt sett er dette nøyaktig hva vi endte opp med å gjøre.

    Det er absolutt ingenting nytt her! Men så fort vi blandet alt sammen... Det er det samme som å si at Olivier-salatoppskriften er tull, for egg, majones og agurker er allerede oppfunnet... Det er omtrent den samme historien.

HighLoad++, Mikhail Tyulenev (MongoDB): Årsakskonsistens: fra teori til praksis

Jeg avslutter med dette. Takk skal du ha!

spørsmål

Spørsmål fra salen (heretter kalt B): – Takk, Mikhail, for rapporten! Temaet om tid er interessant. Du bruker sladder. De sa at alle har sin egen tid, alle kjenner sin lokale tid. Slik jeg forstår det har vi en driver - det kan være mange klienter med drivere, spørringsplanleggere også, shards også... Og hva kommer systemet til hvis vi plutselig har et avvik: noen bestemmer at det er for en minutt foran, noen minuttet bak? Hvor vil vi ende opp?

MT: – Veldig bra spørsmål! Jeg ville bare snakke om skår. Hvis jeg forstår spørsmålet riktig, har vi følgende situasjon: det er skår 1 og skår 2, lesing skjer fra disse to skårene - de har et avvik, de samhandler ikke med hverandre, fordi tiden de vet er forskjellig, spesielt den tiden de eksisterer i oplogs.
La oss si at shard 1 gjorde en million poster, shard 2 gjorde ingenting i det hele tatt, og forespørselen kom til to shards. Og den første har en afterClusterTime på over en million. I en slik situasjon, som jeg forklarte, vil shard 2 aldri svare i det hele tatt.

I: – Jeg ville vite hvordan de synkroniserer og velger én logisk tid?

MT: - Veldig enkelt å synkronisere. Shard, når afterClusterTime kommer til ham og han ikke finner tid i "Oplog", starter ingen godkjent. Det vil si at han hever tiden med hendene til denne verdien. Dette betyr at det ikke har noen hendelser som samsvarer med denne forespørselen. Han skaper denne hendelsen kunstig og blir dermed Causal Consistent.

I: – Hva om det etter dette kommer noen andre hendelser til ham som gikk tapt et sted i nettverket?

MT: – Shard er designet på en slik måte at de ikke kommer igjen, siden det er en enkelt mester. Hvis han allerede har meldt seg på, så kommer de ikke, men kommer senere. Det kan ikke skje at noe blir sittende fast et sted, så skriver han ikke, og så kommer disse hendelsene - og årsakssammenhengen brytes. Når han ikke skriver, bør de alle komme neste (han vil vente på dem).

HighLoad++, Mikhail Tyulenev (MongoDB): Årsakskonsistens: fra teori til praksis

I: – Jeg har flere spørsmål angående køene. Årsakskonsistens forutsetter at det er en spesifikk kø av handlinger som må utføres. Hva skjer hvis en av pakkene våre forsvinner? Her kommer den 10., 11.... den 12. har forsvunnet, og alle andre venter på at den skal gå i oppfyllelse. Og plutselig døde bilen vår, vi kan ikke gjøre noe. Er det en maksimal lengde på køen som samler seg før den kjøres? Hvilken fatal svikt oppstår når en tilstand går tapt? Dessuten, hvis vi skriver ned at det er en tidligere tilstand, bør vi på en eller annen måte starte fra det? Men de dyttet ham ikke bort!

MT: – Også et godt spørsmål! Hva gjør vi? MongoDB har konseptet quorum skriver, quorum leser. I hvilke tilfeller kan en melding gå tapt? Når en skriving ikke er beslutningsdyktig eller når en lesning ikke er beslutningsdyktig (en slags søppel kan også feste seg).
Når det gjelder kausal konsistens, ble det utført en stor eksperimentell test, hvis resultat var at i tilfellet når skriving og lesing er ikke-quorum, forekommer brudd på kausal konsistens. Akkurat det du sier!

Vårt råd: bruk minst quorumslesing når du bruker årsakssammenheng. I dette tilfellet vil ingenting gå tapt, selv om quorumsposten går tapt... Dette er en ortogonal situasjon: hvis brukeren ikke vil at data skal gå tapt, må han bruke en quorumspost. Årsaksmessig konsistens garanterer ikke holdbarhet. Holdbarhet er garantert av replikering og maskineriet knyttet til replikering.

I: – Når vi oppretter en instans som utfører sharding for oss (henholdsvis ikke master, men slave), er den avhengig av Unix-tiden til sin egen maskin eller tiden til "mesteren"; Synkroniserer den for første gang eller med jevne mellomrom?

MT: – Jeg skal avklare nå. Shard (dvs. horisontal partisjon) – det er alltid en Primær der. Og et skår kan ha en "mester", og det kan være kopier. Men sharden støtter alltid opptak, fordi den må støtte et eller annet domene (sharden har Primær).

I: – Så alt avhenger rent av «mesteren»? Brukes alltid mastertid?

MT: - Ja. Du kan figurativt si: klokken tikker når en inntreden i "master", i "Oplog" skjer.

I: – Vi har en klient som kobler opp og ikke trenger å vite noe om tiden?

MT: – Du trenger ikke å vite noe i det hele tatt! Hvis vi snakker om hvordan det fungerer på klienten: når klienten ønsker å bruke årsakssammenheng, må han åpne en økt. Nå er alt der: transaksjoner i økten, og hente rettigheter... En økt er bestilling av logiske hendelser som skjer med klienten.

Hvis han åpner denne økten og sier der at han vil ha årsakssammenheng (hvis økten støtter årsakssammenheng som standard), fungerer alt automatisk. Sjåføren husker denne tiden og øker den når den mottar en ny melding. Den husker hvilket svar den forrige returnerte fra serveren som returnerte dataene. Den neste forespørselen vil inneholde afterCluster("tid større enn dette").

Kunden trenger ikke å vite absolutt noe! Dette er helt ugjennomsiktig for ham. Hvis folk bruker disse funksjonene, hva kan de gjøre? For det første kan du trygt lese sekundærer: du kan skrive til Primær og lese fra geografisk replikerte sekundærer og være sikker på at det fungerer. Samtidig kan økter som ble tatt opp på Primær til og med overføres til Secondary, det vil si at du ikke kan bruke én økt, men flere.

I: – Et nytt lag med datavitenskap – CRDT (Conflict-free Replicated Data Types) datatyper – er sterkt relatert til emnet Eventuell konsistens. Har du vurdert å integrere denne typen data i databasen og hva kan du si om det?

MT: - Godt spørsmål! CRDT gir mening for skrivekonflikter: i MongoDB, enkelt master.

I: – Jeg har et spørsmål fra devopsene. I den virkelige verden er det slike jesuittiske situasjoner når den bysantinske fiaskoen oppstår, og onde mennesker innenfor den beskyttede omkretsen begynner å stikke inn i protokollen, sende håndverkspakker på en spesiell måte?

HighLoad++, Mikhail Tyulenev (MongoDB): Årsakskonsistens: fra teori til praksis

MT: – Onde mennesker innenfor omkretsen er som en trojansk hest! Onde mennesker innenfor omkretsen kan gjøre mange dårlige ting.

I: – Det er klart at det å etterlate, grovt sett, et hull i serveren som du kan skyve en dyrehage av elefanter gjennom og kollapse hele klyngen for alltid... Det vil ta tid for manuell gjenoppretting... Dette, for å si det mildt, er feil. På den annen side er dette interessant: i det virkelige liv er det i praksis situasjoner når naturlig lignende interne angrep forekommer?

MT: – Siden jeg sjelden møter sikkerhetsbrudd i det virkelige liv, kan jeg ikke si om de skjer. Men hvis vi snakker om utviklingsfilosofien, tenker vi slik: vi har en omkrets som gir gutta som driver med sikkerhet - dette er et slott, en mur; og innenfor omkretsen kan du gjøre hva du vil. Det er tydelig at det er brukere med muligheten til kun å se, og det er brukere med muligheten til å slette katalogen.

Avhengig av rettighetene kan skaden som brukere kan gjøre, være en mus, eller det kan være en elefant. Det er klart at en bruker med fulle rettigheter kan gjøre hva som helst. En bruker med begrensede rettigheter kan forårsake betydelig mindre skade. Spesielt kan det ikke bryte systemet.

I: – I den beskyttede perimeteren prøvde noen å lage uventede protokoller for serveren for å fullstendig ødelegge serveren, og hvis du er heldig, hele klyngen... Blir det noen gang så "bra"?

MT: "Jeg har aldri hørt om slike ting." At du kan krasje en server på denne måten er ingen hemmelighet. Feil inne, være fra protokollen, være en autorisert bruker som kan skrive noe slikt i meldingen... Faktisk er det umulig, fordi det fortsatt vil bli verifisert. Det er mulig å deaktivere denne autentiseringen for brukere som ikke ønsker det - da er det deres problem; de, grovt sett, ødela selve veggene og du kan dytte en elefant inn der, som vil tråkke... Men generelt kan du kle deg ut som en reparatør, kom og dra den ut!

I: – Takk for rapporten. Sergey (Yandex). Det er en konstant i Mong som begrenser antall stemmeberettigede medlemmer i replikasettet, og denne konstanten er 7 (sju). Hvorfor er dette en konstant? Hvorfor er ikke dette en slags parameter?

MT: – Vi har replikasett med 40 noder. Det er alltid flertall. Jeg vet ikke hvilken versjon...

I: – I Replica Set kan du kjøre medlemmer uten stemmerett, men det er maksimalt 7 stemmeberettigede medlemmer. Hvordan kan vi overleve nedleggelsen i dette tilfellet hvis vårt Replica Set er spredt på 3 datasentre? Ett datasenter kan enkelt slås av, og en annen maskin kan falle ut.

MT: – Dette er allerede litt utenfor rapportens rammer. Dette er et generelt spørsmål. Kanskje jeg kan fortelle deg om det senere.

HighLoad++, Mikhail Tyulenev (MongoDB): Årsakskonsistens: fra teori til praksis

Noen annonser 🙂

Takk for at du bor hos oss. Liker du artiklene våre? Vil du se mer interessant innhold? Støtt oss ved å legge inn en bestilling eller anbefale til venner, cloud VPS for utviklere fra $4.99, en unik analog av entry-level servere, som ble oppfunnet av oss for deg: Hele sannheten om VPS (KVM) E5-2697 v3 (6 kjerner) 10GB DDR4 480GB SSD 1Gbps fra $19 eller hvordan dele en server? (tilgjengelig med RAID1 og RAID10, opptil 24 kjerner og opptil 40 GB DDR4).

Dell R730xd 2x billigere i Equinix Tier IV datasenter i Amsterdam? Bare her 2 x Intel TetraDeca-Core Xeon 2x E5-2697v3 2.6GHz 14C 64GB DDR4 4x960GB SSD 1Gbps 100 TV fra $199 i Nederland! Dell R420 - 2x E5-2430 2.2Ghz 6C 128GB DDR3 2x960GB SSD 1Gbps 100TB - fra $99! Lese om Hvordan bygge infrastruktur corp. klasse med bruk av Dell R730xd E5-2650 v4-servere verdt 9000 euro for en krone?

Kilde: www.habr.com

Legg til en kommentar