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