1. 程式人生 > >Redis的集群(故障轉移)

Redis的集群(故障轉移)

全量 tex 關註 是否 ont val start 事件 neu

Redis集群自身實現了高可用,當集群內少量節點出現故障時通過自動故障轉移保證集群可以正常對外提供服務。



故障發現


1. 主觀下線

當cluster-node-timeout時間內某節點無法與另一個節點順利完成ping消息通信時,則將該節點標記為主觀下線狀態。


2. 客觀下線

當某個節點判斷另一個節點主觀下線後,該節點的下線報告會通過Gossip消息傳播。當接收節點發現消息體中含有主觀下線的節點,其會嘗試對該節點進行客觀下線,依據下線報告是否在有效期內(如果在cluster-node-timeout*2時間內無法收集到一半以上槽節點的下線報告,那麽之前的下線報告會過期),且數量大於槽節點總數的一半。若是,則將該節點更新為客觀下線,並向集群廣播下線節點的fail消息。



故障恢復


故障節點變為客觀下線後,如果下線節點是持有槽的主節點,則需要在它的從節點中選出一個替換它,從而保證集群的高可用,過程如下:


1. 資格檢查

每個從節點都要檢查最後與主節點斷線時間,判斷是否有資格替換故障的主節點。如果從節點與主節點斷線時間超過cluster-node-timeout*cluster-slave-validity-factor,則當前從節點不具備故障轉移資格。


2. 準備選舉時間

從節點符合故障轉移資格後,更新觸發故障選舉時間,只有到達該時間才能執行後續流程。采用延遲觸發機制,主要是對多個從節點使用不同的延遲選舉時間來支持優先級。復制偏移量越大說明從節點延遲越低,那麽它應該具有更高的優先級。


3. 發起選舉

當從節點到達故障選舉時間後,會觸發選舉流程:


(1) 更新配置紀元

配置紀元是一個只增不減的整數,每個主節點自身維護一個配置紀元,標示當前主節點的版本,所有主節點的配置紀元都不相等,從節點會復制主節點的配置紀元。整個集群又維護一個全局的配置紀元,用於記錄集群內所有主節點配置紀元的最大版本。每次集群發生重大事件,如新加入主節點或由從節點轉換而來,從節點競爭選舉,都會遞增集群全局配置紀元並賦值給相關主節點,用於記錄這一關鍵事件。


(2) 廣播選舉消息

在集群內廣播選舉消息,並記錄已發送過消息的狀態,保證該從節點在一個配置紀元內只能發起一次選舉。


4. 選舉投票

只有持有槽的主節點才會處理故障選舉消息,每個持有槽的節點在一個配置紀元內都有唯一的一張選票,當接到第一個請求投票的從節點消息,回復消息作為投票,之後相同配置紀元內其它從節點的選舉消息將忽略。投票過程其實是一個領導者選舉的過程。


每個配置紀元代表了一次選舉周期,如果在開始投票後的cluster-node-timeout*2時間內從節點沒有獲取足夠數量的投票,則本次選舉作廢。從節點對配置紀元自增並發起下一輪投票,直到選舉成功為止。


5. 替換主節點

當前從節點取消復制變為主節點,撤銷故障主節點負責的槽,把這些槽委派給自己,並向集群廣播告知所有節點當前從節點變為主節點。



故障轉移時間


1. 主觀下線識別時間=cluster-node-timeout。


2. 主觀下線狀態消息傳播時間<=cluster-node-timeout/2(消息通信機制會優先選取下線狀態節點通信)。


3. 從節點轉移時間<=1000毫秒(偏移量最大的從節點最多延遲1秒發起選舉,通常一次就會成功)。


所以,failover-time(毫秒) <= cluster-node-timeout + cluster-node-timeout/2 + 1000



故障轉移過程


以Redis的集群(伸縮)搭建好的集群模擬主節點故障場景。


集群狀態信息

127.0.0.1:6879> cluster nodes

99ea0df1d9683affb1271a5092fc8b15b378adba 127.0.0.1:6885 master - 0 1533780841246 12 connected 0-1364 4096 5461-6826 10923-12287 15018-16383

558b0fb8d44933e694b46c15d05e595ce5ae4fab 127.0.0.1:6886 slave 99ea0df1d9683affb1271a5092fc8b15b378adba 0 1533780844286 12 connected

...


強制關閉6885端口對應的redis進程

$ ps -ef | grep 6885

redis 96825 1 0 Aug04 ? 00:05:03 redis-server 0.0.0.0:6885 [cluster]

$ kill -9 96825


日誌分析如下:


. 從節點6886與主節點6885復制中斷。


96829:S 08 Aug 19:15:45.870 # Connection with master lost.

96829:S 08 Aug 19:15:45.870 * Caching the disconnected master state.

96829:S 08 Aug 19:15:46.804 * Connecting to MASTER 127.0.0.1:6885

96829:S 08 Aug 19:15:46.805 * MASTER <-> SLAVE sync started

96829:S 08 Aug 19:15:46.805 # Error condition on socket for SYNC: Connection refused


. 6879和6880兩個主節點都標記6885為主觀下線,超過半數因此標記為客觀下線狀態。


6879端口日誌

22574:M 08 Aug 19:16:02.677 * Marking node 99ea0df1d9683affb1271a5092fc8b15b378adba as failing (quorum reached).


6880端口日誌

22578:M 08 Aug 19:16:02.680 * Marking node 99ea0df1d9683affb1271a5092fc8b15b378adba as failing (quorum reached).


