Redis | 第12章 Sentinel 哨兵模式《Redis設計與實現》


前言

參考資料:《Redis設計與實現 第二版》;

第四部分為多機資料庫的實現,主要由以下模組組成:複製Sentinel集群

本篇將介紹 Redis 的Sentinel功能。Sentinel(哨兵)是 Redis 的高可用解決方案:由一個或多個 Sentinel 實例(instance)組成的 Sentinel 系統可以監視任意多個主伺服器,以及這些主伺服器屬下的所有從伺服器。在被監控的主伺服器下線時,自動將下屬的某個從伺服器升級為主伺服器,替代舊主伺服器繼續處理命令請求;

與本章相關的 Redis 命令總結在下篇文章,歡迎點擊收藏,本篇將不再重複:

《Redis常用命令及示例總結(API)》//www.cnblogs.com/dlhjw/p/15639773.html


1. 啟動並初始化 Sentinel

  • 使用以下命令:
    • $ redis-sentinel /path/to/your/sentinel.conf
    • $ redis-server /path/to/your/sentinel.conf --sentinel
  • Sentinel 啟動步驟:
    • 1)初始化伺服器:初始化一個普通的 Redis 伺服器,與普通伺服器稍有區別,如下:
      Sentinel 伺服器
    • 2)使用 Sentinel 專屬程式碼:使用 sentinel.c/sentinelcmds 作為伺服器的命令表,因此在 Sentinel 模式下,只能執行 PINGSENTINELINFOSUBSCRIBEUNSUBSCRIBEPSUBSCRIBEPUNSUBSCRIBE 七個命令;
    • 3)初始化 Sentinel 狀態:初始化一個 sentinel.c/sentinelState 結構,該結構保存了伺服器中所有和 Sentinel 功能有關的狀態;
    • 4)初始化 Sentinel 狀態的 masters 屬性:masters 屬性是一個字典,記錄了所有被 Sentinel 監視的主伺服器的相關資訊(圖16-6);
      • 字典的鍵是被監視主伺服器的名字;
      • 字典的值是被監視主伺服器對應的 sentinel.c/sentinelRedisInstance 結構(圖16-5);
        • sentinelRedisInstance 結構里有一個 addr 指針,指向實例的 IP 地址和埠號;
    • 5)創建連向主伺服器的網路連接:對於每個被監視的主伺服器,Sentinel 都會創建兩個連向主伺服器的非同步網路連接:
      • 命令連接:專門用於向主伺服器發送命令,並接收命令回復(Sentinel 是主伺服器的客戶端);
      • 訂閱連接:專門用於訂閱主伺服器的 __sentinel__:hello 頻道;

sentinelRedisInstance 結構示例
masters 字典
sentinel 與主伺服器的網路連接

2. Sentinel 與伺服器間的默認通訊

2.1 獲取主伺服器資訊

  • Sentinel 默認每 10 秒向主伺服器發送 INFO 命令;
  • Sentinel 可以獲得兩方面資訊:
    • 主伺服器本身資訊,如:run_idrole(伺服器角色);
    • 主伺服器下屬所有從伺服器資訊,在以 slave 開頭的字元串里;
  • Sentinel 會根據主伺服器返回的資訊做相應更新;
  • 主從伺服器在 sentinelRedisInstance 結構上的區別:
    • flags 屬性:主伺服器為 SRI_MASTER;從伺服器為 SRI_SLAVE;
    • name屬性:主伺服器為用戶配置文件規定;從伺服器為 IP:埠號;

Sentinel 分析主從伺服器結構

2.2 獲取從伺服器資訊

  • 當 Sentinel 發現新的從伺服器後,會創建一個新的實例結構,同時創建連接到這個從伺服器的命令連接和訂閱連接;
  • 創建命令連接後,Sentinel 默認每 10 秒向從伺服器發送 INFO 命令;
  • Sentinel 會根據從伺服器返回的資訊做相應更新;
    sentinel 與從伺服器的連接

