DDIA 對 Raft 的這種極端場景的描述,要如何理解?
本文選自我在知乎的回答。
《設(shè)計數(shù)據(jù)密集型應(yīng)用》(即 DDIA)中提到 Raft 的一個問題,即,Raft 算法存在一種失去活性(liveness)的極端情況:如果有一條網(wǎng)絡(luò)連接不可靠,Raft 當(dāng)前領(lǐng)導(dǎo)者會不斷被迫下臺導(dǎo)致系統(tǒng)實質(zhì)上毫無進(jìn)展。
我們先來具體描述一下該問題。
如圖所示的 4 節(jié)點 Raft 集群,其中有一個節(jié)點和其他三個網(wǎng)絡(luò)不太穩(wěn)定,假設(shè)它能發(fā)送消息給別的節(jié)點但收不到其他節(jié)點的消息,那么它就會一直收不到心跳消息,然后轉(zhuǎn)為 candidate 自增任期并發(fā)起新的選舉,來自更大任期的 RequestVote 請求會導(dǎo)致現(xiàn)在的 Leader 下臺重新選舉。這樣一直反復(fù),會導(dǎo)致集群無法正常工作。
Raft 大論文提到一種解決方式是加入一個新的 PreVote 階段,etcd 就這么干了,為此增加了一種新的節(jié)點狀態(tài)叫做 PreCandidate 狀態(tài)。
PreVote 階段作用是當(dāng)一個節(jié)點想要發(fā)起選舉時,首先要確認(rèn)自己確實有資格贏得投票而不是在浪費時間,才會真的自增任期發(fā)起新的選舉。
PreVote 階段的具體流程是,在發(fā)起真正的選舉之前,先發(fā)送 PreVote 消息給所有節(jié)點, PreVote消息和 RequestVote 消息一樣,但節(jié)點不會自增自己的任期,只會增加消息中的 term 參數(shù)。
收到 PreVote 消息的節(jié)點同意重新選舉的條件是:
參數(shù)中的任期更大,或者任期相同但 log index 更大;
至少一次 election timeout 時間內(nèi)沒有收到領(lǐng)導(dǎo)者心跳;
只有超過半數(shù)節(jié)點同意 PreVote 消息,該節(jié)點才能真正去自增任期并發(fā)起新的選舉。
回到上述情況,網(wǎng)絡(luò)鏈路有問題的那個節(jié)點在 PreVote 階段會發(fā)現(xiàn)自己無法贏得超過半數(shù)節(jié)點同意自己發(fā)起選舉(別的節(jié)點都能收到心跳),因此不會自增任期去干擾 Leader 工作。
問題解決了嗎?
問題并沒有解決,只有 PreVote 階段還可能有一種極端情況會導(dǎo)致 Raft 失去活性。如圖所示:
圖中是一個 5 節(jié)點組成的 Raft 集群,故障發(fā)生之前 4 是 Leader?,F(xiàn)在故障發(fā)生了,5 宕機(jī)了,同時 4 只和 2 保持連接,1、2、3互相保持連接。這種情況下 1、3 收不到 Leader 的心跳,會發(fā)起 PreVote請求,但由于 2 能收到 Leader 節(jié)點 4 的心跳,所以 2 不會同意 PreVote 請求,因此節(jié)點 1、3 無法獲得多數(shù)派的 PreVote 同意。
該集群的問題是,無法選舉出新的 Leader,但舊的 Leader 又只能 AppendEntries 到兩個節(jié)點(2和自己),無法達(dá)成多數(shù)派,整個集群無法取得任何進(jìn)展,不滿足活性。
此處 Raft 協(xié)議明明可以容忍 2 個節(jié)點故障,但增加了 PreVote 階段后反而無法容忍僅僅 1 個節(jié)點故障,其實沒有 PreVote 階段的話,1 和 3 是有機(jī)會當(dāng)選 Leader 推進(jìn)整個系統(tǒng)正常工作的。
因此 Raft 還需要增加一種機(jī)制來讓 Leader 主動下臺。
這個機(jī)制很簡單:Leader 沒有收到來自多數(shù)派節(jié)點的 AppendEntries 響應(yīng)時就主動下臺。這樣,圖中 1、2 和 3 都有機(jī)會當(dāng)選新的 Leader,整個集群依舊可以正常工作。
etcd 把這叫做 CheckQuorum,etcd 的 issue 中有關(guān)于此問題的討論:https://github.com/etcd-io/etcd/issues/3866
CheckQuorum 確保了如果當(dāng)前 Leader 無法連接到多數(shù)派節(jié)點,它將會下臺并選舉出新的 Leader。PreVote 確保一旦 Leader 當(dāng)選,整個系統(tǒng)將是穩(wěn)定的,Leader 不會被迫下臺。
那么 PreVote + CheckQuorum 可以解決活性問題了嗎?
可以了!