HighLoad++, Mikhail Tyulenev (MongoDB): Causal consistency: frÄn teori till praktik

NÀsta konferens HighLoad++ Àger rum den 6 och 7 april 2020 i Sankt Petersburg.
Detaljer och biljetter via lÀnken. HighLoad++ Sibirien 2019. Sal "Krasnojarsk". 25 juni, 12:00. Sammanfattningar och presentation.

HighLoad++, Mikhail Tyulenev (MongoDB): Causal consistency: frÄn teori till praktik

Det förekommer att praktiska krav krockar med teorin, dÀr viktiga aspekter för kommersiella produkter inte beaktas. I detta föredrag presenteras processen för att vÀlja och kombinera olika metoder för att skapa komponenter för kausal konsistens baserat pÄ akademiska studier, med utgÄngspunkt i kraven för kommersiella produkter. Lyssnarna fÄr veta mer om de teoretiska metoderna för logiska klockor, beroendespÄrning, systemettÀnkande, klocksynchronisering, och varför MongoDB valde vissa lösningar.

Mikhail Tyulenev (hĂ€danefter MT): – Jag kommer att prata om kausal konsistens – en funktion som vi arbetade med pĂ„ MongoDB. Jag jobbar i gruppen för distribuerade system, vi utvecklade den för cirka tvĂ„ Ă„r sedan.

HighLoad++, Mikhail Tyulenev (MongoDB): Causal consistency: frÄn teori till praktik

Under processen var jag tvungen att bekanta mig med en stor mÀngd akademisk forskning, eftersom denna funktion Àr ganska vÀlstudierad. Det visade sig att ingen artikel passar in i vad som krÀvs i produktion, en databas med mycket specifika krav som i stort sett finns i alla produktionsapplikationer.

Jag kommer att diskutera hur vi, som konsumenter av akademisk forskning, förbereder nÄgot sÄdant som vi sedan kan erbjuda vÄra anvÀndare i form av en fÀrdig produkt, som Àr bekvÀm och sÀker att anvÀnda.

Kausal konsistens. Definiera termer

Till att börja med vill jag i allmĂ€nna termer förklara vad kausal konsistens Ă€r. Det finns tvĂ„ karaktĂ€rer – Leonard och Penny (frĂ„n serien "Den stora upptĂ€ckten"):

HighLoad++, Mikhail Tyulenev (MongoDB): Causal consistency: frÄn teori till praktik

Anta att Penny Àr i Europa, och Leonard vill göra en överraskning för henne, en fest. Och han kommer inte pÄ nÄgot bÀttre Àn att ta bort henne frÄn vÀnlistan, skicka en uppdatering till alla sina vÀnner pÄ flödet: "LÄt oss glÀdja Penny!" (hon Àr i Europa, sover, ser inget av detta och kan inte se, eftersom hon inte Àr dÀr). I slutet tar han bort det inlÀgget, raderar det frÄn "Flödet" och ÄterstÀller tillgÄngen sÄ att hon inte mÀrker nÄgot och inga skandaler uppstÄr.
Det hÀr Àr allt utmÀrkt, men lÄt oss anta att systemet Àr distribuerat och att hÀndelserna inte har gÄtt riktigt som de borde. Det kan till exempel hÀnda att begrÀnsningen av access till Penny intrÀffade efter att detta inlÀgg postades, om hÀndelserna inte Àr relaterade till varandra med orsakssamband. Detta Àr i sjÀlva verket ett exempel pÄ nÀr kausal konsistens krÀvs för att genomföra en affÀrsfunktion (i detta fall).

Detta Ă€r faktiskt ganska icke-triviala egenskaper hos databaser – mycket fĂ„ system stödjer dem. LĂ„t oss gĂ„ vidare till modellerna.

Konsistensmodeller (Consistency Models)

Vad Àr egentligen en konsistensmodell i databaser? Det Àr vissa garantier som ett distribuerat system ger angÄende vilka data och i vilken ordning en kund kan fÄ dem.

I princip kan alla konsistensmodeller reduceras till hur likt det distribuerade systemet fungerar som ett system som till exempel körs pÄ en nod pÄ en bÀrbar dator. Och i vilken grad ett system som körs pÄ tusentals geografiskt distribuerade noder liknar en bÀrbar dator dÀr alla dessa egenskaper uppfylls automatiskt.

DÀrför tillÀmpas konsistensmodeller endast pÄ distribuerade system. Alla system som tidigare existerade och fungerade med vertikal skalning upplevde inte sÄdana problem. Det fanns en Buffer Cache och all data lÀstes alltid dÀrifrÄn.

Stark modell

Den allra första modellen Àr den Starka (eller Linearity, som den ofta kallas). Det Àr en konsistensmodell som garanterar att varje Àndring, sÄ snart den bekrÀftas, blir synlig för alla anvÀndare av systemet.

Detta skapar en global ordning för alla hĂ€ndelser i databasen. Detta Ă€r en mycket stark konsistensegenskap och den Ă€r dessutom kostsam. ÄndĂ„ har den mycket bra stöd. Den Ă€r bara mycket dyr och lĂ„ngsam – den anvĂ€nds sĂ€llan. Detta kallas linearitet.

Det finns en annan, Ă€nnu starkare egenskap som stöds i 'Spanner' – den kallas extern konsistens. Vi kommer att prata mer om det senare.

Kausal

NÀsta Àr Causal, precis det jag pratade om. Mellan Strong och Causal finns det ytterligare nÄgra undernivÄer, som jag inte kommer att gÄ in pÄ, men de alla relaterar till Causal. Detta Àr en viktig modell, eftersom den Àr den starkaste av alla modeller, den starkaste konsistensen vid nÀtverk eller partitioner.

Causals Àr faktiskt en situation dÀr hÀndelser Àr kopplade genom orsak och verkan. De uppfattas ofta som Read your on rights ur kundens perspektiv. Om en kund har observerat vissa vÀrden kan han eller hon inte se vÀrden som fanns i det förflutna. De börjar redan se prefixlÀsningar. Allt detta handlar om samma sak.
Causals som en konsistensmodell innebĂ€r en partiell ordning av hĂ€ndelser pĂ„ servern dĂ€r hĂ€ndelser frĂ„n alla kunder observeras i samma sekvens. I detta fall – Leonard och Penny.

Eventual

Den tredje modellen Àr Eventual Consistency. Detta Àr nÄgot som alla distribuerade system stöder, den minimi modell som överhuvudtaget Àr meningsfull. Den innebÀr följande: nÀr vi gör vissa förÀndringar i data, blir de vid en viss tidpunkt konsistenta.

