背景
什么是配置變更踩官?
說白了,就是動態(tài)增減服務器境输。
假設蔗牡,一個 Raft 服務器集群的數量剛開始是 3 臺,過了 2 個月嗅剖,由于要搞類似 618辩越,雙11 大促,領導要增加系統(tǒng)可用性信粮,那么就要增加到 5 臺黔攒。
如果增加到 5 臺,就帶來了配置的變化强缘,首當其沖的督惰,就是 “服務器數量” 這個配置的變化,例如這個配置叫做 “server_count = 3”旅掂, 你需要將配置改成 “server_count = 5”赏胚。同時,每臺服務器還需要知道其他 4 臺服務器的 ip + port商虐,這個配置實際上也是需要變化的觉阅。
并且崖疤,你需要在不停機的情況下,將新的 2 臺服務器增加典勇,并且將這些配置應用到另外 3 臺舊的服務器上劫哼。
這個時候,你該怎么做割笙?
假設是我沦偎,我會先將新的 2 臺服務器配置完畢(新的配置)再啟動。然后咳蔚,將新的配置發(fā)送到舊的 3 臺服務器。那 3 臺服務器如果成功收到并提交了這個配置搔驼,使這個配置生效谈火,那么整個集群的狀態(tài)就一致了。
很完美舌涨。
但是糯耍,分布式肯定沒有這么簡單。假設囊嘉,在成功啟動 2 臺新服務器后温技,老的集群發(fā)生了故障,重新開始選舉扭粱,這個時候舵鳞,是怎么樣子的?
看下圖:
上圖中琢蛤,一共有 5 臺服務器蜓堕,S1,S2博其,S3 代表舊的服務器套才,S4,S5 代表著新的服務器慕淡。
綠色代表舊的配置背伴,藍色代表新的配置。
我們模擬一下:
- 我們先啟動了 S4 和 S5峰髓,成功啟動傻寂。
- 然后我們將新的配置發(fā)送到 S1,S2儿普,S3 中崎逃,試圖讓他們應用新的配置。
- 在某個時刻眉孩,S3 成功應用新的配置个绍,同時勒葱,舊的系統(tǒng)發(fā)生了故障,并開始選舉巴柿。
- 5 臺服務器一起開始選舉凛虽,由于 S1 和 S2 還沒有應用新的配置,所以广恢,S1 和 S2 仍然以為只有 3 臺服務器凯旋,并且在得到 2 張選票后,成功選出一個領導者钉迷;
- 而 S3至非,S4,S5 應用了新的配置糠聪,并且獲得 3 臺服務器的認可荒椭,也成功選出了領導人。
- 此時舰蟆,整個系統(tǒng)出現了 2 個領導人趣惠。
那么,是哪里出現了問題呢身害?
根本原因在于味悄,在同一時刻,有 2 份配置生效了!!!
自然就可以選出 2 個領導人塌鸯。
所以侍瑟,要防止這個問題發(fā)生,必須不能讓 2 份配置同時生效界赔。
Raft 的實現
Raft 是怎么做的呢丢习?
Raft 使用了一種 2 階段提交的方案。
具體見下圖:
第一階段:
- 發(fā)送新配置到舊服務器的 leader淮悼。leader 不會直接存儲
新配置
咐低,而是存儲舊配置 + 新配置
。同時袜腥,一旦這個配置被提交(成功同步到新舊集群的大部分跟隨者中)见擦,那么,所有服務器必須用這個配置來做決定羹令。也就是說鲤屡,舊配置失效了,不能拿舊配置做任何決定福侈,同時酒来,此時的系統(tǒng)狀態(tài)是一致的。這個狀態(tài)稱之為共同一致肪凛。
第二階段:
- 當
舊配置 + 新配置
被成功提交堰汉,這個時候辽社,leader 會創(chuàng)建一條新配置
復制到 followers 中。從而完成配置變更翘鸭。
從上圖和上文的解釋可以看出滴铅,這里不會出現新配置
和 舊配置
同時出現的場景。因為他們都被融合在了 舊配置 + 新配置
中去了就乓。即將兩個配置融合成一個配置汉匙。
那么,圖 1 的問題——同時有 2 個 leader 的問題就解決了生蚁。
思考:共同一致能確保沒有問題嗎噩翠?
簡化起見,我將 新配置 + 舊配置
稱之為 共同配置
邦投。
為了閱讀方便绎秒,我將 舊配置
稱之為 old 配置
,將新配置
稱之為 new 配置
從圖 2 可以看出尼摹,一共有 2 個關鍵的節(jié)點:
- 提交 “共同配置”
- 提交“new 配置”
如果這個兩個地方出現問題了,怎么辦剂娄?
假設: 共同配置
提交失敗蠢涝,會怎么樣?例如提交的時候阅懦,老的 leader 崩潰了和二。
這要分 2 種情況來看:
1.新 leader 已經收到 “共同配置”,那么新 leader 將繼續(xù)進行配置變更操作耳胎。
- 新 leader 沒有收到 “共同配置”惯吕,自然使用 old 配置。
假設:new 配置提交失敗怕午,會怎么樣废登?例如提交的時候,leader 崩潰了郁惜。
這要看 new 配置有沒有同步到大部分節(jié)點堡距。
- 假設已經同步到大部分節(jié)點,則集群使用“新配置” —— 完成配置變更兆蕉。
- 假設沒有同步到大部分節(jié)點羽戒,則集群使用 “共同配置”,繼續(xù)進行配置變更虎韵。
另一個問題:共同一致階段易稠,如果 leader 崩潰,使用什么策略進行選舉包蓝?
答:如果 共同配置 被應用了驶社,那么企量,由于領導人完全特性(如果某條日志在某個任期號中已經被提交,那那個條目必然出現在更大任期號的所有領導人中
)衬吆,新的 leader 必然擁有 共同配置梁钾。
如下圖:
最后,Raft 論文提出的 3 個問題
1. 新的服務器在初始化時逊抡,沒有存儲任何日志條目姆泻。
這個帶來的問題是:由于沒有存儲任何日志條目,那么冒嫡,就需要時間來補充日志條目拇勃,這實際上,是會影響可用性的孝凌。
Raft 使用了一種方法來避免:這個階段的服務器是沒有投票權力的方咆。只有當器補充完日志條目了,才會加入集群蟀架。
2. 集群的領導人可能不是新配置的一員
什么意思瓣赂?
答: 當舊集群的 leader 提交了新配置,Leader 需要變成 follower片拍。
為什么煌集?
答:當新的配置生效時,舊 leader 還使用的老的配置捌省,例如新配置的服務器數量是 5 臺苫纤,而老的 leader 仍然應用的是 3 臺服務器。
新集群應該使用新的配置重新進行選舉(不然使用新配置干嘛纲缓?)卷拘。
3. 移除不在新配置
中的服務器可能會擾亂集群
當移除他們時,他們會重新進行選舉祝高,導致當前 leader 回退到 follower 狀態(tài)栗弟。雖然新的 leader 會被選出來,但被移除的服務器會再次請求重新選舉工闺,循環(huán)反復横腿,影響可用性。
Raft 的解決方式:
- 當節(jié)點確認當前領導人存在時斤寂,則忽略請求投票的 RPC 請求耿焊。
- 當節(jié)點在最小選舉超時時間里收到請求投票請求,他不會更新當前的任期號或者投出選票(從而擾亂集群)遍搞。