一、Sentinel介紹
Sentinel是redis的高可用性(HA)解決方案: 由一個或多個Sentinel實例組成的Sentinel系統可以監視任意多個主服務器,以及這些主服務器屬下的所有從服務器,并在被監視的主服務器進行下線狀態時,自動將下線主服務器屬下的某個從服務器升級為新的主服務器,然后由新的主服務器代替已下線的主服務器繼續處理命令請求。
二、Sentinel的主從原理
Redis提供的sentinel(哨兵)機制,通過sentinel模式啟動redis后,自動監控master/slave的運行狀態,基本原理是:心跳機制+投票裁決
- 監控(Monitoring): Sentinel 會不斷地檢查你的主服務器和從服務器是否運作正常。
- 提醒(Notification): 當被監控的某個 Redis 服務器出現問題時, Sentinel 可以通過 API 向管理員或者其他應用程序發送通知。
- 自動故障遷移(Automatic failover): 當一個主服務器不能正常工作時, Sentinel 會開始一次自動故障遷移操作, 它會將失效主服務器的其中一個從服務器升級為新的主服務器, 并讓失效主服務器的其他從服務器改為復制新的主服務器; 當客戶端試圖連接失效的主服務器時, 集群也會向客戶端返回新主服務器的地址, 使得集群可以使用新主服務器代替失效服務器。

假設這時s1下線,s2、 s3、 s4停止對s1的復制,sentinel系統會察覺到s1下線;s1下線時長超過用戶設定的下線時長限制,sentinel就會開始故障轉移操作;

1、sentinel系統會挑選s1下的從服務器,并將它設置為新的主服務器(master);
- 如何選出新的master?
一、使用如下條件篩選備選node:
1)、刪除列表中處于下線或者斷線狀態的服務器【S_DOWN,O_DOWN,DISCONNECTED】,這樣可以保證列表中剩余的服務器都是正常在線的。
2)、刪除列表中最近5秒內沒有回復領頭sentinel的INFO命令的服務器,保證列表中剩余的服務器都是最近成功進行通信的。
3)、刪除列表中與原master服務器斷開超過down-after-milliseconds*10毫秒的從服務器,保證剩余的服務器沒有過早跟主服務器斷開連接的。或者說是剩下的從服務器保存的數據是最新的。
4)、Slave priority不等于0(這個是在配置文件中指定,默認配置為100)。
二、從備選node中,按照如下順序選擇新的master
1)、選出優先級比較高的服務器;
2)、較大的replication offset(每個slave在與master同步后offset自動增加);
3)、較小的runid(每個redis實例,都會有一個runid,通常是一個40位的隨機字符串,在redis啟動時設置,重復概率非常小)
4)、如果以上條件都不足以區別出唯一的節點,則會看哪個slave節點處理之前master發送的command多,就選誰。
2、sentinel會給s1下的其他服務器,發送新的復制指令,讓他們follow新的主服務器;當所有服務器都開始follow新的主服務器,故障轉移成功;

3、sentinel也會配置s1也follow新的主服務器,當s1重新上線時,s1直接follow新主服務器;

三、主觀下線和客觀下線
redis sentinel關于被監控的redis實例出現不響應的判斷,內部有兩種不同的概念:主觀下線和客觀下線
主觀下線(SDOWN):
當只有單個sentinel實例對redis實例做出無響應的判斷,此時進入主觀判斷,不會觸發自動故障轉移等操作。
一個服務器必須在 master-down-after-milliseconds 毫秒內, 一直返回無效回復才會被 Sentinel 標記為主觀下線。并在主服務器實例的flags屬性中打開【SRI_S_DOWN】標識.
不同的sentinel節點,對主觀下線的判斷時長可以不一樣,主要看自己的節點配置。
客觀下線(ODOWN) :
多個 Sentinel 實例在對同一個服務器做出 SDOWN 判斷, 并且通過 SENTINEL is-master-down-by-addr 命令互相交流之后, 得出的服務器下線判斷。 (一個 Sentinel 可以通過向另一個 Sentinel 發送 SENTINEL is-master-down-by-addr 命令來詢問對方是否認為給定的服務器已下線)如果達到配置要求的數量(sentinel的啟動配置參數)反饋,則可以標識為客觀下線。flags標識為【SRI_O_DOWN】
從主觀下線狀態切換到客觀下線狀態并沒有使用嚴格的法定人數算法(strong quorum algorithm), 而是使用了流言協議: 如果 Sentinel 在給定的時間范圍內, 從其他 Sentinel 那里接收到了足夠數量的主服務器下線報告, 那么 Sentinel 就會將主服務器的狀態從主觀下線改變為客觀下線。 如果之后其他 Sentinel 不再報告主服務器已下線, 那么客觀下線狀態就會被移除。
客觀下線條件只適用于主服務器: 對于任何其他類型的 Redis 實例, Sentinel 在將它們判斷為下線前不需要進行協商, 所以從服務器Slave或者其他 Sentinel 永遠不會達到客觀下線條件。
客觀下線狀態的判斷條件
sentinel monitor master 127.0.0.1 6379 2 那么有兩個sentinel認為主服務器已經下線狀態,當前的sentinel就可以認為主服務器客觀下線了。
不同的sentinel判斷客觀下線的條件可能不同
1、sentinel monitor master 127.0.0.1 6379 2 兩個sentinel認為主服務器已經下線狀態,當前的sentinel就可以認為主服務器客觀下線了。
2、sentinel monitor master 127.0.0.1 6379 5 兩個sentinel認為主服務器已經下線狀態,并不會將主服務器客觀下線,只有5個sentinel認為主服務器已經下線了,當前的sentinel才可以認為主服務器客觀下線了。
四、選取領頭的sentinel
當sentinel發現主庫客觀下線時候會進行【領頭sentinel】選舉進行故障恢復,其選舉算法采用Raft算法,其設計思想類似與zookpeer的選舉機制的zab比較類似,所有在線的sentinel都可以參與選舉,都有機會被選為領頭的sentinel。選舉過程大體如下:
1、 發現主庫客觀下線的哨兵節點(這里稱為A)向每個哨兵節點發送命令【SENTINEL is-master-down-by-addr】,并且命令中包含自己的運行ID(runid),要求對方選舉自己為領頭哨兵(leader);
2、 如果目標哨兵沒有選舉過其他人,則同意將A選舉為領頭哨兵;回復一條命令,回復中的leader_runid參數和leader_epoch參數,分別記錄了領頭sentinel的運行ID和配置紀元;
3、 如果A發現有超過半數且超過quorum參數值的哨兵節點同意選自己成為領頭哨兵,則A哨兵成功選舉為領頭哨兵。
4、 Sentinel設置局部領頭Sentinel的規則是先到先得,最先向目標sentinel發送設置的源sentinel將成為領頭sentinel,而之后接受到的所有設置請求會被拒絕;
5、當有多個哨兵節點同時參與領頭哨兵選舉時,出現沒有任何節點當選可能,此時每個參選節點等待一個隨機時間進行下一輪選舉,直到選出領頭哨兵。