1. 程式人生 > 其它 >Redis設計與實現 第 16 章 Sentinel

Redis設計與實現 第 16 章 Sentinel

第 16 章 Sentinel

Sentinel 哨兵組成了一個 Redis 高可用性的方案:

​ 由一個或多個 Sentinel 例項組成的 Sentinel 系統可以監視任意多個主伺服器及其所有從伺服器,並在主伺服器下線時將其從伺服器升級為新的主伺服器,繼續執行要求,當先前的主伺服器再次上線時則成為新的從伺服器

16.1 啟動並初始化 Sentinel

redis-sentinel /path/to/yourt/setinel.conf
# or
redis-server /path/to/yourt/setinel.conf -- sentinel

啟動時執行以下:

  1. 初始化伺服器
  2. 將普通 Redis 伺服器使用的程式碼替換 Sentinel 專用程式碼
  3. 初始化 Sentinel 程式碼
  4. 根據給定的配置檔案,初始化 Sentinel 的監視主伺服器列表
  5. 建立連向主伺服器的網路連線

16.1.1 初始化伺服器

Sentinel 本質是一個執行在特殊模式下的 Redis 伺服器,所以啟動第一步也是初始化一個 Redis 伺服器,過程與第 14 章的相似,但不完全相同

16.1.2 使用 Sentinel 專用程式碼

例如使用不同埠和不同的命令列表

16.1.3 初始化 Sentinel 狀態

伺服器會初始化一個 sentinel.c/sentinelState 結構,儲存了伺服器中 Sentinel 功能有關的狀態,一般狀態是

16.1.4 初始化 Sentinel 狀態的 master 屬性

  • 字典的鍵:被監視的主伺服器的名字
  • 字典的值:主伺服器對應的 sentinel.c/sentinelRedisInstance 結構
    • 代表一個被 Sentinel 監視的 Redis 伺服器例項
    • 可以是主伺服器、從伺服器、或者另外的 Sentinel

sentinelInstance.addr 屬性指向 sentinel.c/sentinelAddr 結構的指標,sentinelAddr 儲存例項的 IP 地址和埠號

對 Sentinel 狀態的初始化將引發對 masters 字典的初始化,而 master 字典的初始化根據被載入的 Senti 配置檔案來進行的

16.1.5 建立連向主伺服器的網路連線

最後一步即是建立網路連線,Sentinel 將成為主伺服器的客戶端,可以向主伺服器傳送命令,並從命令回覆中獲取相關的資訊

會建立兩個連向主伺服器的非同步網路連線

  • 命令連線:專用傳送命令接收回復

  • 訂閱連線:專門訂閱主伺服器的 _sentinel_:hello 頻道

Redis 釋出與訂閱功能中,被髮送的資訊不會儲存在 Redis 伺服器中,如果資訊傳送時想要接收資訊的客戶端不線上,則會丟失資訊,所以 Sentinel 有專門的連線接收資訊

因為 Sentinel 與多個例項建立連線,所以使用的是非同步連線

16.2 獲取主伺服器資訊

Sentinel 會預設每 10 秒一次頻率向監視的主伺服器通過命令連線傳送 INFO 命令,通過分析回覆獲取當前主伺服器的資訊

  • 主伺服器本身的資訊:
    • run_id:伺服器執行 ID
    • role域:記錄的伺服器角色
  • 主伺服器從屬的所有從伺服器資訊
    • 每一個從伺服器都以一個 "slave" 字串開頭的行記錄
    • ip:記錄了從伺服器的 IP 地址
    • port:從伺服器的埠號

根據 run_id 和 role 域,Sentinel 將對主伺服器的例項結構進行更新,例如重啟後的主伺服器 run_id 將不同,Sentinel 檢測後將會對例項結構的 run_id 進行更新

主伺服器返回的從伺服器資訊被用於更新主伺服器例項的 slave 字典

  • 主伺服器例項結構的 flags 屬性的值是 SRI_MASTER,從伺服器例項結構的 flags 屬性的值是 SRT_SLAVE

  • 主伺服器的 name 屬性是 Sentinel 配置檔案設定的,從伺服器例項結構的 name 屬性的值是 Sentinel 根據從伺服器的 IP 地址、埠號設定的

