raft協議應用方面的疑問?

對於raft協議有幾個疑問:

1、當一個 follower 經過一個 heartbeat 沒有收到包,就會認為 leader down 掉了,就會開始新的一輪選舉。如果集群個數很多的話(比如上千個機器),難免就會有機器延遲很高,那豈不是很容易就會造成重新選主?

2、客戶端的操作每次提交到 leader 都會發往集群中所有的機器,會不會造成網路帶寬佔用過高?

3、如果集群中沒有發生分區,而只是部分不連通。比如說5個機器的集群,A、B兩台機器互相無法連接,而與其他機器都可連通。在這種情況下,如果A為 leader ,B收不到心跳包就會選主成為 leader,這時A又收不到B的回復,就會有兩個 leader存在了。

4、接上面,這個情況下也有一個問題,假如3個節點組成的Raft Group,如果一個Client提交一次數據變動,這個時候 Leader收到了這個數據請求後。把這個數據請求記錄到Log裡面。但是這個時候另外2個機子都處於宕機階段,所以Leader沒有辦法獲得半數以上的機器同意。所以Client就一直收不到數據設置Success的通知。時間一長,比如到了Client的超時機制超時後,Client可能認為數據提交超時了或者失敗了。但是這個時候人工修復了另外Group的2個節點,Raft Group重新同步日誌,這個時候剛剛提交的那次Log被同步到所有的節點並應用上去。其實這次數據設置還是成功,但是Client以為沒有成功,邏輯肯定有問題啊!(同樣是Raft的問題,借題主的寶地提問一下)

希望大神能幫忙回答一下我的疑問,非常感謝!


1. 這個心跳超時時間不要設的太小,否則稍微一卡,就容易重新選主。
2. 並不會發往所有的機器,leader 只會發往本 raft group follower 所在機器。當然,你要實現儘快的複製,那麼集群節點之間的帶寬還是要有一定的保證的。
3. 通過 leader lease 可以解決腦裂問題,TiKV 已經實現了,可以參考:PingCAP


謝邀。

這四個問題里,看了其他答案1~3都沒啥可說的,第四個問題值得回答一下。

第四個問題這種情況確實是存在的,所以一般,返回給客戶端的狀態一般只有兩種:一種是success,一種是unknown,即未決。這樣的話,最後其他機器起來後,對那些日誌是否達成一致apply到上層狀態機都是可以接收的。題主關於Raft這個問題,A,B,C,如果A日誌最多,最後A的日誌肯定會同步多數派。如果換成MultiPaxos的場景,B和C有可能是主,這樣的話A的多餘的日誌有可能不會在paxos第一階段選出來,從而不會達成一致。


第一個和第二個沒什麼可說的,其他答案都說的比較清楚了。

第三個問題,AB兩個節點互相不同,如果A為leader,B沒有收到A的心跳,從follower變成candidate,這個是可能的。但是,CDE不會給B投票,因為B的&都小於CDE的節點,至於 &是什麼含義,要好好看看論文。簡而言之,要成為leader,需要有最新最全的redo log。

第四個問題,你提到了「人工修復」,人工是不能隨意修復的啊,親!即便修復的話,也要遵照raft協議,以一種「正確的方式」來修複數據。什麼是「正確的方式」?就是把每個節點需要持久的值(index_id, term_id,vote_ack)這些都設置正確了,這個本身就是非常難的,所以,在raft集群裡面,是不建議「人工修復」的,人工干預限制於,關掉或者重啟集群。如果在你舉的這個case裡面,真的要人工修復的話,要做兩件事情:1把日誌補充到B和C中去,2要把BC中log的term_id改大。如此做,之後重啟集群,A是不會被選成leader的。

吳鏑 @吳鏑 提到multi-paxos的解法,multi-paxos的「leader」可以是任何節點,甚至可以是日誌最少最舊的節點,但multi-paxos也是有「prepare」階段的。 prepare階段,會取回其他節點的accept記錄(包括A上的多餘日誌),這個記錄(也就是日誌)會採用更大的proposal_id重新發給所有節點(包括leader本身),這樣,也不會出現不一致。