. 從節點識別正在復制的主節點進入客觀下線後準備選舉時間。


6886端口日誌

96829:S 08 Aug 19:16:02.682 * FAIL message received from 90cb860b7f4ff516304c577bc1e514dc95ecd09b about 99ea0df1d9683affb1271a5092fc8b15b378adba

96829:S 08 Aug 19:16:02.761 # Start of election delayed for 855 milliseconds (rank #0, offset 1654026).


. 延遲選舉時間到達後,從節點更新配置紀元並發起故障選舉。


6886端口日誌

96829:S 08 Aug 19:16:03.677 # Starting a failover election for epoch 13.


. 6879和6880主節點為從節點6886投票。


6879端口日誌

22574:M 08 Aug 19:16:03.679 # Failover auth granted to 558b0fb8d44933e694b46c15d05e595ce5ae4fab for epoch 13


6880端口日誌

22578:M 08 Aug 19:16:03.680 # Failover auth granted to 558b0fb8d44933e694b46c15d05e595ce5ae4fab for epoch 13


. 從節點獲取2個主節點投票後,超過半數,執行替換主節點操作從而完成故障轉移。


6886端口日誌

96829:S 08 Aug 19:16:03.688 # Failover election won: I'm the new master.

96829:S 08 Aug 19:16:03.688 # configEpoch set to 13 after successful failover


故障轉移後,集群狀態信息

127.0.0.1:6879> cluster nodes

99ea0df1d9683affb1271a5092fc8b15b378adba 127.0.0.1:6885 master,fail - 1533780945879 1533780943442 12 disconnected

558b0fb8d44933e694b46c15d05e595ce5ae4fab 127.0.0.1:6886 master - 0 1533803267149 13 connected 0-1364 4096 5461-6826 10923-12287 15018-16383

...


重啟6885端口,其會以現有集群配置為準,變為新主節點6886的從節點。


6885端口日誌

47931:M 09 Aug 01:35:34.512 # Configuration change detected. Reconfiguring myself as a replica of 558b0fb8d44933e694b46c15d05e595ce5ae4fab


集群內其它節點接收到6885發來的ping消息,清空客觀下線狀態。

22574:M 09 Aug 01:35:34.520 * Clear FAIL state for node 99ea0df1d9683affb1271a5092fc8b15b378adba: master without slots is reachable again.


此時集群狀態信息

127.0.0.1:6879> cluster nodes

99ea0df1d9683affb1271a5092fc8b15b378adba 127.0.0.1:6885 slave 558b0fb8d44933e694b46c15d05e595ce5ae4fab 0 1533804408406 13 connected

558b0fb8d44933e694b46c15d05e595ce5ae4fab 127.0.0.1:6886 master - 0 1533804407394 13 connected 0-1364 4096 5461-6826 10923-12287 15018-16383

...



手動故障轉移


Redis集群提供了手動故障轉移功能,指定從節點發起轉移,主從節點角色進行互換,過程如下:


1. 從節點通知主節點停止處理所有客戶端請求。


2. 主節點發送對應從節點延遲復制的數據。


3. 從節點接收復制延遲的數據,直到主從復制偏移量一致。


4. 從節點立刻發起投票選舉,選舉成功後斷開復制變為新的主節點,之後向集群廣播。


5. 原主節點接收消息後更新自身配置變為從節點,解除所有客戶端請求阻塞,重定向到新的主節點。


6. 原主節點變為從節點後,向新的主節點發起全量復制請求(Redis4.0版本這一過程會有改善)。


6885端口上發起手動轉移

127.0.0.1:6885> cluster failover

OK


日誌分析如下:


6885端口日誌

47931:S 09 Aug 02:11:19.943 # Manual failover user request accepted.

47931:S 09 Aug 02:11:20.010 # Received replication offset for paused master manual failover: 2969

47931:S 09 Aug 02:11:20.011 # All master replication stream processed, manual failover can start.

47931:S 09 Aug 02:11:20.011 # Start of election delayed for 0 milliseconds (rank #0, offset 2969).

47931:S 09 Aug 02:11:20.111 # Starting a failover election for epoch 14.

47931:S 09 Aug 02:11:20.115 # Failover election won: I'm the new master.

47931:S 09 Aug 02:11:20.115 # configEpoch set to 14 after successful failover

47931:M 09 Aug 02:11:20.115 # Connection with master lost.


6886端口日誌

96829:M 09 Aug 02:11:19.943 # Manual failover requested by slave 99ea0df1d9683affb1271a5092fc8b15b378adba.

96829:M 09 Aug 02:11:20.113 # Failover auth granted to 99ea0df1d9683affb1271a5092fc8b15b378adba for epoch 14

96829:M 09 Aug 02:11:20.116 # Connection with slave 127.0.0.1:6885 lost.

96829:M 09 Aug 02:11:20.318 # Configuration change detected. Reconfiguring myself as a replica of 99ea0df1d9683affb1271a5092fc8b15b378adba

96829:S 09 Aug 02:11:20.521 * Connecting to MASTER 127.0.0.1:6885


Redis集群還提供了強制故障轉移的方法:


1. cluster failover force - 用於主節點宕機且無法自動完成故障轉移的情況。


2. cluster failover takeover - 用於集群內一半以上主節點故障的場景,從節點無法收到半數以上主節點投票,無法完成選舉過程(慎用)。


若感興趣可關註訂閱號”數據庫最佳實踐”(DBBestPractice).

技術分享圖片

Redis的集群(故障轉移)