高可用之戰:Redis Sentinal(哨兵模式)

Hello-Brand發表於2024-04-10

Redis24篇集合

1 背景

在我們的《Redis高可用之戰:主從架構》篇章中,介紹了Redis的主從架構模式,可以有效的提升Redis服務的可用性,減少甚至避免Redis服務發生完全當機的可能。
它主要包含如下能力:
1. 故障隔離和恢復:無論主節點或者從節點當機,其他節點依然可以保證服務的正常執行,並可以手動或自動切換主從。

  • 如果Slave庫故障,則讀寫操作全部走到Master庫中
  • 如果Master庫故障,則將Slave轉成Master庫,僅丟失Master庫來不及同步到Slave的小部分資料

2. 讀寫隔離:Master 節點提供寫服務,Slave 節點提供讀服務,分攤流量壓力,均衡流量的負載。
3. 提供高可用保障:主從模式是高可用的最基礎版本,也是 sentinel 哨兵模式和 cluster 叢集模式實施的前置條件。

主從架構模式雖然很強大,但依然存在一些的問題,我們知道,在衡量系統可用性這方面有個指標叫做MTTR,即平均修復時間。雖然主從模式支援手動切換,但是我們從接收到服務故障預警到手動切換止損到恢復,這可能是一個比較長的過程。這期間的損失將難以計量,對於超高併發大系統是一個絕對災難。所以我們需要系統能自動的感知到Master故障,並選擇一個 Slave 切換為 Master,實現故障自動轉移的能力,提升RTO指數。這時候哨兵模式就可以支稜起來了。

平均修復時間(Mean time to repair,MTTR),是描述產品由故障狀態轉為工作狀態時修理時間的平均值。
復原時間目標(Recovery Time Objective,RTO):是描述產品從故障到恢復原狀的時間,優質架構要求我們儘量在1分鐘左右恢復,一線網際網路大廠的高併發場景0容忍。

2 什麼是哨兵模式

在實際生產環境中,伺服器難免會遇到一些突發狀況:伺服器當機,停電,硬體損壞等等,一旦發生,後果不堪設想。
哨兵模式的核心還是主從模式的演變,只不過相對於主從模式,在主節點當機導致不可寫的情況下,多了探活,以及競選機制:從所有的從節點競選出新的主節點,然後自動切換。競選機制的實現,是依賴於在系統中啟動Sentinel程序,對各個伺服器進行監控。如下圖所示:
image

3 哨兵模式的職責能力

哨兵模式作為Redis高可用的一種執行機制,專注於對 Redis 例項(master、slaves)執行狀態進行監控,並能夠在主節點發生故障時透過一系列的操作,實現新的master競選、主從切換、故障轉移,確保整個 Redis 服務的可用性。

整體來說它有如下能力:

  • 叢集監控
  • 故障監測與通知
  • 自動故障轉移(主從切換)

3.1 叢集監控

哨兵模式的主要任務之一是監控Redis主從複製叢集中的各個節點。它會定期檢查主節點和從節點的健康狀態,確保它們都在正常執行。

3.1.1 前置知識

1. 主觀下線(sdown):

  • sdown(主觀不可用)是單個哨兵自己主觀上檢測到的關於Master的狀態,從哨兵的角度來看,如果傳送PING心跳後,在一定的時間內沒有得到應有的回覆,就達到了sdown的條件。
  • 哨兵配置檔案sentinel.confdown-after-milliseconds屬性設定了判斷主觀下線的回覆時間。

image

# sentinel down-after-milliseconds mymaster 30000  預設30s
sentinel down-after-milliseconds <masterName> <timeout>

這種機制是為了保證多個哨兵例項可以一起綜合判斷,避免單個哨兵(因為自身請求超時、網路抖動等問題)的誤判,導致主庫被下線。

2. 客觀下線 (odown):
上面說了,Master是否下線不是單個Sentinel能夠決定的,一般來說需要一定數量的哨兵,多個哨兵達成一致意見才能認為一個Master客觀上已經當機了。
上面的圖可以看到,我們一般會有個Sentinel叢集 ,這時候這個叢集就發揮作用了,透過投票機制,超過指定數量(一般為半數)的Sentinel 都判斷了『主觀下線』 ,這時候我們就把 Master 標記為『客觀下線』,代表它確實不可用了。
投票判定的數量是透過sentinel.conf配置的:

image

# sentinel monitor <master-name> <master-host> <master-port> <quorum>
# 舉例如下:
sentinel monitor master 127.0.0.1 6379 2

這條配置項用於告知哨兵需要監聽的主節點:
1、sentinel monitor:監控標識
2、mymaster:這邊可以放上主節點的名稱
3、192.168.11.128 6379:代表監控的主節點 ip,port。6379是redis常規埠。
4、2:判定的sentinel數量,果你有3個 Sentinel,並且 quorum 設定為 2,那麼至少需要有2個 Sentinel 認定 Master 節點不可用時(sdown),才會觸發故障轉移,執行 failover 操作。

image

3.1.2 監控和通訊邏輯

1. 哨兵(Sentinel)與主節點(Master)之間

  • Sentinel透過定期(1s一次心跳包)向主節點傳送PING命令來檢查其狀態
  • Sentinel啟動後根據配置向Master傳送 INFO 指令,獲取並儲存所有哨兵(Sentinel)狀態,主節點(Master)和從節點(Slave)資訊。
  • 主節點(Master)會記錄所有從節點(Slave)和與它連線的哨兵(Sentinel)例項的資訊。