類paxos協議的操作都是發生在組成paxos group的參與者之間,跟集群裡面有多少台機器沒有直接關係。集群裡面的機器多,會影響網路通信,這就要求paxos裡面的心跳保持操作要足夠健壯。同時你還可以想一個問題,如果心跳是通的,但是這個leader 壓力大或者工作線程hang不能提供服務怎麼辦?

關於第三個問題,paxos規定每一條請求都要經過多數派決議,通過了才能發響應給客戶端。注意是每一條請求,這跟傳統主備裡面主先做然後批量應用到備是不同的。此時,如果5個參與者,2個3個分為兩區,那麼2個的區是不可能形成多數派決議的,所以任何請求都完成不了,也就不存在充當leader的問題。

我之前學習時候曾經做過筆記,見 使用Paxos前的八大問題 - 知乎專欄


3. 補充: B開始新一輪選舉的時候term會增加,成為leader後更新其他三個follower的term。A在發heartbeat給其餘三個follower的時候會發現自己的term已經落後,這個時候A就不再是leader。

4. Raft group內部會設計一個請求的去重,比如client發送請求的時候可以帶上一個請求的tag。client前一次請求超時後選擇重新發送(用相同的tag來標明這還是上一個請求),這時候raft leader發現這是同一個請求,不會重複記錄這條log而直接返回Success。參考:https://thesquareplanet.com/blog/students-guide-to-raft/


1 和 2 算是一個問題吧 一般一個 raft group 選5個 就可以了 這5個之間用 raft 協議 簡單的 打個比方 一共 1000台機器 5個是 raft group 然後 可以在 剩下995裡面 選個 master 這個 master 更新什麼文件 存在 哪個server里(同樣的block 也最少 存3個 不同的 server 中)然後 這些對應關係 之類的meta data 是通過 raft group 處理記錄的 如果 client 有其它請求 雖然最開始要 找master 但master 會在根據工作量 等找個 primary(可以理解為 再次一級的 master) 來處理 請求 這樣 workload 就分散開了

核心meta data 和master 選擇這類有 raft group 來處理 而文件讀取 和 上傳 基本是選的 master 和 primary 來處理

這是個 簡單的例子 只是說明 1和2 提到的關於 raft group的 過多請求是不會發生 的 然後上面的 例子還有很多其它 問題比如 master 掛了什麼的 請 其參考chubby gfs 和bigtable 上面基本 按gfs 簡單說的

3 關於這個問題 樓主可以 著重讀下 幾個rpc 那一頁 之前a是leader 那麼會有一個 term 如果在這之後 b 當上了leader 說明 有一半以上的 成員term 比a 的term 大(比如5個 裡面 有3個) 那a 發rpc 這3個是 不會理的 而且 a 收到的 ack 發現有 比自己term 大的 也會放棄 繼續當leader 即使沒 收到 這樣的 ack a沒有等到一半以上的 回復自己的 log 等於是不會 繼續更新的 也就是個 無效的 leader 通常leader 也會有timeout 發現 沒有足夠的follower 回應也會 放棄leader

4 這個可以簡單 的理解為 client servet的 行為 client 那邊 超時可以 放棄操作 也可以repeat 發送請求 主要應該是問 repeat後可能的 情況(這裡先 假設一個簡單的 數據流 關係 client - server - raft group)第一次 client 給server 發請求 server 會記錄一些 信息比如那個client 什麼請求之類 然後update 給 raft group 如果 raft group 沒能及時達成一致 可以理解 server 就沒有等到回復 就沒有進一步 處理 那麼這時client 超時了(4中的例子) 然後 client repeat 發送請求 server 發現了這個 可能會繼續給raft group update 也可能 不理睬 (不理睬 應該會記錄操作 因為 一直沒從raft 那有回復 自己可能 周期再向raft update)這期間 raft 如果恢復了 其實無論 之前有沒有 更新成功 其實無所謂 因為在server 處這操作一直 沒有成功 server 就沒有進一步的 處理 如果在server處 看來成功了後 就不會重複操作 之後收到client 的repeat 請求就會當處理過 正常 回復

這裡 可以想想 如果 server 掛了 有沒有關係 :)


四這個問題無解,基本上大家默認的處理方式就是除非server明確告你成功或者失敗,否則不管成功還是失敗都可以接受。

