redis哨兵(sentinel)原理

簡介

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

    1. sentinel初始化

        可使用命令數據庫

        redis-sentinel /path/to/sentinel.conf服務器

        或者網絡

        redis-server /path/to/sentinel.conf --sentinel數據結構

        來啓動sentinel異步

        sentinel啓動時,須要通過一下幾個步驟spa

        a. 初始化服務

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

        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命令,讓其成爲新主的從

相關文章
相關標籤/搜索