-
dva znana protokola: Paxos in Raft
- podobne lastnosti - odpornost na napake in zmogljivost
- Paxos
- Leslie Lamport, 1998
- zelo kompleksen, teoretičen in zelo splošen
- prevelik razkorak med opisom in potrebami realnega sistema; ker ni dovolj natančno opisan za dobro izvedbo, programerji dodajajo svoje (nepreverjene) rešitve
- bolj odziven v primeru, da so procesi porazdeljeni po vsem svetu
- Raft
- Ongaro, Ousterhout, 2014
- zasnovan zato, da je razumljiv
- algoritem ima manj stanj, enostavnejši mehanizmi za obvladovanje sistema
- veliko večino časa se sistem obnaša predvidljivo, v primeru težav (izpad procesa in podobno) mogoče traja malo dlje, da se znova vzpostavi
-
tipične napake: odpoved procesa, izguba sporočila, zamenjan vrstni red sporočil
-
model popolnoma urejenega razširjanja FIFO
-
algoritem predpostavlja obnovljive procese, sprejemljive izgube sporočil in delno sinhrono obnašanje
-
potrebujemo voditelja, ki naloge dodeljuje ostalim procesom
-
procesi se morajo uskladiti - morajo soglašati (angl. consensus) glede
- izbire voditelja in
- replikacije podatkov
-
dva končna avtomata
- vsak proces je končni avtomat: lahko je v enem od treh stanj: sledilec, kandidat, voditelj
- shramba je tudi končni avtomat: vhodi so operacije nad shrambo, shramba spremeni svoje stanje, ob zahtevi odjemalca nastavi ustrezen izhod
- algoritem raft skrbi za dnevnik zapisov
-
glavni elementi algoritma raft
- izbiranje voditelja
- volitve, izguba voditelja, volitve,
- replikacija dnevnika
- problem usklajevanja dnevnikov sledilcev z dnevnikom voditelja
- zagotavljanje odpornosti
- voditelj je lahko tisti, ki ima dober dnevnik
- izbiranje voditelja
-
čas v algoritmu raft se meri v poljubno dolgih volilnih obdobjih (angl. terms)
-
voditelj ostaja glavni dokler ne odstopi ali postane nedostopen; takrat ostali procesi, sledilci, izberejo novega
-
algoritem mora zagotavljati, da je v sistemu na enkrat največ en voditelj, ki lahko dopolnjuje dnevnik
-
dokler v sistemu ni voditelja, je sistem nedostopen; lahko si zapomni zahteve ki so prišle od odjemalcev, ali pa jih zavrne
-
vsak proces je končni avtomat v enem od treh stanj:
- sledilec, ki priznava nekoga drugega za voditelja
- kandidat, ki začenja volitve in sebe okliče za voditelja
- voditelj, ki sledilcem pošilja sporočila za dopolnitev dnevnika
-
dva tipa sporočil
- kandidat pošilja zahtevo za glasovanje (
voteRequest
) - voditelj pošilja zahteva za dopolnjevanje dnevnika (
appendEntry
)
- kandidat pošilja zahtevo za glasovanje (
- ob zagonu so vsi procesi v stanju sledilec
- sledilec
- pričakuje, da ga voditelj redno obvešča s sporočili za dopolnitev dnevnika ali s srčnim utripom
- privzame obdobje, ki mu ga sporoča voditelj
- dovoljen čas čakanja na sporočilo se po vsakem prejetem sporočilu nastavi na naključno vrednost
- če preteče dovoljen čas čakanja na sporočilo, sledilec sklepa, da voditelja ni več in postane kandidat
- kandidat
- začne novo obdobje, ki je označeno z za ena višjo zaporedno številko
- sebe predlaga za voditelja in glasuje zase
- ostalim procesom pošlje sporočilo naj glasujejo zanj (
voteRequest
)
- proces ostane kandidat dokler sam ali nekdo drug ne zmaga na volitvah
- kandidat zmaga na volitvah
- če večina procesov glasuje zanj
- vsak proces lahko v enem volilnem obdobju glasuje samo enkrat
- večinsko pravilo zagotavlja, da bo največ en kandidat zmagal na volitvah
- kandidat izgubi volitve
- če od drugega procesa (novega voditelja) dobi srčni utrip z enako ali višjo oznako obdobja
- sprejme novega voditelja in se vrne v stanje sledilca
- nimamo zmagovalca (manj kot 5 % primerov)
- več sledilcev se je hkrati spremenilo v kandidate in nihče ni dobil večine glasov
- po preteku dovoljenega časa čakanja na izid volitev kandidat začne novo volilno obdobje
- kandidat zmaga na volitvah
- začne novo obdobje, ki je označeno z za ena višjo zaporedno številko
- voditelj
- o svoji vlogi periodično obvešča ostale procese
- pošiljanje sporočil z zahtevo za dopolnitev dnevnika (
appendEntry
) - če zahtev ni, po preteku določenega časa pošlje srčni utrip (prazna zahteva za dopolnitev)
- pošiljanje sporočil z zahtevo za dopolnitev dnevnika (
- zahteva za dopolnitev med drugim vključuje oznako voditelja, številko obdobja, ko je bil izvoljen, in število zapisov v dnevniku
- o svoji vlogi periodično obvešča ostale procese
- program Raftscope
- pet procesov
- proces kandidat ima v notranjosti kroge, ki označujejo, kdo je glasoval zanj
- obrobljen proces je voditelj
- primer 1: izbiranje voditelja
- na začetku vsi sledilci
- eden postane kandidat (nepopolna debela siva obroba označuje dovoljen čas za izvedbo volitev)
- kandidat pošlje sporočilo
requestVote
(zelene barve) - sledilci prevzamejo obdobje
- sledilci glasujejo zanj (potrditev zelene barve, polne pike v kandidatu označujejo, kdo je glasoval zanj)
- ko je izglasovan, postane voditelj (debel črn rob)
- pošilja srčni utrip - prazen
appendEntry
(oranžne barve)
- primer 2: dva kandidata
- ponovno zaženemo aplikacijo (desni klik, Reload Page)
- zaustavimo simulacijo (tipka .)
- povečamo verjetnost, da bomo imeli dva kandidata hkrati (tipka A)
- nadaljujemo simulacijo (tipka .)
- eden zmaga
- primer 3: dva kandidata hkrati, volitve brez zmagovalca
- ponovno zaženemo aplikacijo (desni klik, Reload Page)
- zaustavimo simulacijo (tipka .)
- en proces ustavimo (desni klik nanj in stop)
- povečamo verjetnost, da bomo imeli dva kandidata hkrati (tipka A)
- nadaljujemo simulacijo (tipka .)
- lahko dobi en tri glasove, drugi enega ali pa oba dobita po dva glasova
- če dobi vsak dva glasova
- poskuša dobiti sporočilo od nedostopnega procesa s zahtevo po glasovanju
- lahko bi se oba kandidata pomenila, kdo bo postal voditelj, ampak algoritem raft v svoji enostavnosti tega ne podpira
- sistem čaka, da se izteče en od dovoljenih časov
- volitve za kandidata trajajo predolgo
- sledilec predolgo ne dobi sporočila od voditelja
- začne novo obdobje
- vsak proces v sistemu ima svojo shrambo
- voditelj je edini proces, ki lahko zahteva spreminjanje shrambe
- zahteve za spremembo shrambe zapisuje v svoj lokalni dnevnik
- dnevnik je urejen seznam zapisov
- vsak zapis vključuje
- deterministično operacijo nad shrambo (za replikacijo shrambe)
- oznako voditelja (da sledilci lahko usmerjajo odjemalce)
- številko trenutnega obdobja (za nadzor nad gradnjo dnevnika)
- številko zapisa v dnevniku (za nadzor nad gradnjo dnevnika)
- številko predhodnega obdobja in zapisa (za nadzor nad gradnjo dnevnika)
- lokalni dnevnik razširja na sledilce
- vsak sledilec gradi svoj dnevnik iz prejetih sporočil
- proces lahko zapise, ki so soglasno usklajeni med vsemi procesi, uporabi za posodobitev shrambe
- odjemalec pošlje voditelju zahtevo za operacijo nad shrambo
- voditelj pripravi dnevniški zapis, ki vključuje operacijo in kontrolne parametre (oznako voditelja, številko zapisa, številko obdobja)
- voditelj nato zapis razširi (pošlje) sledilcem
- voditelj lahko v potrjevanje pošlje nov zapis šele potem, ko je prejšnji potrjen
- če po preteku določenega časa ni novih operacij, voditelj pošlje prazen zapis (srčni utrip)
- sledilec zapis doda v svoj dnevnik in voditelju potrdi sprejem
- ko voditelj prejme dovolj potrditev (večina), privzame, da je zapis potrjen in operacijo iz zapisa izvede na svoji shrambi
- voditelj pošlje potrditev odjemalcem
- voditelj potrditev zapisa sporoči sledilcem ob razširjanju naslednjega zapisa ali srčnega utripa tako, s tem, ko poveča številko zapisa
- sledilec ob prejemu sporočila potrdi svoj zapis in izvede operacijo na svoji shrambi
- nov voditelj začne razširjati zapise šele potem, ko ima vse svoje zapise potrjene
- ob zmagi na volitvah v dnevnik doda zapis z operacijo nop (angl. no operation)
- ko je ta potrjena, začne razširjati ostale zapise
- algoritem zagotavlja, da je potrjen zapis trajen in ga bodo prej ali slej izvedli vsi procesi v skupini, ne le tisti ki so v trenutku potrditve zagotavljali večino
- tabela na desni strani
- v polja se vpisujejo zapisi; zapis je označen s številko obdobja, operacija ni prikazana
- puščica predstavlja kazalec
nextIndex
in prikazuje mesto v dnevniku, kamor želi voditelj sledilcu vpisati naslednji zapis - pika predstavlja kazalec
matchIndex
in prikazuje, do kje se sledilčevi zapisi ujemajo z voditeljevimi
- primer 1: osnovna replikacija
- vzpostavimo začetno stanje (desni klik, Reload Page in tipka L)
- voditelj in en sledilec
- odjemalec je dodal tri zahteve za vpis v shrambo
- zapisi niso potrjeni (črtkana obroba)
- podobno stanje lahko dosežemo tudi tako, da počakamo da procesi izberejo voditelja, nato tri procese ustavimo in kot odjemalec zahtevamo tri vpise v dnevnik (tipka C)
- zaženemo simulacijo (tipka .)
- voditelj zapise iz dnevnika pošlje sledilcem
- na sledilcu se kazalca
nextIndex
inmatchIndex
povečujeta
- zbudimo sledilca S3 (desni klik, resume)
- voditelj pošlje potrebne zapise sledilcu
- ko sledilec S3 potrdi prvi zapis, se obroba na voditelju spremeni v neprekinjeno (zapis potrjen)
- ob naslednjem pošiljanju zapisa je zapis potrjen tudi na vsakem sledilcu
- ko je zapis potrjen, bo obstal za vedno, proces lahko posodobi shrambo
- če je na voditelju mesto, kamor kaže kazalec
nextIndex
, prazno, bo voditelj pošiljal srčni utrip
- vzpostavimo začetno stanje (desni klik, Reload Page in tipka L)
- primer 2: dodajanje manjkajočih zapisov
- vzpostavimo začetno stanje (desni klik Reload Page in tipka L)
- dodamo sledilca S3 (desni klik, resume)
- počakamo, da vsi potrdijo zapise
- ko ni na poti nobenih sporočil, ustavimo simulacijo (tipka .)
- voditelju S1 dodamo dva nepotrjena zapisa (tipka C)
- ustavimo voditelja S1 (desni klik, stop)
- zbudimo sledilca S4 (desni klik, resume)
- nadaljujemo simulacijo (tipka .)
- najprej morajo izbrati voditelja: zmaga S2 ali S3, S4 ne more, ker nima dovolj sodobnega dnevnika
- vsi sledilci konzervativno nastavijo, da se njihovi zapisi ne ujemajo z voditeljevimi (
matchIndex
postavijo na nič, pika skoči na začetek) - po prvem sprejetem zapisu kazalec
matchIndex
kaže na mesto, do kjer so zapisi potrjeni - kazalec
nextIndex
se postavi na mesto, kjer novi voditelj pričakuje vnos - S4 zazna razliko med položajema obeh kazalcev, zato zavrne sporočilo
- voditelj zato pošlje prejšnje sporočilo
- ko se kazalca ujameta, voditelj manjkajoča sporočila pošlje sledilcu; lahko enega za drugim (simulacija) ali pa več hkrati (spodnja koda)
- primer 3: brisanje nepotrjenih zapisov
- nadaljevanje primera 2
- dodamo zapis (tipka C) in počakamo, da ga vsi potrdijo
- zbudimo S1 (desni klik, resume)
- S1 ima na položaju
nextIndex
napačen zapis - voditelj pošlje prejšnje sporočilo, spet se morata kazalca ujeti
- zapisi na voditelju so potrjeni, zato S1 svoje zapise zavrže in jih zamenja z voditeljevimi
- primer 4: kandidat ne dobi volitev
- vzpostavimo začetno stanje (tipka L)
- dvignemo procesa S3 in S4 (desni klik, resume)
- sprožimo simulacijo (tipka .)
- počakamo, da vsi delujoči procesi posodobijo dnevnik
- ustavimo voditelja S1 (desni klik, stop)
- dvignemo S5 (desni klik, resume)
- na S5 sprožimo volitve (desni klik na S5, timeout)
- S5 ima star dnevnik, zato ne dobi glasov od ostalih
- v ponovnih volitvah zmaga nek drug kandidat
-
ohranjanje voditeljstva
- če ne pošilja zapisov, pošilja srčne utripe (prazne zapise) in s tem sporoča svojo prisotnost
- dovoljeni časi čakanja na zapis so naključni, da se izognemo več kandidatom na volitvah
-
glasovanje
- če odpove voditelj, skupina izvoli novega
- ker je za potrditev zapisa dovolj večina, ni nujno, da so shrambe na vseh procesih do konca posodobljene
- kandidat ne sme zmagati na volitvah, če nima sodobnega dnevnika
- pri glasovanju proces ne more glasovati za kandidata, ki ima manj sodoben dnevnik kot sam
- primerjanje dnevnikov
- med procesoma primerjamo zadnja zapisa v dnevnikih: številko zapisa in številko obdobja
- če se razlikujeta številki obdobij, je novejši tisti, ki ima višjo številko
- če sta obdobji enaki, je dnevnik, v katerem je zapis z višjo številko, daljši in bolj posodobljen
- ker mora za kandidata glasovati večina, je njegov dnevnik vsaj tako sodoben kot dnevnik ostalih in torej vključuje vse potrjene zapise
- nič hudega, če izgubimo nepotrjene zapise, saj z njimi še nismo posodabljali shrambe
-
težave v omrežju lahko skupino razbijejo na dva dela
- dva voditelja v različnih obdobjih
- stari, ki se ne zaveda izgube sledilcev
- sporočila, ki jih pošilja stari voditelj, niso potrjena, dnevnik se ne nadgrajuje
- da ne širi lažnih informacij, mora voditelj ob vsaki bralni zahtevi preveriti, da ima večino
- novi, izvoljen z večino
- stari, ki se ne zaveda izgube sledilcev
- ko se omrežje spet vzpostavi, bo stari voditelj sestopil (če ne že prej), saj bo dobil sporočilo z višjo številko obdobja
- dva voditelja v različnih obdobjih
-
če voditelj ne uspe dostaviti zapisa (ne dobi potrditve), bo ponovno poskušal, dokler ne uspe
- če so operacije idempotentne, ni nič narobe, če isti zapis prispe dvakrat
-
ko sledilec pride nazaj v sistem
- od voditelja prejme sporočilo z novim zapisom
- če sledilec ne najde zapisa z istimi podatki, kot so za prejšnji zapis navedeni v sporočilu, sporočilo zavrne, da ne ustvari luknje v dnevniku
- voditelj zato sledilcu pošlje sporočilo s predhodnim zapisom
- postopek ponavljata, dokler številka obdobja in številka zapisa nista sprejemljiva za sledilca
- v primeru, da ima sledilec v dnevniku že nepotrjene zapise, novejše od točke ujemanja, jih pobriše in zamenja z zapisi, ki jih dobi od trenutnega voditelja
- zapise lahko prejema zaporedno ali v paketu, odvisno od izvedbe
-
sprememba zgradbe sistema
- sprememba števila procesov, ki predstavljajo večino
- procesi v sistemu se morajo uskladiti za spremembo zgradbe sistema
- dodajanje in odstranjevanje procesov mora iti preko mehanizma soglasja
- dodamo ukaze, ki se ne nanašajo na samo shrambo
-
velikost dnevnika
- ko ima dnevnik ogromno zapisov, bi posodabljanje shrambe iz nič trajalo zelo dolgo
- občasno je treba narediti varnostno sliko shrambe (angl. checkpoint, snapshot)
- potem lahko vse zapise v dnevniku, ki so bili s soglasjem potrjeni pred izdelavo varnostne slike, pobrišemo
-
komunikacija z odjemalci
- odjemalec komunicira z voditeljem
- če voditelj ni znan ali se je spremenil, ga mora vsak proces v sistemu znati preusmeriti na voditelja
- ponovno pošiljanje sporočil v primeru težav (lahko drugemu voditelju!)
- razreševanje problema podvojenih zapisov (odjemalec vsa svoja sporočila označuje)
- podatkovni bazi CockroachDB in MongoDB uporabljata algoritem raft na replikacijski plasti
- posrednik sporočil RabbitMQ uporablja algoritem raft za replikacijo vrst FIFO
- Paxos: multi-paxos, cheap paxos, fast paxos, generalised paxos
- Practical Byzantine Fault Tolerance algorithm (PBFT)
- Proof-of-Stake algorithm (PoS)
- Delegated Proof-of-Stake algorithm (DPoS)
- pri verižni replikaciji moramo pri pisalnih zahtevah po verigi do repa in nazaj; to je počasneje kot pri replikaciji z voditeljem, kjer je dovolj, da zahtevo potrdi večina procesov
- pri verižni replikaciji je rep usklajen z vsemi procesi, zato na bralno zahtevo lahko odjemalcu nemudoma odgovori; pri replikaciji z voditeljem mora proces z ostalimi preveriti, če je še voditelj; verižna replikacija je v tem elementu bistveno bolj odzivna
- če med obdelavo zahteve odpove eden od procesov, mora nadzorna ravnina odpoved najprej zaznati in nato spremeniti verigo; pri replikaciji z voditeljem odpoved enega procesa ne vpliva na obdelavo zahteve