2. 哨兵(Sentinel)與從節點(Slave)之間

  • 從上面得知,Sentinel向Master傳送 INFO 命令,並獲取所有Slave的資訊
  • Sentinel 根據 Master 返回的 Slave 列表,逐個與 Salve 建立連線,同樣的定期向從節點傳送PING命令來檢查它們的狀態

3. 叢集中的哨兵(sentinel)之間實現通訊

使用Redis的pub/sub 訂閱能力實現哨兵間通訊 和 Slave 發現。

哨兵之間可以相互通訊,主要歸功於 Redis 的 pub/sub (釋出/訂閱)機制。Master 有一個 __sentinel__:hello 的專用通訊通道,用於哨兵之間釋出和訂閱訊息。哨兵與 Master 建立通訊之後,就可以利用 Master 提供釋出/訂閱機制釋出自己的IP、Port等資訊,同時訂閱其他Sentinel釋出的Name、IP、Port訊息。

  • Sentinel 建立與 Master 的通訊
  • 透過訂閱Master的__sentinel__:hello頻道,當自身節點啟動或更新其狀態時,重新發布自己的當前狀態和資訊(Name、IP、Port訊息)
  • 同時訂閱其他哨兵釋出的Name、IP、Port訊息
  • 互相發現之後建立起了連線,後續的訊息通訊就可以直接進行互動

★ 有沒有覺得套路很熟悉,這個與微服務中的服務註冊與發現,以及RPC通訊類似的做法。請理解清楚圖中1、2、3步驟。
image

4. 標記下線的過程
我們上面說過了,Sentinel程序啟動之後,會定期(1s一次心跳包)向主節點傳送PING命令來檢查其狀態,檢檢視狀態是否正常響應。

  • 如果Slave 沒有在規定的時間內響應 Sentinel 的 PING 命令 , Sentinel 會認為該例項已經掛了,將它tag為下線狀態(offline)。
  • 同理,如果Master 沒有在規定時間響應 Sentinel 的 PING 命令,也會被判定為 offline 狀態,為後續的主從自動切換做好準備工作。

3.2 主從動態切換(故障轉移)

當master出現故障之後,Sentinel 的一個很核心的作用,就是從多個Slave中選舉出一個新的Master,以達到故障轉移的目的。核心步驟如下:

  1. 哨兵會心跳包定時給主節點傳送 publish sentinel :hello,如果超時不響應則標記 主觀下線(sdown)。超時時間配置 down-after-milliseconds前面說過了。
  2. 哨兵標記主節點 sdown 只是單個哨兵行為,需要往Sentinel叢集釋出訊息說明這個主節點掛了,傳送的指令 sentinel is-master-down-by-address-port
  3. 其餘的哨兵接收到指令後,也對Master進行探活,如果收不到響應同樣標記 sdown,同時傳送指令 sentinel is-master-down-by-address-port 到Sentinel內網,這樣哨兵內部群會再收到 Master 掛了的訊息。
  4. 彙總計票,超過半數(透過quorum配置)就認為Master節點確實不行了,然後修改其狀態為 odown, 既客觀下線。注意哨兵總數儘量為單數,避免『腦裂』。
  5. 一旦認為主節點odown後,哨兵就會進行選舉新Master的工作,這很重要。
  6. 選舉新的Master,由指定的哨兵進行選舉。選舉條件:
    • 響應慢的過濾掉,Sentinel會給所有的Redis從節點傳送資訊,響應速度慢的就會被優先過濾掉,說明健壯性不夠。
    • 判斷 offset 偏移量,選擇資料偏移量差距最小的,即slave_repl_offsetmaster_repl_offset 的進度差距,其實就是比較 Slave 與 原 Master 複製進度差距。 假如 slave2 的 offset 為90, slave1 偏移量 為100 那麼哨兵就會認為slave2的網路不佳,優先選擇slave1為新的主節點。
    • slave runID,在優先順序和複製進度都相同的情況下,選用runID最小的,runID越小說明建立時間越早,優先選為Master,先來後到原則。

等這幾個條件都評估完,我們就會選擇出最合適的Slave,把他推舉為新的Master。
image

3.3 資訊通知

等推選出最新的Master之後,後續所有的寫操作都會進入這個Master中。所以需要儘快廣播通知到所有的Slave,讓他們重新 replacaof 到 Master上,重新建立runIDslave_repl_offset ,來保證資料的正常傳輸和主從一致性。

4 總結

Redis 哨兵機制是實現 Redis 高可用的核心手段,相比之前的《Redis高可用之戰:主從架構》更具自動化和時效性。
它的核心功能職責如下:

  • 叢集監控:哨兵模式的主要任務之一是監控Redis主從複製叢集中的各個節點。它會定期檢查主節點和從節點的健康狀態,確保它們都在正常執行。
  • 故障檢測與通知:當檢測到主節點出現故障或不可用時,哨兵會立即傳送報警通知給其他哨兵。這有助於及時發現並處理潛在的問題。
  • 自動故障轉移:在檢測到主節點故障後,哨兵會自動觸發故障轉移機制。它會選擇一個健康的從節點,將其提升為新的主節點,並通知其他從節點更新複製目標。這樣,整個系統可以在主節點故障時保持可用性。
  • 配置更新與通知:在故障轉移完成後,哨兵會更新相關配置,並將新的主節點地址通知給客戶端。這確保了客戶端可以連線到新的主節點並繼續進行操作。

相關文章