Redis(開發與運維):44---Sentinel之(哨兵實現原理:三個定時監控任務、主觀下線和客觀下線、領導者節點選舉、故障轉移)

一、三個定時監控任務

  • 一套合理的監控機制是Sentinel節點判定節點不可達的重要保證,Redis Sentinel通過三個定時監控任務完成對各個節點發現和監控

①每隔10秒

  • 每隔10秒,每個Sentinel節點會向主節點和從節點發送info命令獲取最新的拓撲結構,如下圖所示

  • 例如下面就是在一個主節點上執行info replication的結果片段:

  • 這個定時任務的作用具體可以表現在三個方面:
    • 通過向主節點執行info命令,獲取從節點的信息,這也是爲什麼 Sentinel節點不需要顯式配置監控從節點
    • 當有新的從節點加入時都可以立刻感知出來
    • 節點不可達或者故障轉移後,可以通過info命令實時更新節點拓撲信 息

②每隔2秒

  • 如下圖所示:每隔2秒,每個Sentinel節點會向Redis數據節點的__sentinel__:hello頻道上發送該Sentinel節點對於主節點的判斷以及當前Sentinel節點的信息 ,同時每個Sentinel節點也會訂閱該頻道,來了解其他 Sentinel節點以及它們對主節點的判斷

  • 所以這個定時任務可以完成以下兩個工作:
    • 發現新的Sentinel節點:通過訂閱主節點的__sentinel__:hello瞭解其他的Sentinel節點信息,如果是新加入的Sentinel節點,將該Sentinel節點信息保存起來,並與該Sentinel節點創建連接
    • Sentinel節點之間交換主節點的狀態,作爲後面客觀下線以及領導者選舉的依據
  • Sentinel節點publish的消息格式如下:
<Sentinel節點IP> <Sentinel節點端口> <Sentinel節點runId> <Sentinel節點配置版本>
    <主節點名字> <主節點Ip> <主節點端口> <主節點配置版本>

③每隔1秒

  • 每隔1秒,每個Sentinel節點會向主節點、從節點、其餘Sentinel節點發送一條ping命令做一次心跳檢測,來確認這些節點當前是否可達
  • 如下圖所示。通過上面的定時任務,Sentinel節點對主節點、從節點、其餘 Sentinel節點都建立起連接,實現了對每個節點的監控,這個定時任務是節點失敗判定的重要依據

二、主觀下線和客觀下線

①主觀下線

  • 上面介紹的第三個定時任務,每個Sentinel節點會每隔1秒對主節點、從節點、其他Sentinel節點發送ping命令做心跳檢測,當這些節點超過down-after-milliseconds沒有進行有效回覆,Sentinel節點就會對該節點做失敗判定,這個行爲叫做主觀下線
  • 關於down-after-milliseconds參數可以參閱前文:https://blog.csdn.net/qq_41453285/article/details/106382660
  • 從字面意思也可以很容易看出主觀下線是當前Sentinel節點的一家之言,存在誤判的可能,如下圖所示

②客觀下線

  • 客觀下線過程:
    • 當Sentinel主觀下線的節點是主節點時,該Sentinel節點會通過sentinel ismaster-down-by-addr命令向其他Sentinel節點詢問對主節點的判斷,當超過<quorum>個數,Sentinel節點認爲主節點確實有問題,這時該Sentinel節點會 做出客觀下線的決定
    • 這樣客觀下線的含義是比較明顯了,也就是大部分Sentinel節點都對主節點的下線做了同意的判定,那麼這個判定就是客觀 的,如下圖所示

  • sentinel is-master-down-by-addr命令格式如下:
    • ip:主節點IP
    • port:主節點端口
    • current_epoch:當前配置紀元
    • runid:此參數有兩種類型,不同類型決定了此API作用的不同
      • 當runid等於“*”時,作用是Sentinel節點直接交換對主節點下線的判定
      • 當runid等於當前Sentinel節點的runid時,作用是當前Sentinel節點希望目標Sentinel節點同意自己成爲領導者的請求,有關Sentinel領導者選舉下面介紹
sentinel is-master-down-by-addr <ip> <port> <current_epoch> <runid>
  • 例如sentinel-1節點對主節點做主觀下線後,會向其餘Sentinel節點(假設sentinel-2和sentinel-3節點)發送該命令:
sentinel is-master-down-by-addr 127.0.0.1 6379 0 *
  • 返回結果包含三個參數,如下所示:
    • down_state:目標Sentinel節點對於主節點的下線判斷,1是下線,0是在線
    • leader_runid:當leader_runid等於“*”時,代表返回結果是用來做主節點是否不可達,當leader_runid等於具體的runid,代表目標節點同意runid成爲 領導者
    • eader_epoch:領導者紀元