注意超時就是典型的server沒告你成功還是失敗。你說的這個情況,可能不apply更好,但有更簡單的情況,就是server在收到你的請求之後,你和server之間的網斷了。。。


1

Raft的論文的5.6節裡面有一個式子:

broadcastTime &<&< electionTimeout &<&< MTBF

  • broadcastTime是leader發送心跳到所有follower後收到響應的時間。

  • 當follower超過electionTimeout的時間都沒有收到leader的心跳,則轉換成candidate並發起選舉。

  • MTBF,即發生兩次故障的時間間隔。

根據論文,broadcastTime大約是0.5~20ms,實際情況取決於日誌存儲的實現,electionTimeout大約是10~500ms。所以,只要合理設置electionTimeout的大小,並不會出現一個心跳收不到就發起新的一輪選舉的情況。

2

需要通信的機器數量應該等於數據的副本數,如果你的數據有5個副本,這5個副本組成一個raft group,之間才需要相互通信。

3

在Raft論文的5.4.1節 Election restriction裡面提到重新選舉leader時的一個限制:

Raft uses the voting process to prevent a candidate from winning an election unless its log contains all committed entries.

根據問題,假設A為leader,一開始A和B的日誌保持同步。某一時刻,A和B之間無法連通,但是A和C、D、E可以正常連通,B和C、D、E可以正常連通。

如果在B超時發起選舉之前,有寫操作通過A,寫成功,此時C、D、E中一定至少有兩個的日誌比B新(因為至少要有兩個follower寫成功)。之後B超時發起選舉,由於上面提到的限制,B不會被選舉為新leader。

如果在B超時發起選舉之前,沒有寫請求,則B會成為新的leader,之後A通過C、D、E發現自己的term落後了而轉換為follower。

之後的情況就和上面類似了。

4

根據我的理解,3個節點掛了2個,超過半數了。這個raft group應該不能正常工作了,寫操作應該都是失敗的。


1. 正常設置,follower任何原因錯過單獨一個heartbeat不應認為leader是當了。連續錯過多個才應認為leader出問題了。解決你提出的問題的一個辦法是PreVote,你說的那個機器延遲大,如果正好也造成同步慢,那麼PreVote決定它可以開始嘗試問詢是否有成為leader可能,但卻無機會開始選舉無端挑戰當前leader

2. 工程做法是把不同leader分布到不同機器上,避免過於集中,也就是leadership transfer功能。CS的做法是改進協議,各衍生協議上,leader這個bottlenck的消息數對比看下文表1

https://www.usenix.org/system/files/conference/osdi16/osdi16-li.pdf

3. CheckQuorum可以讓cluster較快速度穩定下來,短期有雙主不是問題。其實,這個問題本質是不存在的,因為A和B按照描述是可經由第三方通訊。顯然的,在非同步網路假設下,任何包都允許經由第三節點轉發,A和B實質是聯通的。

4. 應用邏輯無問題,client超時以後,client得到的確認是unknown,此時用強一致讀看一次,如果BC恢復了且工作,能確定地判斷數據變動是否被應用了。Raft里,A會存這個entry,BC啟動後會得到這個entry,完成複製。


超時選舉時間不一定要等於心跳時間,只要大於心跳時間就行。

第三個問題raft已經考慮到了,兩個leader其中必有一個是只讀的,舊term一旦收到新leader的消息就會解散。


關於第三個問題:

Raft不保證任何時刻最多只有一個節點認為自己是leader,只保證任何時刻最多只有一個leader能成功提交提案。

腦裂情況下, 少數派的主是沒有辦法達成提案的。


第四點不應該由raft來保證。類似地,日誌提交應用成功了,但是給客戶端回復成功時網路異常了,也一樣的。這種情況可以通過把操作冪等化來解決(比如同一個操作有相同的事物id),客戶端沒收到成功,重試就行了。


第一個問題需要補充的是:參與選主的節點是幾個核心節點,當etcd集群節點數多於核心節點上限時,新增節點是以proxy方式接入的,不會參與選主,所以參與投票的節點是有上限的。


除非是大部分都接收不到心跳,否則只有小部分接收不到心跳是選舉不成功的啊.


推薦閱讀:

TAG:分散式系統 | 分散式一致性 |