16.3 獲取從伺服器資訊

如果監視的主伺服器有新的從伺服器出現時,Sentinel 會為這個新的從伺服器建立相應的例項結構外,還會建立連線到從伺服器的命令連線和訂閱連線

建立命令連線後,Sentinel 會以每十秒一次的頻率通過命令連線向從伺服器傳送 INFO 命令

根據 INFO 命令的回覆,Sentinel 會提取以下資訊:

  • 從伺服器的 run_id
  • 從伺服器的角色 role
  • 主伺服器的 IP 地址 master_host,主伺服器的埠號 master_port
  • 主從伺服器的連線狀態 master_link_status
  • 從伺服器的優先順序 slave_priority
  • 從伺服器的複製偏移量 slave_repl_offset

再對從伺服器的例項結構進行更新

16.4 向主伺服器和從伺服器傳送資訊

預設情況下:Sentinel 會以每兩秒一次的頻率,通過命令連線向所有被監視的主伺服器和從伺服器傳送以下格式的命令:

根據監視的是主伺服器還是從伺服器判斷

16.5 接收來自主伺服器和從伺服器的頻道資訊

建立訂閱連線後,Sentinel 則會向伺服器傳送以下命令:

SUBCRIBE _sentinel_:hello

此訂閱會持續到與伺服器的連線斷開,Sentinel 通過此連線接收和傳送訊息

對於監視同一個伺服器的多個 Sentinel,一個 Sentinel 傳送的訊息也會被其他 Sentinel 接收到,然後被用於更新對傳送訊息的 Sentinel 的認知,也會更新其監控的伺服器的認知

16.5.2 更新 sentinels 字典

Sentinel 的 sentinels 字典 同樣監視這個主伺服器的其他 Sentinel:

  • 鍵:其他 Sentinel 的名字,格式為 ip:port
  • 值:對應的 Sentinel 的例項結構

當一個 Sentinel 接收到其他 Sentinel 發來的資訊時,目標 Sentinel 會提取出以下引數:

  • 與 Sentinel 有關的引數:源 Sentinel 的 IP、埠、run_id、配置紀元
  • 與主伺服器有關的引數:源 Sentinel 正在監視的主伺服器的名字、IP、埠、配置紀元

根據主伺服器引數,目標 Sentinel 會在自己的 Sentinel 狀態的 masters 字典查詢對應的主伺服器例項的結構,根據引數,檢查主伺服器例項結構的 Sentinels 字典中 Sentinel 例項結構是否存在:

  • 存在則更新
  • 不存在則源 Sentinel 剛開始監視主伺服器,目標 Sentinel 建立新的例項結構,並新增到 sentinels 字典中

16.5.2 建立連向其他 Sentinel 的命令連線

當 Sentinel 通過頻道資訊發現新的 Sentinel 後不僅建立對應的例項結構,也會建立連向此的命令連線,最終監視同一主伺服器的多個 Sentinel 將形成相互連線的網路

16.6 檢測主觀下線狀態

預設情況下,Sentinel 會預設每秒一次的頻率向所有與它建立了命令連線的例項(主伺服器、從伺服器、其他 Sentinel ) 傳送 PING 命令,通過回覆判斷例項是否線上

例項對 PING 命令的回覆有兩種:

  • 有效回覆:+PONG、-LOADING、-MASTERDOWN 三種
  • 無效回覆:返回有效回覆外的其他回覆,或在指定時間內沒有任何回覆

Sentinel 配置檔案中的 down-after-millisecond 的值為 50000 毫秒,當主伺服器 master 連續 50000 毫秒內都向 Sentinel 返回無效回覆,則會被標記為主觀下線,對應的例項結構的 flags 被標識為 SRI_S_DOWN

down-after-millisecond 的值不僅會被 Sentinel 用來判斷主伺服器的主觀下線狀態,還會被用於判斷主伺服器屬下的從伺服器,以及所有同樣監視這個主伺服器的其他 Sentinel 的主觀下線狀態

且監視同一個主伺服器的不同 Sentinel 來說,此值可能不同

