Multi-Paxos Raft
前言
分佈式一致性算法中鼎鼎有名的Paxos算法,有以下的特點
1、理論上證明了是可靠的
2、但是這個證明,這個原理,是真他喵的難懂😂
3、就算真懂了也很難真正實現
4、有live lock的問題
於是人們實在被搞的煩死了,又發明了另一種Multi-Paxos算法:Raft
Raft,相對於Paxos,特點是:
1、沒有理論證明是可靠的
2、容易理解
3、容易實現
4、實踐見真知
先看動畫學個大概
http://thesecretlivesofdata.com/raft/
看懂了大概流程之後,我們可以在這裏面玩一下各種情況下最終怎麼保持一致性的:
玩完之後我們來帶着一些問題看細節:
當有一個機器掛掉了,落後了好多進度,應該怎麼通過這個協議追上來呢?
說明 | 總覽圖 | leader視角 | follower視角 | 數據包 |
先模擬這個進度落後的情況: 好端端的突然S4掉線了 |
由於S4掛了,leader拿不到信息了,上次記着他的match index=2,next index = 3 |
而我們掛掉的S4保存的信息是:commitIndex=2 |
leader給S4發的請求AppendEntries。prevIndex=2, commitIndex=3,entries=[2]
S4知道自己commitIndex=2,然後S1想讓S4commitIndex=3,大概意思就是想讓S4把3這個entry給填成【2】 |
|
然後我們把S4重啓 【bring yourself back online 😂】,接收一個來自S1的請求之後 |
然後S1收到了S4的返回,知道S4填好了,就把本地的表給改成S4的match index=3 |
|||
如無意外,這麼搞下去很快S4就會追上進度了。那就來點意外吧😂讓leader掛掉,咱們換個任期。 |
||||
其他人都收不到leader心跳了,會重新選一個leader |
S2作爲candidate請求大家給自己投票 | |||
隨後S5也想當leader |
S2想當leader,S3 S4同意,S5不同意 但是已經獲得大多數,S2還是成爲了leader;而S5無法獲得多數,競選失敗。 這個過程中,各個節點如果認可新leader,應該會把自己的log信息彙報給新leader,新leader更新自己的peers表。 |
|
||
在這個戰亂的時刻,我們來關注一下進度跟不上的S4, |
somehow S4的matchindex歸爲0了 |
|||
然後S4需要向leader彙報自己的進度,最終也就跟上來了 |
我們再簡化一下,只有3個機器
說明&總覽 | S1 | S2 | S3 |
S3經過投票成爲leader,然後接受了2個寫請求並同步完成 | follower | follower | leader |
讓S1掛掉,S3接受2寫請求,S1落後進度,這時候S3發4個請求出去,只有1個回,達不到過半數,數據處於半提交狀態。 |
掛掉 | follower |
leader |
讓S1重新上線,慢慢就恢復了一致性 |
follower | follower | leader |
所以這個協議是怎麼保證最終的一致性呢,落後進度的情況下,有些節點掛掉的情況下,再重啓,怎麼就會好了呢?這些都要通過原理來解釋
然後參考下面視頻看看原理
https://www.bilibili.com/video/BV1wt411y7Da/?spm_id_from=333.788.videocard.0
1、客戶端給server發送command
2、server使用paxos協議,選擇command
3、server等待前一個log entries被applied,然後apply一個新的command到狀態機
4、server狀態機的結果給客戶端。
解答以下問題:
來了一個客戶端請求,要用哪個log entry?
性能優化:
- 選個leader來減少proposer 衝突
- 消除大量的Prepare 請求
保證全部複製好
客戶端協議
配置改變
注:這個算法其實沒有得到嚴格的證明,說不定有bug。哈哈哈哈
當客戶端的請求到達的時候:
- 找到第一個還沒被chosen的logEntry
- 運行basic paxos,propose 客戶端的command
- prepare請求返回了acceptedValue?
- yes:選擇acceptedValue,重新開始
- no:選擇客戶端的command
如上圖,先假設server3掉線了,client command=jmp,發到了server1;
server1找到最小的not chosen index = 3,運行paxos,prepare請求,發現server1已經acceptedValue=cmp,那就接受index=3:cmp,然後重新開始
server1找到最小的not chosen index = 4,運行paxos,prepare請求,發現server2已經acceptedValue=sub,那就接受index=4:sub,然後重新開始
server1找到最小的not chosen index = 5,運行paxos,prepare請求,沒發現acceptedValue,終於可以使用client的command。index=5:jmp
選leader:
有最大的id的人當leader
每Tms 每個server發送心跳給其他server
如果一個server在過去的2Tms 沒有收到其他server更高的id,他就成爲了leader:
- 可以接受客戶端的請求
- 扮演proposer和Acceptor
如果server不是leader
- 拒絕客戶端請求,轉發給leader
- 只能當Acceptor
消除Prepares
爲什麼需要prepare?
- 用來block掉老的proposal
- 讓proposal number代表整個log,而不是一個entry
有點難懂,未完待續。。。。。。。