redis哨兵(sentinel)原理

jopen 10年前發布 | 25K 次閱讀 Redis NoSQL數據庫

簡介

sentinel是redis高可用的解決方案,sentinel系統(N個sentinel實例,N >= 1)可以監視一個或者多個redis master服務,以及這些master服務的所有從服務;當某個master服務下線時,自動將該master下的某個從服務升級為master服務替代已下線的master服務繼續處理請求。

    1. sentinel初始化

        可以使用命令

        redis-sentinel /path/to/sentinel.conf

        或者

        redis-server /path/to/sentinel.conf --sentinel

        來啟動sentinel

        sentinel啟動時,需要經過一下幾個步驟

        a. 初始化服務

            sentinel本質上是一個特殊的redis服務,所以初始化的時候跟redis服務初始化差不多,不過有幾點不一樣;首先sentinel不會載入RDB或者AOF文件,因為sentinel根本不使用數據庫,其次,sentinel不能使用數據庫鍵值對方面的命令,例如set、del、flushdb等等,同時,sentinel也不能使用事務、腳本、RDB或者AOF持久化命令,最后,復制命令,發布與訂閱命令,文件事件處理器,時間事件處理器等只能在sentinel內部使用。

        b. 將普通redis代碼轉成sentinel專用代碼

            將redis服務的代碼轉成sentinel的專用代碼,例如sentinel的command與redis的command命令表就不一樣(redis很多命令,sentinel不需要

        c. 初始化sentinel狀態

            主要是初始化sentinelState結構,sentinelState里面保存了sentinel的所有功能和狀態,sentinelState結構如下

            

       

        d. 根據指定的配置文件,初始化sentinel監視的主服務器列表

            其實就是初始化sentinelState中的masters屬性,masters字典中記錄了所有被監視的主服務器信息,其中鍵是服務器名字,值是服務對應的sentinelRedisInstance結構,主要有實例名字,運行id,實例地址,客觀下線票數,主管下線的最大無響應時間等等

     

        sentinelState中masters字典的大致結構如下:

        

        e. sentinel創建與masters(所有master)之間的網絡連接

        創建與被監視的master的網絡連接后,sentinel成為該master的客戶端,它會向master發送命令,并從master的響應中獲取master的信息。對于每個被監視的master,sentinel會向其創建兩個異步的網絡連接

        命令連接,這個連接專門用于向master發送命令,并接收命令回復

        訂閱連接,專門訂閱master服務的 sentinel:hello頻道

    

    2. 獲取master信息

        sentinel以每10秒一次的頻率向master發送info命令,通過info的回復來分析master信息,master的回復主要包含了兩部分信息,一部分是master自身的信息,一部分是master所有的slave(從)的信息,所以sentinel可以自動發現master的從服務。sentinel從master哪兒獲取到的master自身信息以及master所有的從信息,將會更新到sentinel的sentinelState中及masters(sentinelRedisInstance結構)中的slaves字典中

            


    3. 獲取從服務器信息

        sentinel發現master有新的從服務時,不但為從服務創建相信的實例結構,而且還會創建連接到該從服務的命令連接和訂閱連接,創建命令連接后,sentinel會10秒每次的向從服務發送info命令,并從回復信息中提取從服務ID、從服務角色、從服務所屬的主服務的ip及端口、主從服務的連接狀態、從服務的優先級、從服務的復制偏移量等信息;創建或者更新到從服務的sentinelRedisInstance結構。

    4. 向被監視服務器發送詢問命令

        sentinel會以每兩秒一次的頻率向所有的被監視服務器(master和從服務)發送詢問命令,命令格式如下

        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:主服務器紀元

    5. 接收被監視服務器的頻道信息

        sentinel與被監視的服務之間,一方面,sentinel通過命令鏈接發送信息到頻道,另一方面,通過訂閱連接從頻道中接收信息。

        對于同一服務的多個sentinel,一個sentinel發送的信息,會被其他sentinel收到,用于更新對該sentinel以及被監視服務的認知,用于更新sentinelRedisInstance的sentinels字典信息(請看sentinelRedisInstance的數據結構)及master信息。

當sentinel通過頻道發現新的sentinel時,不但會更新上圖的sentinel字典,同時會與新的sentinel建立命令連接(不會建立訂閱連接,沒啥可訂閱的,因為sentinel與master及從建立訂閱連接,是用來發現新的sentinel,而sentinel之間是已知的,所以不需要訂閱連接),最終,監視同一個服務的多個sentinel會互聯形成一個網絡。

    6. 主觀下線

        首先解析一下什么叫主觀下線,所謂主觀下線,就是單個sentinel認為某個服務下線(有可能是接收不到訂閱,之間的網絡不通等等原因)。

        sentinel會以每秒一次的頻率向所有與其建立了命令連接的實例(master,從服務,其他sentinel)發ping命令,通過判斷ping回復是有效回復,還是無效回復來判斷實例時候在線(對該sentinel來說是“主觀在線”)。

        sentinel配置文件中的down-after-milliseconds設置了判斷主觀下線的時間長度,如果實例在down-after-milliseconds毫秒內,返回的都是無效回復,那么sentinel回認為該實例已(主觀)下線,修改其flags狀態為SRI_S_DOWN。如果多個sentinel監視一個服務,有可能存在多個sentinel的down-after-milliseconds配置不同,這個在實際生產中要注意。

    7. 客觀下線

        sentinel監視的某個服務主觀下線后,sentinel會詢問其它監視該服務的sentinel,看它們是否也認為該服務主觀下線,接收到足夠數量(這個值可以配置)的sentinel判斷為主觀下線,既任務該服務客觀下線,并對其做故障轉移操作。

        sentinel通過發送 SENTINEL is-master-down-by-addr ip port current_epoch runid,(ip:主觀下線的服務id,port:主觀下線的服務端口,current_epoch:sentinel的紀元,runid:*表示檢測服務下線狀態,如果是sentinel 運行id,表示用來選舉領頭sentinel)來詢問其它sentinel是否同意服務下線。

        一個sentinel接收另一個sentinel發來的is-master-down-by-addr后,提取參數,根據ip和端口,檢測該服務時候在該sentinel主觀下線,并且回復is-master-down-by-addr,回復包含三個參數:down_state(1表示已下線,0表示未下線),leader_runid(領頭sentinal id),leader_epoch(領頭sentinel紀元)。

        sentinel接收到回復后,根據配置設置的下線最小數量,達到這個值,既認為該服務客觀下線

    8. 選舉領頭sentinel

        一個redis服務被判斷為客觀下線時,多個監視該服務的sentinel協商,選舉一個領頭sentinel,對該redis服務進行古戰轉移操作。選舉領頭sentinel遵循以下規則:

        所有的sentinel都有公平被選舉成領頭的資格

        所有的sentinel都有且只有一次將某個sentinel選舉成領頭的機會(在一輪選舉中),一旦選舉某個sentinel為領頭,不能更改

        sentinel設置領頭sentinel是先到先得,一旦當前sentinel設置了領頭sentinel,以后要求設置sentinel為領頭請求都會被拒絕

        每個發現服務客觀下線的sentinel,都會要求其他sentinel將自己設置成領頭

        當一個sentinel(源sentinel)向另一個sentinel(目sentinel)發送is-master-down-by-addr ip port current_epoch runid命令的時候,runid參數不是*,而是sentinel運行id,就表示源sentinel要求目標sentinel選舉其為領頭

        源sentinel會檢查目標sentinel對其要求設置成領頭的回復,如果回復的leader_runid和leader_epoch為源sentinel,表示目標sentinel同意將源sentinel設置成領頭

        如果某個sentinel被半數以上的sentinel設置成領頭,那么該sentinel既為領頭

        如果在限定時間內,沒有選舉出領頭sentinel,暫定一段時間,再選舉

    9. 故障轉移

        故障轉移分為三個主要步驟

        a. 從下線的主服務的所有從服務里面挑選一個從服務,將其轉成主服務

             sentinel狀態數據結構中保存了主服務的所有從服務信息,領頭sentinel按照如下的規則從從服務列表中挑選出新的主服務

            刪除列表中處于下線狀態的從服務

            刪除最近5秒沒有回復過領頭sentinel info信息的從服務

            刪除與已下線的主服務斷開連接時間超過 down-after-milliseconds*10毫秒的從服務,這樣就能保留從的數據比較新(沒有過早的與主斷開連接)

            領頭sentinel從剩下的從列表中選擇優先級高的,如果優先級一樣,選擇偏移量最大的(偏移量大說明復制的數據比較新),如果偏移量一樣,選擇運行id最小的從服務

        b. 已下線主服務的所有從服務改為復制新的主服務

            挑選出新的主服務之后,領頭sentinel 向原主服務的從服務發送 slaveof 新主服務 的命令,復制新master

        c. 將已下線的主服務設置成新的主服務的從服務,當其回復正常時,復制新的主服務,變成新的主服務的從服務

            同理,當已下線的服務重新上線時,sentinel會向其發送slaveof命令,讓其成為新主的從


    

來自: http://my.oschina.net/u/172871/blog/596976

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!