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