Sentinel(哨兵、哨崗)是Redis的高可用(high availability)解決方案:由一個或多個Sentinel實體組成Sentinel系統可以監視任意多個主服務器以及它們屬下的所有從服務器,并在監視主服務器進行下線時,將主服務器下屬的從服務器升級為新的主服務器,然后由新的主服務器代替已下線的主服務器繼續處理命令請求,
Redis的Sentinel主從服務關系圖

從Redis的Sentinel主從服務關系中可以看出:
- Sentinel與Sentinel是彼此之間相互連接,且通過命令連接的方式進行通訊
- 有兩個主服務(master1和master2),每個主服務有3個從服務(master1的3個從服務分別是:slave10、slave11和slave12,master2的3個從服務分別是:slave20、slave21和slave22)
- master與slave之間是復制的關系
- Sentinel系統與master和slave之間可以通過命令連接和訂閱連接進行監控master和slave的狀態
啟動并初始化Sentinel
Sentinel本質上只是一個運行在特殊模式下的Redis服務器,所以啟動Sentinel的第一步就是初始化一個普通的Redis服務器,并將普通Redis服務器使用的代碼替換成Sentinel專用代碼,然后再進行初始化,具體如下:
- 初始化Sentinel狀態
struct sentinelState {
// sentinel id
char myid[CONFIG_RUN_ID_SIZE+1];
// 當前紀元,用于實作故障轉移
uint64_t current_epoch;
// 保存了所有被這個sentinel監視的主服務器
// 字典的鍵是主服務的名字
// 字典的只則是一個指向sentinelRedisInstance結構的指標
dict *masters;
// 是否進入了TILT模式
int tilt;
// 目前正在執行的腳本的數量
int running_scripts;
// 進入TILT模式的時間
mstime_t tilt_start_time;
// 最后一次執行時間處理器的時間
mstime_t previous_time;
// 一個FIFO佇列,包含了所有需要執行的用戶腳本
list *scripts_queue;
} sentinel;
主要初始化Sentinel相關的基礎資訊,其中masters屬性表示該Sentinel需要監聽的所有master實體,這些資料都是通過sentinel.conf組態檔獲取的
- 初始化Sentinel狀態的masters屬性
typedef struct sentinelRedisInstance {
// 標識值,記錄了實體的型別以及該實體的當前狀態
int flags;
// 實體的名字
// 主服務器的名字由用戶在組態檔中的設定
// 從服務器以及Sentinel的名字由Sentinel自動設定
// 格式為ip:port,例如"127.0.0.1:26397"
char *name;
// 實體運行的ID
char *runid;
// 配置紀元,用于實作故障轉移
uint64_t config_epoch;
// 實體的地址
sentinelAddr *addr;
// 實體無回應多少毫米之后才會被判斷為主觀下線
mstime_t down_after_period;
// 監聽同一個master節點的其它sentinel
dict *sentinels;
// master的所有slave節點
dict *slaves;
// 判斷這個實體客觀下線所需的支持投票數量
unsigned int quorum;
// ......
// master實體
struct sentinelRedisInstance *master;
// 如果是master實體,表示執行故障轉移的sentinel的runid
// 如果是sentinel,表示被投票成leader的sentinel的runid
char *leader;
// 重繪故障遷移狀態的最大時限
mstime_t failover_timeout;
// ......
} sentinelRedisInstance;
sentinelState.masters中的實體為sentinelRedisInstance的master物件,sentinelRedisInstance.slaves表示該master物件對應的所有slave,sentinelRedisInstance.sentinels表示該master物件所有被監聽的sentinel
3) 創建連向主服務器的網路連接
初始化Sentinel時需要創建連向被監視器主服務器的網路連接,Sentinel將成為主服務器的客戶端,它可以向主服務器發送命令,并從命令回復中獲取相關的資訊,每個Sentinel會創建兩個連向主服務器的異步網路連接:
- 命令連接,這個連接專門用于向主服務器發送命令,并接收命令回復
- 訂閱連接,這個連接專門用于訂閱主服務器的
__sentinel__:hello頻道
獲取主服務器資訊
Sentinel默認會以每十秒一次的頻率,通過命令連接向被監視的主服務器發送INFO命令,并通過分析INFO命令的回復來獲取主服務器的當前資訊,Sentinel可以獲取以下兩個方面的資訊:
- 主服務的本身的資訊:服務器
runid和服務器的角色 - 主服務器屬下的所有從服務器資訊:從服務器的
ip、port等資訊,同時將從服務器的資訊更新到sentinelRedisInstance.slaves屬性中
獲取從服務器資訊
當Sentinel發現主服務器有新的從服務器出現時,Sentinel除了會為這個新的從服務器創建相應的實體結構之外,Sentinel還會創建連接到從服務器的命令連接和訂閱連接,
接收來自主服務器和從服務器的頻道資訊
Sentinel會對__sentinel__:hello頻道的訂閱一直持續到Sentinel與服務器的連接斷開為止,當一個Sentinel收到從__sentinel__:hello頻道的一條資訊,會對資訊進行分析并,然后如下操作:
- 更新主從服務器的實體結構
- 更新sentinels字典
- 創建連向其它Sentinel的命令連接
檢測主觀下線狀態
默認情況下,Sentinel以每秒一次的頻率向所有其它創建了命令連接的實體(包括主服務器、從服務器、其它Sentinel在內)發送PING命令,并通過PING命令回復來判斷實體是否在線
如果一個實體在down-after-milliseconds毫米內(Sentinel組態檔中配置項),連續向Sentinel回傳無效回復,那么Sentinel會在這個實體中flags屬性中打開SRI_S_DOWN標識,以此來表示這個實體已經進入主觀下線狀態
檢測客觀下線狀態
當Sentinel將一個主服務器判定為主觀下線之后,為了確保這個主服務器是否真的下線,它會詢問其它同樣監視這一主服務器的其它Sentinel,具體步驟如下:
- 源Sentinel發送SENTINEL
is-master-down-by-addr命令 - 目標Sentinel接收SENTINEL
is-master-down-by-addr命令,檢測主服務器是否已下線 - 源Sentinel接收SENTINEL
is-master-down-by-addr命令的回復,通過判斷同意主服務器下線Sentinel的數量是否大于quorum來判定是否主服務器被標記為客觀下線
Sentinel選舉
當一個主服務器被判定為客觀下線時,監視這個主服務器的所有Sentinel會進行協商,選出一個leader執行故障轉移,選舉規則如下:
- 所有在線的Sentinel都有被選為Leader的資格
- 無論選舉是否成功,所有Sentinel的
current_epoch的值都會自增一次 - 所有Sentinel都有一次將某個Sentinel設定為leader的機會,設定以后不能修改,設定的規則是先到先得
- Sentinel通過發送
is-master-down-by-addr命令中的runid引數的值(*除外)來表示leader的runid - 如果有某個Sentinel被半數以上的Sentinel設定成了leader,那么這個Sentinel將成為leader
- 如果在規定的時間內沒有一個Sentinel被選舉為leader,那么所有Sentinel將在一段時間后重新開始選舉直到選出leader為止
故障轉移
選舉產生最為leader的Sentinel將執行對主服務器的故障轉移操作,主要包含三個步驟:
- 在已下線的主服務器的所有從服務器中挑選一個從服務器將其轉換為新的主服務器
- 讓已下線的主服務器的所有從服務器改為復制新的主服務器
- 將已下線主服務器設定為新的主服務器的從服務器,當這個久的主服務器重新上線時,它就會成為新的主服務器的從服務器
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/145071.html
標籤:Java
上一篇:Redis的復制模式
下一篇:Redis的cluster模式