Vid den tidpunkten sĂ€ger den ingenting, annars skulle den ha blivit External Consistency – det skulle ha blivit en helt annan historia. Trots det Ă€r detta en mycket populĂ€r modell, den mest utbredda. Som standard anvĂ€nder alla anvĂ€ndare av distribuerade system Eventual Consistency.

Jag vill ge nÄgra jÀmförande exempel:

HighLoad++, Mikhail Tyulenev (MongoDB): Causal consistency: frÄn teori till praktik

Vad betyder dessa pilar?

  • Latens. NĂ€r styrkan i konsistensen ökar blir den större av uppenbara skĂ€l: man behöver göra fler skrivningar, fĂ„ bekrĂ€ftelse frĂ„n alla vĂ€rdar och noder som deltar i klustret pĂ„ att data redan finns dĂ€r. DĂ€rför ger Eventual Consistency det snabbaste svaret, eftersom man vanligtvis kan committa Ă€ven i minnet och att detta i princip rĂ€cker.
  • TillgĂ€nglighet. Om detta förstĂ„s som systemets möjlighet att svara vid nĂ€tverksavbrott, partitioner eller nĂ„gra typer av fel – ökar felmotstĂ„ndet nĂ€r konsistensmodellen minskar, eftersom vi bara behöver att en vĂ€rd fungerar och samtidigt ger viss data. Eventual Consistency garanterar överhuvudtaget ingenting om data – det kan vara vad som helst.
  • Anomalier. Det Ă€r dock sjĂ€lvklart att antalet anomalier ökar. I stark konsistens bör det knappt förekomma nĂ„gra, medan eventual consistency kan ha vilka anomalier som helst. FrĂ„gan uppstĂ„r: varför vĂ€ljer mĂ€nniskor eventual consistency om den innehĂ„ller anomalier? Svaret ligger i att eventual consistency-modeller Ă€r tillĂ€mpliga och anomalier finns, till exempel under en kort tid; det finns möjlighet att anvĂ€nda en master för att lĂ€sa och mer eller mindre lĂ€sa konsekventa data; det finns ofta möjlighet att anvĂ€nda starka konsistensmodeller. Praktiskt fungerar detta, och ofta Ă€r antalet anomalier tidsbegrĂ€nsat.

CAP-teoremet

NĂ€r du ser orden konsistens, tillgĂ€nglighet – vad kommer dĂ„ till ditt sinne? RĂ€tt, CAP-teoremet! Jag vill nu avfĂ€rda en myt... Det Ă€r inte jag – det Ă€r Martin Kleppmann som har skrivit en utmĂ€rkt artikel, en utmĂ€rkt bok.

HighLoad++, Mikhail Tyulenev (MongoDB): Causal consistency: frÄn teori till praktik

CAP-teoremet Ă€r ett principiellt uttalande som formulerades under 2000-talet, om att konsistens, tillgĂ€nglighet och partitioner: ta vilken som helst av de tvĂ„, och du kan inte vĂ€lja tre. Det var ett slags princip. Det bevisades som en teorem nĂ„gra Ă„r senare av Gilbert och Lynch. Sedan började det anvĂ€nda som en mantra – system började delas upp i CA, CP, AP och sĂ„ vidare.

Detta teorem bevisades faktiskt för specifika fall... Först betraktades tillgĂ€nglighet inte som ett kontinuerligt vĂ€rde frĂ„n noll till hundra (0 – systemet "dött", 100 – svarar snabbt; vi Ă€r vana vid att se det sĂ„), utan som en egenskap hos en algoritm som garanterar att den vid alla sina körningar Ă„terger data.

Det finns ingen information om svarstiden! Det finns en algoritm som returnerar data efter 100 Ă„r – en helt utmĂ€rkt tillgĂ€nglig algoritm, som Ă€r en del av CAP-teoremet.
För det andra: teoremet bevisades för förÀndringar i vÀrdena av samma nyckel, medan dessa förÀndringar Àr en resizable-linje. Det betyder att de i praktiken nÀstan inte anvÀnds eftersom andra modeller, eventual consistency, strong consistency (kan vara) Àr mer tillÀmpbara.

Vad leder allt detta till? Jo, att CAP-teoremet i den form det bevisats Àr praktiskt taget inte tillÀmpligt, sÀllan anvÀnds. I teoretisk form begrÀnsar det pÄ nÄgot sÀtt allt. Det blir en slags princip som Àr intuitivt korrekt men pÄ nÄgot sÀtt inte bevisad.

Causal consistency – den starkaste modellen

Det som hĂ€nder just nu Ă€r att man kan fĂ„ alla tre saker: Konsistens, TillgĂ€nglighet kan uppnĂ„s med Partitioner. SĂ€rskilt Causal consistency – den starkaste konsistensmodellen, som trots Partitioner (nĂ€tverksavbrott) fortfarande fungerar. DĂ€rför Ă€r den av sĂ„ stort intresse, och dĂ€rför har vi arbetat med den.

HighLoad++, Mikhail Tyulenev (MongoDB): Causal consistency: frÄn teori till praktik

För det första förenklar den utvecklarnas arbete. Speciellt finns det stort stöd frÄn servern: nÀr alla poster som görs av en enda klient garanterat kommer i rÀtt ordning till en annan klient. För det andra klarar den av partitioner.

Den interna verksamheten i MongoDB

Med tanke pÄ att det Àr lunch, rör vi oss till köket. Jag kommer att förklara systemmodellen, nÀmligen vad MongoDB Àr för dem som hör talas om denna databas för första gÄngen.

HighLoad++, Mikhail Tyulenev (MongoDB): Causal consistency: frÄn teori till praktik

HighLoad++, Mikhail Tyulenev (MongoDB): Causal consistency: frÄn teori till praktik

MongoDB (nedan kallad "MongoDB") Àr ett distribuerat system som stöder horisontell skalning, det vill sÀga sharding; och inom varje shard stöder den ocksÄ dataröda, det vill sÀga replikering.

Sharding i "MongoDB" (en icke-relationell databas) utför automatisk balans, vilket innebÀr att varje dokumentkollektion (eller "tabell" i relationella datatermer) delas upp i bitar, och servern flyttar automatiskt dem mellan sharden.

Query Router, som distribuerar förfrÄgningar, Àr en slags klient för kunden, genom vilken denne arbetar. Den vet redan var och vilka data som finns, och dirigerar alla förfrÄgningar till rÀtt shard.