2.3 向主伺服器和從伺服器發送資訊

  • Sentinel 默認每 2 秒通過命令連接向所有被監視的主從伺服器發送以下格式命令:
    • PUBLISH __sentinel__:hello "<s_ip>,<s_port>,<s_runid>,<s_epoch>,<m_name>,<m_ip>,<m_port>,<m_epoch>"

    • 各參數含義如下:

      參數 含義
      s_ip Sentinel 的 IP 地址
      s_port Sentinel 的埠號
      s_runid Sentinel 的運行 ID
      s_epoch Sentinel 當前的配置紀元
      m_name 主伺服器的名字
      m_ip 主伺服器的 IP 地址
      m_port 主伺服器的埠號
      m_epoch 主伺服器當前的配置紀元

3. 接受來自主伺服器和從伺服器的頻道資訊

  • 當 Sentinel 與一個主伺服器或從伺服器建立訂閱連接後,Sentinel 會通過訂閱連接,向伺服器發送以下命令:
    • SUBSCRIBE __sentinel__:hello
  • Sentinel 既通過命令連接向伺服器的 __sentinel__:hello 頻道發送資訊,又通過訂閱連接從伺服器的 __sentinel__:hello 頻道接受資訊;
  • 當多個 Sentinel 監視一個伺服器時,可以通過 __sentinel__:hello 頻道的獲取資訊:
    • 如果資訊中記錄的 Sentinel 運行 ID 跟本Sentinel 一樣,說明資訊是自己發出的,丟棄這條資訊;
    • 反之,說明是其他 Sentinel 發出的;

3.1 更新 Sentinel 字典

  • 一個 Sentinel 可以通過分析接收到的頻道資訊獲知其他 Sentinel 的存在,並通過發送頻道資訊來讓其他 Sentinel 知道自己的存在;
  • 當目標 Sentinel 接受到源 Sentinel 的消息後,會查找主伺服器實例結構的 sentinels 字典:
    • 如果源 Sentinel 存在,對源 Sentinel 的結構進行更新;
    • 反之,說明源 Sentinel 是剛剛監視主伺服器,將其添加到主伺服器實例結構的 sentinels 字典里;
  • 需要注意與從伺服器的區別:sentinels 字典里的源 Sentinel 的 flags 屬性為 SRI_SENTINEL;而從伺服器為 SRI_SLAVE
  • 下圖為 127.0.0.1:26379 的 Sentinel 為主伺服器創建的實例化,其他兩個 Sentinel (埠號為26380和26381)也會為主伺服器創建自己的實例化;

Sentinels 字典里的 Sentinel

3.2 創建連向其他 Sentinel 的命令連接

  • 當目標 Sentinel 通過通道資訊發現一個新的源 Sentinel 時,會做兩件事:
    • 為該源 Sentinel 在 sentinels 字典里創建相應的示例結構;
    • 創建一個連向該源 Sentinel 的命令連接;
      創建連向其他 Sentinel 的命令連接

4. 檢測主觀下線狀態

  • Sentinel 默認每秒向與它建立的所有實例(包括主伺服器、從伺服器和其他 Sentinel)發送 PING 命令;
  • 實例對 PING 命令的回復有兩種情況:
    • 有效回復:實例返回 +PONG、-LOADING、-MASTERDOWN 三種之一;
    • 無效回復:返回其他;
  • Sentinel 配置文件中的 down-after-milliseconds 選項指定 Sentinel 判斷實例進入主觀下線所需的時間;
  • 不同 Sentinel 所設置的主觀下線時長可能不同;
  • 如果某個實例在該時間內已知返回無效回復,Sentinel 會打開該實例 flagsSRI_S_DOWN 標識;

5. 檢查客觀下線狀態

  • 當 Sentinel 將一個主伺服器判斷主觀下線後,會詢問其他 Sentinel。當從其他 Sentinel 接受到足夠數量的已下線判斷後,Sentinel 會將從伺服器判斷為客觀下線,並對主伺服器執行故障轉移操作;

