Redis設計與實現---Sentinel

Sentinel

Redis的高可用性解決方案:由一個或多個Sentinel實例組成的系統可以監視任意多個主服務器,以及這些主服務器屬下的所有從服務器,並在被監視的主服務器進入下線狀態時,自動將下線主服務器屬下的某個從服務器升級爲新的主服務器。

                                        

對於每個被Sentinel監視的主服務器來說,Sentinel會創建兩個連向主服務器的異步網絡連接:

  • 命令連接:用於向主服務器發送命令,並接收命令回覆
  • 訂閱連接:用於訂閱主服務器的_sentinel_:hello頻道

獲取主服務器信息

Sentinel默認會以每十秒一次的頻率,通過命令連接向被監視的主服務器發送Info命令,獲取到主服務器的當前信息。

  • 主服務器本身的信息,包括run_id以及服務器角色
  • 主服務器屬下所有從服務器的信息,IP地址和端口號。根據這些Sentinel可以自動發現從服務器。

獲取從服務器信息

當Sentinel發現主服務器有新的從服務器出現時,Sentinel除了會爲這個新的從服務器創建相應的實例結構之外,還會創建連接到從服務器的命令連接和訂閱連接。

創建命令連接之後,會以每十秒一次的頻率通過命令連接向從服務器發送INFO命令。獲取到以下信息,更新實例結構

  • 從服務器運行ID run_id
  • 從服務器角色role
  • 主服務器IP地址以及端口號
  • 主服務器連接狀態master_link_status
  • 從服務器優先級slave_priority
  • 從服務器的複製偏移量slave_repl_offset

向主從服務器發送信息

默認情況下,Sentinel會以每兩秒一次的頻率,通過命令連接向所有被監視的主服務器和從服務器發送命令。

PUBLISH _sentinel_:hello "<s_ip>,<s_port>,<s_runid>,<s_epoch>,<m_name>,<m_ip>,<m_port>,<m_epoch>"

接收來自主從服務器的頻道消息

當sentinel與主從服務器建立起訂閱連接之後,就會通過訂閱連接,向服務器發送命令。Sentinel對_sentinel_:hello頻道的訂閱會一直持續到與服務器的斷開爲止。

                                            

通過這種機制,Sentinel爲主服務器創建的實例結構中的sentinels字典保存了所有同樣監視這個主服務器的其他Sentinel資料

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

當Sentinel通過頻道信息發現一個新的Sentinel時,不僅會爲新Sentinel在sentinels字典中創建相應的實例接哦股,還會創建一個連向新Sentinel的命令連接,而新Sentinel也同樣會創建連向這個Sentinel的命令連接。(只會創建命令連接,不創建訂閱連接。訂閱連接是爲了通過頻道信息發現未知的新Sentinel)

                                                    

檢測主觀下線

默認情況下,Sentinel會以每秒一次的頻率向所有與它創建了命令連接的實例(包括主服務器、從服務器、其他Sentinel在內)發送PING命令。並通過實例返回的PING命令回覆判斷實例是否在線。

  • 有效回覆:實例返回+PONG、-LOADING、-MASTERDOWN三種回覆的其中一種
  • 無效回覆:除上面三個回覆之外的其他回覆,或者指定時限內沒有返回任何回覆。

Sentinel配置文件中down-after-milliseconds指定了判斷實例進入主觀下線所需的時間長度。如果一個實例在down-after-milliseconds毫秒內,連續返回無效回覆。Sentinel會修改這個實例所對應的實例結構,flags屬性中打開SRI_S_DOWN表示,以此表示該實例進入主觀下線狀態。

                                                 

注意:

  • 設置down-after-milliseconds的標準,是針對所有實例的,包括主服務器、從服務器、Sentinel
  • 監視同一個主服務器的各個Sentinel來說,設置的down-after-milliseconds值不同,判斷主觀下線的標準也就不一樣。

檢查客觀下線狀態

當Sentinel將一個主服務器判斷爲主觀下線之後,爲了確認這個主服務器是否真的下線了,它會向同樣監視這一主服務器的其他Sentinel進行詢問。當接收到足夠數量的已下線(可以是主觀下線或者客觀下線,爲啥還有客觀下線?因爲每個Sentinel的配置可能不同)判斷之後,會將從服務器判定爲客觀下線,並對主服務器執行故障轉移操作

發送命令

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

回覆命令

接收回覆命令

根據其他Sentinel的命令回覆,統計其他Sentinel同意主服務器已下線的數量,當達到配置(quorum參數配置)指定的判斷客觀下線所需的數量時,將主服務器實例結構flags屬性的SRI_O_DOWN標識打開,表示主服務器已經進入客觀下線狀態。

選舉領頭Sentinel

  • 監視同一個主服務器的多個在線Sentinel中任意一個都有可能成爲領頭Sentinel
  • 每次進行選舉之後,所有Sentinel配置紀元都會自增一次
  • 在一個配置紀元裏,所有Sentinel都有一次設置局部領頭Sentinel的機會,一旦設置成功,在這個配置紀元裏面就不能更改
  • 每個發現主服務器進入客觀下線的Sentinel都會要求其他Sentinel將自己設爲局部領頭Sentinel
  • 當一個Sentinel(源)向另一個Sentinel(目標)發送SENTINEL命令,命令中runid參數不是*符號,而是源Sentinel運行ID時,表示源Sentinel要求目標Sentinel將源Sentinel設置爲局部領頭Sentinel
  • Sentinel設置局部領頭Sentinel的規則是先到先得,後接收的請求都會被拒絕
  • 目標Sentinel的接收到SENTINEL命令的回覆,leader_runid和leader_epoch記錄了目標Sentinel的局部領頭Sentinel的運行ID和配置紀元
  • 某個Sentinel被半數以上的Sentinel設置爲局部領頭Sentinel,那麼這個Sentinel成爲領頭Sentinel
  • 如果給定時限內,沒有選舉成功。那麼將在一段時間之後再次進行選舉,直到選出爲止。

故障轉移

選出新的主服務器

  1. 刪除所有處於下線或者斷線狀態的從服務器
  2. 刪除列表中所有最近五秒內沒有回覆過領頭Sentinel的INFO命令的從服務器
  3. 刪除所有與已下線主服務連接斷開超過down-after-milliseconds*10毫秒的從服務器。保留保存數據比較新的服務器
  4. 根據從服務器的優先級
  5. 根據從服務器的複製偏移量
  6. 根據RunId,選擇runid最小的從服務器
  7. 領頭Sentinel向選中服務器發送SLAVOF no one 命令
  8. 通過Info命令確認從服務器已經升級爲主服務器

            

修改從服務器的複製目標

領頭Sentinel向已下線主服務器的從服務器發送SLAVEOF命令

將舊主服務器變爲從服務器

當下線主服務器重新上線,發送SLAVEOF命令,讓它成爲從服務器。

                                   

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