三、領導者節點選舉

  • 假如Sentinel節點對於主節點已經做了客觀下線,那麼是不是就可以立即進行故障轉移了?當然不是,實際上故障轉移的工作只需要一個Sentinel 節點來完成即可,所以Sentinel節點之間會做一個領導者選舉的工作,選出 一個Sentinel節點作爲領導者進行故障轉移的工作
  • Redis使用了Raft算法實 現領導者選舉,因爲Raft算法相對比較抽象和複雜,以及篇幅所限,所以這裏給出一個Redis Sentinel進行領導者選舉的大致思路:
    • 1)每個在線的Sentinel節點都有資格成爲領導者,當它確認主節點主觀下線時候,會向其他Sentinel節點發送sentinel is-master-down-by-addr命令, 要求將自己設置爲領導者
    • 2)收到命令的Sentinel節點,如果沒有同意過其他Sentinel節點的sentinel is-master-down-by-addr命令,將同意該請求,否則拒絕
    • 3)如果該Sentinel節點發現自己的票數已經大於等於max(quorum, num(sentinels)/2+1),那麼它將成爲領導者
    • 4)如果此過程沒有選舉出領導者,將進入下一次選舉
  • 有關Raft算法可以參考其Github主頁:https://raft.github.io/

圖示

  • 下圖展示了一次領導者選舉的大致過程:
    • 1)s1(sentinel-1)最先完成了客觀下線,它會向s2(sentinel-2)和 s3(sentinel-3)發送sentinel is-master-down-by-addr命令,s2和s3同意選其爲 領導者
    • 2)s1此時已經拿到2張投票,滿足了大於等於max(quorum, num(sentinels)/2+1)=2的條件,所以此時s1成爲領導者

  • 由於每個Sentinel節點只有一票,所以當s2向s1和s3索要投票時,只能獲取一票,而s3由於最後完成主觀下線,當s3向s1和s2索要投票時一票都得不到。整個過程如下圖所示:

  • 實際上Redis Sentinel實現會更簡單一些,因爲一旦有一個Sentinel節點獲得了max(quorum,num(sentinels)/2+1)的票數,其他Sentinel節點再去確 認已經沒有意義了,因爲每個Sentinel節點只有一票,如果讀者有興趣的話,可以修改sentinel.c源碼,在Sentinel的執行命令列表中添加monitor命令:
struct redisCommand sentinelcmds[] = {
    {"monitor",monitorCommand,1,"",0,NULL,0,0,0,0,0},
    {"ping",pingCommand,1,"",0,NULL,0,0,0,0,0},
    {"sentinel",sentinelCommand,-2,"",0,NULL,0,0,0,0,0},
    ...
};
  • 重新編譯部署Redis Sentinel測試環境,在3個Sentinel節點上執行monitor命令:
  • 1)可以看到sentinel is-master-down-by-addr命令,此命令的執行過程並 沒有在Redis的日誌中有所體現,monitor監控類似如下命令:
// 因爲最後參數是"*",所以此時是Sentinel節點之間交換對主節點的失敗判定
[0 127.0.0.1:38440] "SENTINEL" "is-master-down-by-addr" "127.0.0.1" "6379" "0" "*"
// 因爲最後參數是具體的runid,所以此時代表runid="2f4430bb62c039fb125c5771d7cde2571a7
    a5ab4"的節點希望目標Sentinel節點同意自己成爲領導者。
[0 127.0.0.1:38440] "SENTINEL" "is-master-down-by-addr" "127.0.0.1" "6379" "1"
    "2f4430bb62c039fb125c5771d7cde2571a7a5ab4"
  • 2)選舉的過程非常快,基本上誰先完成客觀下線,誰就是領導者
  • 3)一旦Sentinel得到足夠的票數,不存在上圖所示的過程

四、故障轉移

  • 領導者選舉出的Sentinel節點負責故障轉移,具體步驟如下:
    • 1)在從節點列表中選出一個節點作爲新的主節點,選擇方法如下:
      • a)過濾:“不健康”(主觀下線、斷線)、5秒內沒有回覆過Sentinel節 點ping響應、與主節點失聯超過down-after-milliseconds*10秒
      • b)選擇slave-priority(從節點優先級)最高的從節點列表,如果存在則 返回,不存在則繼續
      • c)選擇複製偏移量最大的從節點(複製的最完整),如果存在則返回,不存在則繼續
      • d)選擇runid最小的從節點
    • 2)Sentinel領導者節點會對第一步選出來的從節點執行slaveof no one命令讓其成爲主節點
    • 3)Sentinel領導者節點會向剩餘的從節點發送命令,讓它們成爲新主節點的從節點,複製規則和parallel-syncs參數有關
    • 4)Sentinel節點集合會將原來的主節點更新爲從節點,並保持着對其關注,當其恢復後命令它去複製新的主節點

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章