Ytterligare en viktig punkt: MongoDB Ă€r en single master. Det finns en Primary – den kan ta emot poster som stödjer de nycklar den innehĂ„ller. Multi-master skrivning Ă€r inte möjligt.

Vi har slĂ€ppt version 4.2 – dĂ€r finns nya intressanta saker. SĂ€rskilt har vi infört Lucene – sökningen – precis executable java direkt i "Mongo", och dĂ€r kan man göra sökningar via Lucene, pĂ„ samma sĂ€tt som i "Elasticsearch".

Och vi har skapat en ny produkt - Charts, som ocksĂ„ Ă€r tillgĂ€nglig pĂ„ "Atlas" (Mongo's egna moln). De har en Free Tier – man kan leka med detta. Charts tyckte jag mycket om – datavisualisering, mycket intuitiv.

Ingredienser till Causal consistency

Jag har rĂ€knat till cirka 230 artiklar som har publicerats om detta Ă€mne – av Leslie Lamport. Nu kommer jag att Ă„terge nĂ„gra delar av dessa material frĂ„n mitt minne.

HighLoad++, Mikhail Tyulenev (MongoDB): Causal consistency: frÄn teori till praktik

Allt började med en artikel av Leslie Lampert som skrevs pÄ 1970-talet. Som ni kan se fortsÀtter forskningen inom detta Àmne fortfarande. Just nu fÄr Causal consistency nytt intresse i samband med utvecklingen av distribuerade system.

BegrÀnsningar

Vilka begrÀnsningar finns? Detta Àr faktiskt en av de viktigaste punkterna eftersom begrÀnsningarna som stÀlls av produktionssystem skiljer sig kraftigt frÄn de som finns i akademiska artiklar. Ofta Àr de ganska artificiella.

HighLoad++, Mikhail Tyulenev (MongoDB): Causal consistency: frÄn teori till praktik

  • För det första Ă€r "MongoDB" ett single master, som jag redan har sagt (detta förenklar mycket).
  • Vi anser att systemet bör stödja omkring 10 000 shards. Vi kan inte fatta arkitektoniska beslut som uppenbart skulle begrĂ€nsa detta vĂ€rde.
  • Vi har en molntjĂ€nst, men vi anser att anvĂ€ndare ska ha möjligheten att ladda ner en binĂ€r och köra den pĂ„ sin laptop, och allt ska fungera perfekt.
  • Vi förutsĂ€tter att det som sĂ€llan anvĂ€nds i forskning Ă€r: externa klienter kan göra vad de vill. "MongoDB" Ă€r open source. SĂ„ledes kan klienterna vara smarta, elaka – de kan vilja förstöra allt. Vi förutsĂ€tter att bysantinska fel kan intrĂ€ffa.
  • För externa klienter, som befinner sig utanför perimeterna – en viktig begrĂ€nsning: om den hĂ€r funktionen Ă€r avstĂ€ngd, bör inga prestandaförsĂ€mringar observeras.
  • En annan punkt – överhuvudtaget antiakademisk: kompatibilitet mellan tidigare versioner och framtida. Gamla drivrutiner mĂ„ste stödja nya uppdateringar, och databasen mĂ„ste stödja gamla drivrutiner.

I stort sett stÀller allt detta upp begrÀnsningar.

Komponenter av Causal consistency

Jag kommer nu att tala om nĂ„gra av komponenterna. Om man överhuvudtaget ser pĂ„ Causal consistency kan man identifiera block. Vi valde frĂ„n arbeten som relaterar till nĂ„got block: Dependency Tracking, valet av klockor, hur dessa klockor kan synkroniseras och hur vi sĂ€kerstĂ€ller sĂ€kerheten – detta Ă€r en ungefĂ€rlig plan för vad jag kommer att tala om:

HighLoad++, Mikhail Tyulenev (MongoDB): Causal consistency: frÄn teori till praktik

FullstÀndig spÄrning av beroenden (Full Dependency Tracking)

Varför behövs det? För att nÀr data replikeras, ska varje post och varje Àndring av data innehÄlla information om vilka förÀndringar den Àr beroende av. Den allra första och mest grundlÀggande förÀndringen Àr nÀr varje meddelande, som innehÄller en post, Àven innehÄller information om tidigare meddelanden:

HighLoad++, Mikhail Tyulenev (MongoDB): Causal consistency: frÄn teori till praktik

I det hĂ€r exemplet representerar numret inom klamrarna – posternas nummer. Ibland överförs dessa poster med vĂ€rden till och med helt, ibland överförs vissa versioner. PoĂ€ngen Ă€r att varje Ă€ndring innehĂ„ller information om den föregĂ„ende (den bĂ€r tydligt detta i sig).

Varför beslutade vi oss för att inte anvĂ€nda den metoden (full spĂ„rning)? Uppenbart för att denna metod Ă€r opraktisk: varje förĂ€ndring i ett socialt nĂ€tverk beror pĂ„ alla tidigare förĂ€ndringar i det sociala nĂ€tverket, vilket skulle innebĂ€ra att man mĂ„ste skicka, lĂ„t oss sĂ€ga, "Facebook" eller "VKontakte" i varje uppdatering. Det finns dock mĂ„nga studier om Full Dependency Tracking – detta före sociala medier, vilket fungerar i vissa situationer.

Tydlig spÄrning av beroenden (Explicit Dependency Tracking)

Den följande metoden Àr mer begrÀnsad. HÀr diskuteras ocksÄ överföringen av information, men endast den som Àr tydligt beroende. Vad som beror pÄ vad bestÀms vanligtvis av applikationen. NÀr data replikeras, ges endast svar nÀr tidigare beroenden har uppfyllts, det vill sÀga nÀr de har visats. Det Àr sjÀlva essensen av hur kausal konsistens fungerar.

HighLoad++, Mikhail Tyulenev (MongoDB): Causal consistency: frÄn teori till praktik

Den ser att post 5 Ă€r beroende av poster 1, 2, 3, 4 – dĂ€rmed vĂ€ntar den innan klienten fĂ„r tillgĂ„ng till de Ă€ndringar som gjorts av Penny's access-beslut, nĂ€r alla tidigare Ă€ndringar redan har utförts i databasen.

Detta passar oss inte heller, eftersom det fortfarande finns för mycket information, och detta kommer att sakta ner processen. Det finns en annan metod


Lamports klocka (Lamport Clock)

De Àr mycket gamla. Lamport Clock innebÀr att dessa beroenden sammanfattas i en skalarfunktion, som kallas Lamport Clock.

En skalar funktion Ă€r ett abstrakt tal. Den kallas ofta för logisk tid. Vid varje hĂ€ndelse ökar denna counter. Den counter som processen just nu kĂ€nner till skickar varje meddelande. Det Ă€r klart att processerna kan vara desynkroniserade, de kan ha helt olika tider. ÄndĂ„ balanserar systemet pĂ„ nĂ„got sĂ€tt klockorna genom denna meddelandeutbyte. Vad hĂ€nder i sĂ„ fall?

Jag delade den stora shard i tvĂ„ för att göra det tydligt: VĂ€nner kan bo pĂ„ en nod som innehĂ„ller en del av samlingen, medan Feed – helt pĂ„ en annan nod, som innehĂ„ller en del av denna samling. Hur kan de dĂ„ hamna utanför kön? Först sĂ€ger Feed: "Replikerad", och sedan – VĂ€nner. Om systemet inte garanterar att Feed inte kommer att visas förrĂ€n beroenden för VĂ€nner i samlingen ocksĂ„ har levererats, sĂ„ kommer vi precis att fĂ„ den situation som jag nĂ€mnde.

Du ser hur den logiska tiden för counter pÄ Feed ökar:

HighLoad++, Mikhail Tyulenev (MongoDB): Causal consistency: frÄn teori till praktik

DÀrför Àr huvudegenskapen hos denna Lamport-klocka och kausal konsistens (förklarad genom Lamport-klockan) följande: om vi har hÀndelser A och B, och hÀndelse B beror pÄ hÀndelse A *, sÄ följer det att LogicalTime för Event A Àr mindre Àn LogicalTime för Event B.

* Ibland sĂ€gs det ocksĂ„ att A hĂ€nde före B, det vill sĂ€ga A intrĂ€ffade före B – detta Ă€r en relation som delvis ordnar hela mĂ€ngden av hĂ€ndelser som har intrĂ€ffat.

Detta gĂ€ller inte Ă„t andra hĂ„llet. Det Ă€r faktiskt en av de största nackdelarna med Lamport-klockan – delvis ordning. Det finns en uppfattning om samtidiga hĂ€ndelser, det vill sĂ€ga hĂ€ndelser dĂ€r varken (A hĂ€nde före B) eller (B hĂ€nde före A). Ett exempel kan vara parallell vĂ€nskap som Leonard lĂ€gger till nĂ„gon annan (inte ens Leonard, utan Sheldon till exempel).
Det Ă€r just denna egenskap som ofta utnyttjas vid arbete med Lamport-klockor: man ser just pĂ„ funktionen och drar slutsatsen – kanske Ă€r dessa hĂ€ndelser beroende av varandra. För i en riktning Ă€r det sant: om LogicalTime A Ă€r mindre Ă€n LogicalTime B, sĂ„ kan B inte hĂ€nda före A; och om det Ă€r större, sĂ„ kan det vara.

Vektor klockor (Vector Clock)

Det logiska utvecklingen av Lamport-klockan Àr Vektor klockor. De skiljer sig Ät genom att varje nod som finns hÀr innehÄller sina egna, separata klockor, och de överförs som en vektor.
I det hĂ€r fallet ser du att den noll-indexerade vektorn svarar för Feed, medan den första indexerade vektorn svarar för Friends (var och en av dessa noder). Och nu kommer de att öka: noll-indexen för "Feed" ökar vid skrivning – 1, 2, 3:

HighLoad++, Mikhail Tyulenev (MongoDB): Causal consistency: frÄn teori till praktik

Vad gör vektorur bÀttre? De gör det möjligt att förstÄ vilka hÀndelser som Àr samtidiga och nÀr de sker pÄ olika noder. Detta Àr mycket viktigt för sharding-systemet som "MongoDB". Vi valde dock inte detta, Àven om det Àr en fantastisk sak som fungerar bra och skulle passa oss, antagligen...

Om vi har 10 000 shardar kan vi inte överföra 10 000 komponenter, Ă€ven om vi komprimerar och hittar pĂ„ andra lösningar – lastern kommer fortfarande att vara mĂ„nga gĂ„nger mindre Ă€n volymen av hela denna vektor. SĂ„, med tungt hjĂ€rta och tĂ€nder, avstod vi frĂ„n detta tillvĂ€gagĂ„ngssĂ€tt och gick över till ett annat.

Spanner TrueTime. Atomur

Jag sa att det skulle handla om "Spanner". Det Àr en fantastisk grej, verkligen 2000-talet: atomur, GPS-synkronisering.

Vad Ă€r idĂ©n? "Spanner" Ă€r ett Google-system som nyligen blev tillgĂ€ngligt för allmĂ€nheten (de lade till SQL). Varje transaktion dĂ€r har en viss tidsstĂ€mpel. Eftersom tiden Ă€r synkroniserad* kan varje hĂ€ndelse tilldelas en specifik tid – atomuren har vĂ€ntetid efter vilken en annan tid garanterat "sker".

HighLoad++, Mikhail Tyulenev (MongoDB): Causal consistency: frÄn teori till praktik

SĂ„ genom att helt enkelt skriva till databasen och vĂ€nta en viss tidsperiod garanteras serialiserbarheten för hĂ€ndelsen automatiskt. De har den starkaste konsistensmodellen som överhuvudtaget kan förestĂ€llas – den Ă€r extern konsistens.

* Detta Ă€r det grundlĂ€ggande problemet med Lamports klockor – de Ă€r aldrig synkroniserade i distribuerade system. De kan avvika, Ă€ven med NTP fungerar de fortfarande inte sĂ€rskilt bra. "Spanner" har atomur och synkronisering, verkar vara pĂ„ mikrosekundsnivĂ„.

Varför valde vi inte det? Vi förutsĂ€tter inte att vĂ„ra anvĂ€ndare har inbyggda atomur. NĂ€r de blir inbyggda i varje laptop, med supercool GPS-synkronisering – dĂ„ ja
 Men just nu Ă€r det bĂ€sta som Ă€r möjligt – "Amazon", basstationer – för entusiaster
 DĂ€rför anvĂ€nde vi andra klockor.

Hybridklockor (Hybrid Clock)

Det hÀr Àr faktiskt vad som tickar i 'MongoDB' för att sÀkerstÀlla kausal konsistens. Vad Àr de hybridiska? En hybrid Àr ett skalarvÀrde, men det bestÄr av tvÄ komponenter:

HighLoad++, Mikhail Tyulenev (MongoDB): Causal consistency: frÄn teori till praktik

  • Den första Ă€r Unix-epoken (hur mĂ„nga sekunder som har passerat sedan 'början av den digitala vĂ€rlden').
  • Den andra Ă€r en viss inkrement, ocksĂ„ en 32-bitars unsigned int.

Det Àr faktiskt allt. Det finns en metod: den del som ansvarar för tiden synkroniseras hela tiden med klockan; varje gÄng en uppdatering görs, synkroniseras den delen med klockan och det visar sig att tiden alltid Àr mer eller mindre korrekt, medan inkrementet gör det möjligt att sÀrskilja hÀndelser som intrÀffade vid samma tidpunkt.

Varför Àr detta viktigt för 'MongoDB'? För det möjliggör att skapa backup-restaureringar vid specifika tidpunkter, det vill sÀga hÀndelsen indexeras med tid. Detta Àr viktigt nÀr vissa hÀndelser behövs; för databaser Àr hÀndelser förÀndringar i databasen som intrÀffade vid specifika tidsintervall.

Den viktigaste orsaken sÀger jag endast till er (snÀlla, sÀg det inte till nÄgon annan)! Vi gjorde det pÄ det hÀr sÀttet för att sÄ ser ordnade, indexerade data ut i MongoDB OpLog. OpLog Àr en databasstruktur som innehÄller alla förÀndringar i databasen: de hamnar först i OpLog och tillÀmpas sedan pÄ lagringen i de fall det Àr replikerad data eller shard.

Detta var den huvudsakliga anledningen. Det finns ocksĂ„ praktiska krav pĂ„ databasutveckling, vilket innebĂ€r att det mĂ„ste vara enkelt – lite kod, sĂ„ fĂ„ saker som möjligt som behöver skrivas om och testas. Att vĂ„ra op-logs visade sig vara indexerade med hybridklockor hjĂ€lpte mycket och möjliggjorde rĂ€tt val. Det har verkligen lönat sig och fungerade pĂ„ nĂ„got magiskt sĂ€tt pĂ„ den första prototypen. Det var riktigt hĂ€ftigt!

Klocksynkronisering

Det finns flera sĂ€tt att synkronisera som beskrivs i den vetenskapliga litteraturen. Jag pratar om synkronisering nĂ€r vi har tvĂ„ olika shards. Om det finns ett replikasett sĂ„ behövs ingen synkronisering: det Ă€r en "singel-master"; vi har en OpLog dit alla förĂ€ndringar gĂ„r – i sĂ„ fall Ă€r allt redan sekventiellt ordnat i sjĂ€lva "OpLog". Men om vi har tvĂ„ olika shards Ă€r tidssynkronisering viktig. HĂ€r har vektorklockor hjĂ€lpt mer! Men vi har inga.

HighLoad++, Mikhail Tyulenev (MongoDB): Causal consistency: frÄn teori till praktik

Det andra alternativet Àr "Heartbeats". Man kan utbyta vissa signaler som sker varje tidsenhet. Men "Heartbeats" Àr för lÄngsamma, vi kan inte sÀkerstÀlla latensen för vÄr klient.

True time – det Ă€r sjĂ€lvklart en fantastisk sak. Men Ă„ andra sidan, det Ă€r nog framtiden
 Även om man redan kan göra det i "Atlas", det finns redan snabba "amazoniska" tidssynkroniserare. Men detta kommer inte vara tillgĂ€ngligt för alla.

Gossiping – det Ă€r nĂ€r alla meddelanden inkluderar tid. Det Ă€r ungefĂ€r vad vi anvĂ€nder. Varje meddelande mellan noder, drivrutiner, routers för datanoder, absolut allt för "MongoDB" – det Ă€r vissa element, komponenter i databasen som innehĂ„ller klockor som tickar. De har överallt ett hybridt tidsvĂ€rde som överförs. 64 bitar? Det Ă€r möjligt, det kan göras.

Hur fungerar allt detta tillsammans?

HÀr övervÀger jag ett replikasett för att göra det lite enklare. Det finns en Primary och en Secondary. Secondary gör replikering och Àr inte alltid helt synkroniserad med Primary.

Det sker en insÀttning (insert) i "Primary" med ett visst tidsvÀrde. Denna insÀttning ökar den interna rÀknaren med 11, om det Àr max. Eller sÄ kommer den att kontrollera tidsvÀrdena och synkronisera enligt klockorna, om tidsvÀrdena Àr högre. Det möjliggör tidsordning.

Efter att den har gjort en registrering sker en viktig punkt. Klockorna i "MongoDB" inkrementeras endast vid registrering i "OpLog". Detta Ă€r hĂ€ndelsen som förĂ€ndrar systemets tillstĂ„nd. I praktiskt taget alla klassiska artiklar betraktas en hĂ€ndelse som att ett meddelande kommer in i noden: meddelandet kom – vilket betyder att systemet har Ă€ndrat sitt tillstĂ„nd.

Detta beror pÄ att nÀr man undersöker kan man inte riktigt förstÄ hur detta meddelande kommer att tolkas. Vi vet med sÀkerhet att om det inte reflekteras i "Oploggen", sÄ kommer det inte att tolkas pÄ nÄgot sÀtt, och förÀndringen av systemets tillstÄnd Àr endast en registrering i "Oploggen". Detta förenklar allt för oss: bÄde modellen förenklas och det möjliggör ordning inom ett enda replikasett, och mycket annat anvÀndbart.

Det vĂ€rde som redan Ă€r registrerat i "Oploggen" Ă„terlĂ€mnas – vi vet att detta vĂ€rde redan ligger i "Oploggen", och dess tid Ă€r 12. Nu, lĂ„t oss sĂ€ga, börjar lĂ€sningen frĂ„n en annan nod (SekundĂ€r), och den skickar redan afterClusterTime i sjĂ€lva meddelandet. Den sĂ€ger: "Jag behöver allt som hĂ€nde minst efter 12 eller under klockan tolv" (se bilden ovan).

Detta kallas för Kausal konsekvent (CAT). Det finns ett begrepp i teorin att detta Àr en viss tidsutsikt som Àr konsekvent i sig sjÀlv. I detta fall kan vi sÀga att detta Àr systemets tillstÄnd som observerades vid tidpunkten 12.

Just nu finns det inget hĂ€r, eftersom detta pĂ„ nĂ„got sĂ€tt imiterar situationen nĂ€r SekundĂ€r behöver replikera data frĂ„n PrimĂ€r. Den vĂ€ntar
 Och hĂ€r kommer datan – den Ă„terlĂ€mnar dessa vĂ€rden.

HighLoad++, Mikhail Tyulenev (MongoDB): Causal consistency: frÄn teori till praktik

SÄ hÀr fungerar det ungefÀr. NÀstan.

Vad betyder "nÀstan"? LÄt oss anta att det finns en viss person som lÀste och förstod hur allt detta fungerar. Förstod att varje gÄng sker ClusterTime, den uppdaterar de interna logiska klockorna, och sedan ökar nÀsta registrering med ett. Denna funktion tar 20 rader. Anta att denna person överför det maximalt stora 64-bitars numret, minus ett.

Varför "minus ett"? För att de interna klockorna kommer att sĂ€ttas in i detta vĂ€rde (uppenbarligen det största möjliga och större Ă€n den aktuella tiden), sedan kommer en registrering ske i "Oploggen", och klockorna kommer att öka med Ă€nnu ett – och dĂ„ kommer det att vara det maximala vĂ€rdet (dĂ€r Ă€r bara ettor, det finns inget mer, unsaint int:s).

Det Ă€r tydligt att efter detta blir systemet helt otillgĂ€ngligt för nĂ„got. Det kan bara avlastas, rengöras – mycket manuellt arbete. Full tillgĂ€nglighet:

HighLoad++, Mikhail Tyulenev (MongoDB): Causal consistency: frÄn teori till praktik

Om detta skulle replikeras nÄgon annanstans, skulle hela klustret fallera. En absolut oacceptabel situation som vem som helst snabbt och enkelt kan Ästadkomma! DÀrför betraktade vi denna punkt som en av de viktigaste. Hur kan vi förhindra det?

VÄr vÀg Àr att signera clusterTime

SÄ det överförs i meddelandet (före den blÄ texten). Men vi började ocksÄ generera en signatur (blÄ text):

HighLoad++, Mikhail Tyulenev (MongoDB): Causal consistency: frÄn teori till praktik

Signaturen genereras med en nyckel som lagras inom databasen, inom ett skyddat omrÄde; den genereras och uppdateras (anvÀndare ser inget av detta). En hash genereras, och varje meddelande signeras vid skapandet och valideras vid mottagandet.
Det vÀcker antagligen frÄgan hos folk: "Hur mycket sakta ner allt detta?" Jag har sagt att det ska fungera snabbt, sÀrskilt utan denna funktion.

Vad betyder det att anvÀnda Causal consistency i detta fall? Det innebÀr att visa afterClusterTime-parametern. Utan den kommer den helt enkelt att överföra vÀrden oavsett. Gossiping har alltid fungerat frÄn version 3.6.

Om vi lÀmnar konstant signering av signaturer, kommer det att sakta ner systemet Àven utan funktioner, vilket inte stÀmmer överens med vÄra metoder och krav. Vad gjorde vi?

Gör detta snabbt!

En ganska enkel sak, men en intressant trick – jag delar med mig, kanske nĂ„gon finner det intressant.
Vi har en hash som lagrar signerade data. All information gÄr genom cachen. Cachen signerar inte specifikt tiden, utan Range. NÀr ett visst vÀrde kommer, genererar vi Range, maskerar de senaste 16 bitarna, och det vÀrdet signerar vi:

HighLoad++, Mikhail Tyulenev (MongoDB): Causal consistency: frÄn teori till praktik

Genom att fĂ„ en sĂ„dan signatur ökar vi systemets hastighet (teoretiskt) med 65 tusen gĂ„nger. Det fungerar utmĂ€rkt: nĂ€r vi satte upp experimenten – tiden minskade verkligen med 10 tusen gĂ„nger nĂ€r vi hade sekventiella uppdateringar. Klart att det inte fungerar nĂ€r de Ă€r oordnade. Men i de flesta praktiska fall fungerar det. Kombinationen av Range-signaturen tillsammans med signaturen löste sĂ€kerhetsproblemet.

Vad har vi lÀrt oss?

Lektioner vi dragit frÄn detta:

  • Man mĂ„ste lĂ€sa material, berĂ€ttelser, artiklar, för att vi har mycket intressant. NĂ€r vi arbetar med en funktion (sĂ€rskilt nu nĂ€r vi har genomfört transaktioner osv.) mĂ„ste vi lĂ€sa och förstĂ„. Det tar tid, men det Ă€r verkligen vĂ€ldigt nyttigt, eftersom det blir tydligt var vi stĂ„r. Vi har inte direkt kommit pĂ„ nĂ„got nytt – vi har bara tagit ingredienser.

    Det rĂ„der överhuvudtaget en viss skillnad i tĂ€nkandet nĂ€r det handlar om en akademisk konferens (som "Sigmon", till exempel) – dĂ€r fokuserar alla pĂ„ nya idĂ©er. Vad Ă€r nyheten med vĂ„r algoritm? HĂ€r finns det inte mycket nyhet. Nyheten ligger snarare i hur vi blandade ihop befintliga metoder. DĂ€rför Ă€r det viktigt att lĂ€sa klassikerna, frĂ„n Lamport.

  • Inom produktion Ă€r kraven helt andra. Jag Ă€r sĂ€ker pĂ„ att mĂ„nga av er inte stĂ„r inför "sferiska" databaser i ett abstrakt vakuum, utan med normala, verkliga saker som har problem med tillgĂ€nglighet, latens och felmotstĂ„nd.
  • Det sista Ă€r att vi var tvungna att övervĂ€ga olika idĂ©er och kombinera flera helt olika artiklar till en metod, tillsammans. IdĂ©n om signering, till exempel, kom överhuvudtaget frĂ„n en artikel som behandlade Paxos-protokollet, som för icke-byzantinska fel inom auktorisationsprotokollet, för byzantinska – utanför auktorisationsprotokollet... I stort sett Ă€r det precis vad vi i slutĂ€ndan gjorde.

    Det finns absolut ingenting nytt hÀr! Men sÄ snart vi blandade allt detta tillsammans... Det skulle vara som att sÀga att receptet pÄ Olivier-sallad Àr nonsens, eftersom Àgg, majonnÀs och gurkor redan Àr uppfunna... Det Àr ungefÀr samma historia.

HighLoad++, Mikhail Tyulenev (MongoDB): Causal consistency: frÄn teori till praktik

Jag avslutar hÀr. Tack!

FrÄgor

FrĂ„ga frĂ„n publiken (nedan – F): – Tack, Michail, för föredraget! Temat om tid Ă€r intressant. Ni anvĂ€nder Gossiping. Ni sa att alla har sin egen tid, alla vet sin lokala tid. Jag förstod det som att vi har en drivrutin – det kan finnas mĂ„nga kunder med drivrutiner, ocksĂ„ mĂ„nga query-planners, och det finns ocksĂ„ mĂ„nga shards... Vad hĂ€nder med systemet om vi plötsligt fĂ„r en avvikelse: nĂ„gon bestĂ€mmer sig för att vara en minut före, nĂ„gon annan – en minut efter? Var hamnar vi?

MT: – Faktiskt en bra frĂ„ga! Jag ville just nĂ€mna sharding. Om jag förstĂ„r frĂ„gan rĂ€tt, Ă€r vĂ„r situation sĂ„dan att vi har shard 1 och shard 2, och lĂ€sning sker frĂ„n dessa tvĂ„ shards – de har olika tidpunkter och interagerar inte med varandra, eftersom den tid de Ă€r medvetna om Ă€r olika, sĂ€rskilt tiden som de har i loggarna.
Anta att shard 1 har gjort en miljon poster, medan shard 2 inte har gjort nÄgot. Om en förfrÄgan kommer in till bÀgge shards och den första har afterClusterTime som Àr mer Àn en miljon. I en sÄdan situation, som jag har förklarat, kommer shard 2 aldrig att svara.

L: – Jag ville veta hur de synkroniserar och vĂ€ljer en logisk tid.

MT: – Det Ă€r mycket enkelt att synkronisera. NĂ€r en shard fĂ„r afterClusterTime och inte hittar nĂ„gon tid i "Loggen" – initierar den no approved. Det innebĂ€r att den manuellt höjer sin tid till detta vĂ€rde. Det betyder att den inte har hĂ€ndelser som motsvarar denna förfrĂ„gan. Den skapar denna hĂ€ndelse konstgjort och blir dĂ€rmed Causal Consistent.

L: – Men om den efter det skulle fĂ„ flera hĂ€ndelser, som har försvunnit i nĂ€tverket?

MT: – Sharding Ă€r utformat sĂ„ att de inte kommer att anlĂ€nda, eftersom det Ă€r en single master. Om den redan har skrivit, sĂ„ kommer de inte att anlĂ€nda, utan de kommer senare. Det kan inte hĂ€nda att nĂ„got har fastnat nĂ„gonstans, sen gör den no write, och plötsligt anlĂ€nder dessa hĂ€ndelser – vilket skulle bryta den Causal consistency. NĂ€r den gör no write mĂ„ste alla komma igen (den kommer att vĂ€nta pĂ„ dem).

HighLoad++, Mikhail Tyulenev (MongoDB): Causal consistency: frÄn teori till praktik

L: – Jag har nĂ„gra frĂ„gor angĂ„ende köer. Causal consistency innebĂ€r att det finns en specifik kö av Ă„tgĂ€rder som mĂ„ste utföras. Vad hĂ€nder om en paket försvinner? LĂ„t oss sĂ€ga 10:e, 11:e
 12:e paketet försvinner, medan alla andra vĂ€ntar pĂ„ att det ska utföras. Om plötsligt maskinen kraschar, kan vi inte göra nĂ„got. Finns det en maximal lĂ€ngd pĂ„ kön som samlas innan den utförs? Vilken fatal failure intrĂ€ffar vid förlust av ett enda tillstĂ„nd? Dessutom, om vi skriver att det finns ett tidigare tillstĂ„nd, hur ska vi dĂ„ basera oss pĂ„ det? Men vi baserade oss inte pĂ„ det!

MT: – OcksĂ„ en utmĂ€rkt frĂ„ga! Vad gör vi? I MongoDB finns det begreppet kvorumförĂ€ndringar och kvorumlĂ€sningar. Under vilka omstĂ€ndigheter kan ett meddelande försvinna? NĂ€r en förĂ€ndring inte Ă€r kvorum eller nĂ€r en lĂ€sning inte Ă€r kvorum (det kan ocksĂ„ vara nĂ„got skrĂ€p).
AngÄende Causal consistency har vi genomfört omfattande experimentell testning, vars resultat visar att nÀr skrivningar och lÀsningar Àr icke-kvorum finns det brott mot Causal consistency. Precis det du sÀger!

VÄrt rÄd: anvÀnd Ätminstone kvorum-lÀsning vid anvÀndning av Causal consistency. I sÄ fall kommer inget att gÄ förlorat, Àven om kvorum-skrivningen försvinner... Det Àr en ortogonal situation: om anvÀndaren inte vill att data ska försvinna, mÄste kvorum-skrivning anvÀndas. Causal consistency garanterar inte hÄllbarhet. HÄllbarhet garanteras av replikering och den mekanism som Àr kopplad till replikering.

L: – NĂ€r vi skapar en instans som sköter vĂ„r sharding (inte master, utan slav), baseras den pĂ„ maskinens unix-tid eller pĂ„ "masterns" tid; synkroniseras den första gĂ„ngen eller periodiskt?

MT: – LĂ„t mig förtydliga. En shard (dvs. en horisontell partition) har alltid en Primary. I en shard kan det finnas en "master" och det kan finnas repliker. Men en shard stödjer alltid skrivningar, eftersom den mĂ„ste upprĂ€tthĂ„lla en viss domĂ€n (i sharden finns en Primary).

L: – SĂ„ allt beror helt och hĂ„llet pĂ„ "mastern"? AnvĂ€nds alltid "master-tid"?

MT: – Ja. Man kan bildligt sĂ€ga: klockorna tickar nĂ€r det görs en skrivning pĂ„ "mastern", i "OpLog".

L: – Vi har en kund som kopplar upp sig, och han behöver inte veta nĂ„got om tiden?

MT: – Absolut inget behöver han veta! Om vi pratar om hur detta fungerar pĂ„ klientsidan: för klienten, nĂ€r han vill anvĂ€nda Causal consistency, mĂ„ste han öppna en session. Just nu finns allt dĂ€r: bĂ„de transaktioner i sessionen och hĂ€mta rĂ€ttigheter
 En session Ă€r en ordning av logiska hĂ€ndelser som intrĂ€ffar med klienten.

Om han öppnar denna session och sÀger att han vill ha Causal consistency (om sessionen stödjer Causal consistency som standard), fungerar allt automatiskt. Drivrutinen kommer att komma ihÄg denna tid och öka den nÀr den fÄr ett nytt meddelande. Den kommer att komma ihÄg vilket svar som kom tillbaka frÄn servern, som Ätergav data. NÀsta begÀran kommer att innehÄlla afterCluster ("tid större Àn detta").

Kunden behöver inte veta nÄgot alls! Det Àr helt oklart för dem. Vad gör man om man anvÀnder dessa funktioner? För det första kan man sÀkert lÀsa frÄn sekundÀrer: man kan skriva till primÀr och lÀsa frÄn geografiskt replikerade sekundÀrer och vara sÀker pÄ att det fungerar. Dessutom kan sessioner som sparas pÄ primÀr överföras till sekundÀr, dvs. man kan anvÀnda mer Àn en session.

L: – Den nya delen av datavetenskap som Ă€r starkt kopplad till temat eventuella konsekvenser Ă€r datatyperna CRDT (Conflict-free Replicated Data Types). Har ni övervĂ€gt integrationen av dessa datatyper i databasen och vad kan ni sĂ€ga om det?

MT: – Bra frĂ„ga! CRDT Ă€r meningsfullt för konflikter vid skrivning: i MongoDB – en enda master.

L: – Jag har en frĂ„ga frĂ„n devops. I den verkliga vĂ€rlden finns det sĂ„dana jesuitiska situationer dĂ€r bysantinsk felaktighet intrĂ€ffar och illvilliga mĂ€nniskor inom den skyddade perimetern börjar manipulera protokollet, skickar specialtillverkade paket?

HighLoad++, Mikhail Tyulenev (MongoDB): Causal consistency: frÄn teori till praktik

MT: – Illvilliga mĂ€nniskor inom perimetern Ă€r som en trojansk hĂ€st! Illvilliga mĂ€nniskor inom perimetern kan göra mĂ„nga dĂ„liga saker.

L: – Det Ă€r uppenbart att lĂ€mna ett hĂ„l i servern, om man sĂ€ger sĂ„, genom vilket man kan föra in en djurpark med elefanter och permanent krossa hela klustret... Det kommer att ta tid för manuell Ă„terstĂ€llning... Det Ă€r, mildt uttryckt, fel. Å andra sidan Ă€r det intressant: förekommer det sĂ„dana situationer i verkliga livet, dĂ€r sĂ„dana interna attacker intrĂ€ffar?

MT: – Eftersom jag sĂ€llan stöter pĂ„ sĂ€kerhetsbrott i verkliga livet, kan jag inte sĂ€ga om de verkligen intrĂ€ffar. Men nĂ€r det gĂ€ller utvecklingsfilosofin sĂ„ anser vi sĂ„ hĂ€r: vi har en grĂ€ns som skyddar de som arbetar med sĂ€kerhet – det Ă€r lĂ„set, muren; och inom perimetern kan man göra vad man vill. Det Ă€r klart att det finns anvĂ€ndare med enbart utsiktsrĂ€ttigheter, och det finns anvĂ€ndare med rĂ€tten att radera kataloger.

Beroende pÄ rÀttigheterna kan den skada som anvÀndare kan orsaka vara som en mus, eller sÄ kan det vara en elefant. Det Àr klart att en anvÀndare med fulla rÀttigheter kan göra vad som helst. En anvÀndare med begrÀnsade rÀttigheter kan orsaka avsevÀrt mindre skada. I synnerhet kan han inte krossa systemet.

L: – In the secured perimeter, someone is trying to form unexpected protocols for the server, to bring the server down, and if they’re lucky, maybe even the entire cluster
 Is it ever that “good”?

MT: – I have never heard of such things. That it’s possible to take down a server this way is no secret. Taking it down from the inside, being an authorized user who can write something into the message
 In fact, it can’t be done, because it still must be verified. There is a way to disable this authentication for users who do not want it – that’s their problem; they’ve essentially built walls themselves and could stuff an elephant in there, which would trample
 Generally speaking, you can dress up as a repairman, come in, and pull it out!

L: – Thank you for the report. Sergey (Yandex). In Mongo, there is a constant that limits the number of voting members in the Replica Set, and this constant is equal to 7 (seven). Why is this a constant? Why isn’t this some kind of parameter?

MT: – We can have Replica Sets with up to 40 nodes. There is always a majority there. I don’t know which version


L: – In a Replica Set, you can run non-voting members, but voting members are limited to a maximum of 7. How do we deal with a shutdown in this case, if our Replica Set is distributed across 3 data centers? One data center can easily go down, and another machine might drop out.

MT: – That’s already a bit beyond the scope of the report. It’s a general question. Maybe I can talk about it later.

HighLoad++, Mikhail Tyulenev (MongoDB): Causal consistency: frÄn teori till praktik

Spela video

Lite reklam 🙂

Tack för att ni stannar kvar hos oss. Gillar ni vÄra artiklar? Vill ni se fler intressanta material? Stöd oss genom att göra en bestÀllning eller rekommendera oss till era vÀnner, moln-VPS för utvecklare frÄn $4,99, en unik motsvarighet till entry-level servrar som vi har skapat för er: Allt om VPS (KVM) E5-2697 v3 (6 Cores) 10GB DDR4 480GB SSD 1Gbps frÄn $19 eller hur man korrekt delar en server? (alternativ med RAID1 och RAID10 finns tillgÀngliga, upp till 24 kÀrnor och upp till 40GB DDR4).

Dell R730xd Ă€r tvĂ„ gĂ„nger billigare i datacentret Equinix Tier IV i Amsterdam? Bara hos oss 2 x Intel TetraDeca-Core Xeon 2x E5-2697v3 2.6GHz 14C 64GB DDR4 4x960GB SSD 1Gbps 100TB frĂ„n $199 i NederlĂ€nderna! Dell R420 — 2x E5-2430 2.2Ghz 6C 128GB DDR3 2x960GB SSD 1Gbps 100TB — frĂ„n $99! LĂ€s om Hur man bygger en företagsinfrastruktur med Dell R730xd E5-2650 v4-servrar som kostar 9000 euro för en brĂ„kdel?

KĂ€lla: habr.com

Köp pĂ„litlig webbhotell med DDoS-skydd, VPS VDS-servrar đŸ”„ Köp pĂ„litlig webbhotell med DDoS-skydd, VPS VDS-servrar | ProHoster