在B站上一個講這三個算法的視頻網址https://www.bilibili.com/video/av21667358
Paxos協議
Basic paxos算法中,分爲4種角色:
- Client: 系統外部角色,產生議題者,像民衆
- Proposer :接收議題請求,像集羣提出議題(propose),並在衝突發生時,起到衝突調節的作用,像議員
- Acceptor:提議的投票者和決策者,只有在形成法定人數(一般是majority多數派)時,提議纔會被最終接受,像國會
- Learner:最終提議的接收者,backup,對集羣的已執行沒有什麼影響,像記錄員
Paxos有三種實現版本
- Basic Paxos版本
- Multi Paxos版本
- Fast Paxos版本
兩個階段
Prepare階段
- Proposer 生成提案編號 Mn, 向Quorum 廣播該編號。
- Acceptor 收到Prepare Mn 之後
- 如果比已接受提案編號大,則接受Mn, 並承諾不再接受小於Mn 的提案,將已接收的編號最大提案通過返回ACK 給Proposer。
- 否則忽略Prepare Mn
- Proposer 收到Quorum 數量的ACK 之後,則進入提交階段。否則重新開始Prepare 階段。
Accept階段
- Proposer 選取ACK 中編號最大的提案的Value 作爲Vn, 向Quorum 廣播 Accept [Mn, Vn]。
- Acceptor 收到Accept [Mn, Vn] 之後
- 若提案不違背承諾,則接受該提案,並返回ACK
- 否則忽略
Basic Paxos版本
該版本是最基本的版本,由多個proposer和多個acceptor組成
該版本的問題是,
- 一個完整的事務,需要兩次RPC遠程調用,分別是Prepare階段和Accpet階段。效率不高
- 因爲是多個proposer可以都提交提案,因此會出現活鎖問題,Proposer1提出了M1的提案,並完成的Prepare階段。與此同時,Proposer2提出了一個新的提案M2(M2>M1),同樣也完成了Prepare階段,於是Acceptor承諾不再批准編號小於M2的提案。當P1進入Accept階段時,其發出的Accept請求將被Acceptor忽略。於是Proposer1再次進入Prepare階段並提出一個編號爲M3(M3>M2)的提案,而這又會讓Proposer2的M2在第二階段的Accept請求被忽略,如此陷入死循環。
Multi Paxos版本
該版本只有一個Leader Proposer,只有Leader Proposer可以提出提案,Leader Proposer通過選舉產生。
選舉一個Leader Proposer的時候,需要進行投標,當一個Leader選舉出來之後,該Leader發出的提案就可以直接進入Accpet階段。
Raft協議
raft 簡化版的Multi Paxos,劃分了三個子問題
- Leader Electtion
- Log Replication
- Safety
重定義了三個角色
- eader
- Fllower
- Candidate
這個解釋的非常明白
原理動畫解釋:https://http://thesecretlivesofdata.com/raft/
這個是怎樣選舉的leader,某個節點宕機了怎麼解決的詳細動畫演示
場景測試:http://raft.github.io
ZAB協議
基本與Raft相同,在一些名詞叫起來是有區別的
ZAB將Leader的一個生命週期叫做epoch,而Raft稱之爲term
實現上也有些許不同,如raft保證日誌的連續性,心跳是Leader向Follower發送,而ZAB方向與之相反
術語說明:
ZXID:高32位是epoch,表示Leader週期,單調遞增;低32位,Leader產生一個新的事務proposer時,該計數器會加1(在一個Leader週期裏是單調遞增,epoch變更後從0開始)
SID:服務器ID,用來唯一標識一臺ZooKeeper集羣中的服務器,每臺機器不能重複,和myid的值一致。
vote_sid:接收到的投票信息中所推舉的Leader服務器的SID
vote_zxid:接收到的投票信息中所推舉的Leader服務器的ZXID
self_sid:當前服務器自己的SID
self_zxid:當前服務器自己的ZXID
electionEpoch:當前服務器的選舉輪次。
Leader選舉
1.變更狀態:如果是運行過程中Leader掛了,則會有這一步,非Observer服務器會將自己的服務器狀態變更爲LOOKING(尋找Leader狀態),然後進入Leader選舉流程
2.每個Server會發出一個投票 vote[self_id,self_zxid]
3.接收來自各個Server的投票 vote[vote_sid,vote_zxid]
4.處理投票
-
先比較ZXID,ZXID比較大的服務器優先作爲Leader
如果vote_zxid > self_zxid,就認可收到的投票,並再次將該投票發送出去
如果vote_zxid < self_zxid,就堅持自己的投票,不做任何變更
-
如果ZXID相同的話,那麼比較myid,myid比較大的服務器作爲Leader服務器。
如果vote_sid > self_sid,就認可收到的投票,並再次將該投票發送出去
如果vote_sid < self_sid,那麼就堅持自己的投票,不做任何變更
5.統計投票:判斷是否已經有過半的機器Quorum接收到相同的投票信息,如果存在一個服務器得到過半的票數,那麼得到過半票數的機器作爲Leader,終止投票。否則進入步驟3,進入到新一輪的投票選舉中。
6.改變服務器狀態:確定Leader後,每個服務器會更新自己的狀態,如果是Follower,那麼就變更爲FOLLOWING(跟隨者狀態),如果是Leader,那麼就變更爲LEADING(領導者狀態)
注意:選舉出一個leader後,服務器不會馬上更新狀態,而是會等待一段時間(默認是200毫秒)來確定是否有新的更優的投票。
Leader同步
由於上述選舉過程保證了 Leader 必然擁有最大zxid, Leader 只需要向Follower 同步自己的歷史提案即可。
- 若Follower 擁有 Leader 沒有的提案,則 truncat掉。
- 若Follower的epoch = 當前leader的epoch,落後則根據log, reply 歷史transcation
- 若落後太多,則直接同步 snapshot,再replay transaction log.