16.7 檢查客觀下線狀態

當一個主伺服器被認為主觀下線後,Sentinel 會詢問其他監視此主伺服器的 Sentinel,當接收到足夠多的下線判斷(主觀或者客觀下線)後,才會將主伺服器判斷為客觀下線,並對主伺服器執行故障轉移操作

16.7.1 傳送 SENTINEL is-master-down-by-addr 命令

Sentinel 使用

SENTINEL IS-master-down-by-addr <current_epoch> <run_id> 來詢問其他 Sentinel 是否同意主伺服器已下線

16.7.2 接收 SENTIENL is-master-down-by-addr 命令

目標 Sentinel 接收到源 Sentinel 發來的命令後,目標會分析提取引數,根據主伺服器 IP 和埠檢查主伺服器是否已下線,然後向源返回一個包含三個引數的 Multi Bulk 作為回覆

  1. <down_state>
  2. <leader_runid>
  3. <leader_epoch>

16.7.3 接收 SENTIENL is-master-down-by-addr 命令的回覆

根據其他 Sentinel 發回的命令回覆,統計同意已下線的數量,達到配置的數量則判斷為客觀下線,flags 標誌為 SRI_O_DOWN

Sentinel 配置的 quorum 引數判斷的標誌,大於等於則被認為是客觀下線

不同的 Sentinel 此引數的配置不同,即對主伺服器的客觀下線判斷不同

16.8 選舉領頭 Sentinel

領頭 Sentinel 對下線主伺服器進行故障轉移操作

選舉 Sentinel :

  • 每個監視同一主伺服器的 Sentinel 都有資格成為領頭
  • 每次選舉後不論成功失敗,每個 Sentinel 的配置紀元增 1
  • 一個配置紀元裡,所有 Sentinel 都有一次機會將某個 Sentinel 設定為區域性領頭,且設定後在此紀元不會更改
  • 每個發現主伺服器進入客觀下線狀態的 Sentinel 都會要求其他將自己設定為區域性領頭
  • 源 Sentinel 向目標 Sentinel 傳送 SENTIENL is-master-down-by-addr 命令且 runid 引數不是 * 而是自己的 runid 時表示要目標設定源為它的區域性領頭 Sentinel
  • 設定區域性領頭的規則是先到先得,後來的都被拒絕
  • 目標接收後將向源回覆,其中的 leader_runid 和 leader_epoch 記錄目標的區域性領頭的 runid 和配置紀元
  • 源接收命令的回覆後取出引數,如果和自己相同則表示自己成為目標的區域性領頭
  • 如果某個 Sentinel 被半數以上設定為區域性領頭,則他成為領頭 Sentinel
  • 因為需要半數以上支援且只能設定一次區域性領頭,則領頭 Sentinel 只有一個
  • 在指定時間內沒有選出領頭 Sentinel,則在一段時間後再進行選擇,直到選出

16.9 故障轉移

三個步驟:

  1. 在已下線的主伺服器的從伺服器中選出一個從伺服器,成為新的主伺服器
  2. 讓其他從伺服器改為複製新的主伺服器
  3. 將已下線的主伺服器設定為新的主伺服器的從伺服器,當重新上線時自動成為主伺服器的從伺服器

16.9.1 選出新的主伺服器

挑選一個狀態良好、資料完整的從伺服器,傳送 SLAVEOF no one 成為主伺服器

挑選

領頭 Sentinel 將所有屬於的從伺服器儲存在列表中,然後按照以下規則過濾

  1. 刪除下線或斷線伺服器
  2. 刪除最近 5 秒沒有回覆領頭 Sentinel 的 INFO 命令的伺服器
  3. 刪除與已下線主伺服器連線斷開超過 down-after-milliseconds * 10 毫秒的伺服器
  4. 根據伺服器的優先順序排序,選出
  5. 如果優先順序一致,選出複製偏移量最大的
  6. 再一致選出執行 ID 最小的

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

讓其他從伺服器複製新的主伺服器,領頭 Sentinel 傳送 SLAVEOF 命令

16.9.3 將舊主伺服器變為從伺服器

領頭 Sentinel 傳送命令