5.1 發送 SENTINEL is-master-down-by-addr 命令

  • 源 Sentinel 使用以下命令詢問其他 Sentinel 是否同意主伺服器已下線:

  • SENTINEL is-master-down-by-addr <ip> <port> <current_epoch> <runid>

    參數 說明
    ip 被 Sentinel 判斷為主觀下線的主伺服器的 IP 地址
    port 被 Sentinel 判斷為主觀下線的主伺服器的埠號
    current_epoch Sentinel 當前的配置紀元,用於選舉領頭 Sentinel
    runid 可以是 * 符合(用於檢測主伺服器的客觀下線狀態)或 Sentinel 的運行 ID(用於選舉領頭 Sentinel)

5.2 接受 SENTINEL is-master-down-by-addr 命令

  • 目標 Sentinel 收到 SENTINEL 命令後,根據其中的主伺服器 IP 和埠號檢查主伺服器是否已下線;

  • 然後向源 Sentinel 返回一個包含三個參數的 Multi Bulk 作為回復;

    參數 說明
    down_state 返回目標 Sentinel 對主伺服器的檢查結果,1代表主伺服器已下線
    leader_runid 可以是 * 符號(用於檢測主伺服器的下線狀態)或目標 Sentinel 的局部領頭 Sentinel 的運行 ID(用於選舉領頭 Sentinel)
    leader_epoch 目標 Sentinel 的局部領頭 Sentinel 的配置紀元,用於選舉領頭 Sentinel

5.3 接受 SENTINEL is-master-down-by-addr 命令的回復

  • 源 Sentinel 統計其他 Sentinel 同意主伺服器已下線的數量,達到一定數量後打開主伺服器實例結構 flags 屬性的 SRI_O_DOWN 標識,標識主伺服器已經進入客觀下線狀態;
  • 該數量可以在 Sentinel 的 quorum 參數中設置(包括源 Sentinel);
  • 不同 Sentinel 判斷客觀下線的條件可能不同;

客觀下線後的主伺服器實例

6. 選舉領頭 Sentinel

  • 當主伺服器被判斷客觀下線時,監視這個下線主伺服器的各個 Sentinel 會進行協商,選舉出一個領頭 Sentinel,並由領頭 Sentinel 對下線的主伺服器執行故障轉移操作;
  • Sentinel 系統選舉領頭 Sentinel 的方法是對 Raft 演算法的領頭選舉方法的實現;
  • Redis 選舉領頭 Sentinel 的規則和方法如下:

領頭 Sentinel 的選舉規則與方法

7. 故障轉移

7.1 選出新的主伺服器

  • 領頭 Sentinel 在從伺服器中選出一個狀態良好、數據完整的從伺服器。選舉規則如下:

主伺服器的選舉規則

  • 選出來後,發送 SLAVEOF no one 命令,將其設置為主伺服器;

設置主伺服器

  • 領頭 Sentinel 每秒(正常是每 10 秒)向被升級的從伺服器發送 INFO 命令,監控從伺服器的 role 屬性;
  • 當伺服器的 role 屬性從 slave 變成 master 時,表明順利升級;

主伺服器升級成功

7.2 修改從伺服器的複製目標

  • 領頭 Sentinel 通過 SLAVEOF 命令讓從伺服器複製新的主伺服器;

修改從伺服器的複製目標

7.3 將舊的主伺服器變成從伺服器

  • 將已下線的主伺服器設置為新主伺服器的從伺服器;

將舊的主伺服器變成從伺服器


最後

新人製作,如有錯誤,歡迎指出,感激不盡!
歡迎關注公眾號,會分享一些更日常的東西!
如需轉載,請標註出處!


另外,下邊有個程式設計師學習求職分享交流群
是我跟科銳國際的 HR 合作的
裡面會分享發布一些求職就業相關的東西
也可以來交流學習技術,歡迎來玩!
掃碼添加 HR 小姐姐為好友,備註【加群】