1.概述
Redis Sentinel是一個分布式系統,為Redis提供高可用性解決方案。可以在一個架構中運行多個 Sentinel 進程(progress), 這些進程使用流言協議(gossip protocols)來 接收關於主服務器是否下線的信息, 並使用投票協議(agreement protocols)來決定是否執行自動故 障遷移, 以及選擇哪個從服務器作為新的主服務器。
Redis 的 Sentinel 系統用於管理多個 Redis 服務器(instance) 該系統執行以下三個任務:
- 監控(Monitoring): Sentinel 會不斷地定期檢查你的主服務器和從服務器是否運作正常。
- 提醒(Notification): 當被監控的某個 Redis 服務器出現問題時, Sentinel 可以通過 API 向管理員或者其他應用程序發送通知。
- 自動故障遷移(Automaticfailover): 當一個主服務器不能正常工作時, Sentinel 會開始一次自動故障遷移操作, 它會將失效主服務器的其中 一個從服務器升級為新的主服務器, 並讓失效主服務器的其他從服務器改為復制新的主服務器; 當客 戶端試圖連接失效的主服務器時, 集群也會向客戶端返回新主服務器的地址, 使得集群可以使用新主 服務器代替失效服務器。
2.Sentinel 工作原理分析
(1)哨兵文件詳解
配置一:sentinel monitor <master-name> <ip> <port> <quorum>
這個配置表達的是 哨兵節點定期監控 名字叫做 <master-name> 並且 IP 為 <ip> 端口號為 <port> 的主節點。<quorum> 表示的是哨兵判斷主節點是否發生故障的票數。也就是說如果我們將<quorum>設置為2就代表至少要有兩個哨兵認為主節點故障了,才算這個主節點是客觀下線的了,一般是設置為sentinel節點數的一半加一。
配置二:sentinel down-after-milliseconds <master-name> <times>
每個哨兵節點會定期發送ping命令來判斷Redis節點和其余的哨兵節點是否是可達的,如果超過了配置的<times>時間沒有收到pong回復,就主觀判斷節點是不可達的,<times>的單位為毫秒。
配置三:sentinel parallel-syncs <master-name> <nums>
當哨兵節點都認為主節點故障時,哨兵投票選出的leader會進行故障轉移,選出新的主節點,原來的從節點們會向新的主節點發起復制,這個配置就是控制在故障轉移之后,每次可以向新的主節點發起復制的節點的個數,最多為<nums>個,因為如果不加控制會對主節點的網絡和磁盤IO資源很大的開銷。
配置四:sentinel failover-timeout <master-name> <times>
這個代表哨兵進行故障轉移時如果超過了配置的<times>時間就表示故障轉移超時失敗。
配置五: sentinel auth-pass <master-name> <password>
如果主節點設置了密碼,則需要這個配置,否則哨兵無法對主節點進行監控。
(2)為什么要用到哨兵
哨兵(Sentinel)主要是為了解決在主從復制架構中出現宕機的情況,主要分為兩種情況:
1).從Redis宕機
這個相對而言比較簡單,在Redis中從庫重新啟動后會自動加入到主從架構中,自動完成同步數據。在Redis2.8版本后,主從斷線后恢復
的情況下實現增量復制。
2).主Redis宕機
這個相對而言就會復雜一些,需要以下2步才能完成
a. 在從數據庫中執行SLAVEOF NO ONE命令,斷開主從關系並且提升為主庫繼續服務
b. 第二步,將主庫重新啟動后,執行SLAVEOF命令,將其設置為其他庫的從庫,這時數據就能更新回來
由於這個手動完成恢復的過程其實是比較麻煩的並且容易出錯,所以Redis提供的哨兵(sentinel)的功能來解決
(3)哨兵機制(sentinel)的高可用
Sentinel(哨兵)是Redis 的高可用性解決方案:由一個或多個Sentinel 實例 組成的Sentinel 系統可以監視任意多個主服務器,以及這些主服務器屬下的所有從服務器,並在被監視的主服務器進入下線狀態時,自動將下線主服務器屬下的某個從服務器升級為新的主服務器。
如圖所示
在Server1 掉線后:
升級Server2 為新的主服務器:
(4)哨兵的定時監控
任務1:每個哨兵節點每10秒會向主節點和從節點發送info命令獲取最拓撲結構圖,哨兵配置時只要配置對主節點的監控即可,通過向主節點發送info,獲取從節點的信息,並當有新的從節點加入時可以馬上感知到
任務2:每個哨兵節點每隔2秒會向redis數據節點的指定頻道上發送該哨兵節點對於主節點的判斷以及當前哨兵節點的信息,同時每個哨兵節點也會訂閱該頻道,來了解其它哨兵節點的信息及對主節點的判斷,其實就是通過消息publish和subscribe來完成的
任務3:每隔1秒每個哨兵會向主節點、從節點及其余哨兵節點發送一次ping命令做一次心跳檢測,這個也是哨兵用來判斷節點是否正常的重要依據
主觀下線:所謂主觀下線,就是單個sentinel認為某個服務下線(有可能是接收不到訂閱,之間的網絡不通等等原因)。
sentinel會以每秒一次的頻率向所有與其建立了命令連接的實例(master,從服務,其他sentinel)發ping命令,通過判斷ping回復是有效回復,還是無效回復來判斷實例時候在線(對該sentinel來說是“主觀在線”)。
sentinel配置文件中的down-after-milliseconds設置了判斷主觀下線的時間長度,如果實例在down-after-milliseconds毫秒內,返回的都是無效回復,那么sentinel回認為該實例已(主觀)下線,修改其flags狀態為SRI_S_DOWN。如果多個sentinel監視一個服務,有可能存在多個sentinel的down-after-milliseconds配置不同,這個在實際生產中要注意。
客觀下線:當主觀下線的節點是主節點時,此時該哨兵3節點會通過指令sentinel is-masterdown-by-addr尋求其它哨兵節點對主節點的判斷,如果其他的哨兵也認為主節點主觀線下了,則當認為主觀下線的票數超過了quorum(選舉)個數,此時哨兵節點則認為該主節點確實有問題,這樣就客觀下線了,大部分哨兵節點都同意下線操作,也就說是客觀下線
(5)哨兵lerder選舉流程
如果主節點被判定為客觀下線之后,就要選取一個哨兵節點來完成后面的故障轉移工作,選舉出一個leader的流程如下:
a)每個在線的哨兵節點都可以成為領導者,當它確認(比如哨兵3)主節點下線時,會向其它哨兵發is-master-down-by-addr命令,征求判斷並要求將自己設置為領導者,由領導者處理故障轉移;
b)當其它哨兵收到此命令時,可以同意或者拒絕它成為領導者;
c)如果哨兵3發現自己在選舉的票數大於等於num(sentinels)/2+1時,將成為領導者,如果沒有超過,繼續選舉…………
(6)自動故障轉移機制
在從節點中選擇新的主節點
sentinel狀態數據結構中保存了主服務的所有從服務信息,領頭sentinel按照如下的規則從從服務列表中挑選出新的主服務
- 過濾掉主觀下線的節點
- 選擇slave-priority最高的節點,如果由則返回沒有就繼續選擇
- 選擇出復制偏移量最大的系節點,因為復制便宜量越大則數據復制的越完整,如果由就返回了,沒有就繼續
- 選擇run_id最小的節點
更新主從狀態
通過slaveof no one命令,讓選出來的從節點成為主節點;並通過slaveof命令讓其他節點成為其從節點。
將已下線的主節點設置成新的主節點的從節點,當其回復正常時,復制新的主節點,變成新的主節點的從節點
同理,當已下線的服務重新上線時,sentinel會向其發送slaveof命令,讓其成為新主的從
3.Sentinel獲取服務器信息
(1) Sentinel獲取主服務器信息
Sentinel默認會以每10秒一次的頻率,通過命令連接向主服務器發送info命令,通過分析info命令的回復來獲取主服務器的當前信息,就像在上篇講到的復制功能,在客戶端輸入info replication 命令一樣,Sentinel可以獲取以下兩方面的信息:
(1) 關於主服務器本身的信息,包括服務器run_id,role的服務器角色。
(2) 關於所有從服務器的信息,每個從服務器都由一個slave字符串開頭的行記錄,記錄了從服務器IP和端口(主服務器中有從庫的配置信息)。
(2)Sentinel獲取從服務器信息
當Sentinel發現主服務器有新的從服務器出現時,Sentinel除了會為這個新的從服務器創建相應的實例結構(sentinelRedisInstance)之外,Sentinel還會創建連接到從服務器的命令連接和訂閱連接。Sentinel默認會以每10秒一次的頻率通過命令連接從服務器發送info命令,通過分析info命令的回復來獲取從服務器的當前信息。包括:從服務器運行run_ID、從服務器角色role、主服務器的ip及端口、主從服務器的連接狀態master_link_status、從服務器的優先級slave_priority。
(3)Sentinel向主從服務器發送信息
在默認情況下, Sentinel會以每2秒一次的頻率,通過命令連接向所有被監視的主服務器和從服務器發送以下格式的命令:
這條命令向服務器的_sentinel_:hello頻道發送了一條信息,信息的內容由多個參數組成:
(1) 以s_開頭以參數記錄的是sentinel本身的信息。
(2) 而m_開頭的參數記錄的則是主服務器的信息,如果sentinel正在監視的是主服務器,那么這些參數就是主服務器的信息,如果sentinel正在監視的是從服務器,那么這些參數記錄就是從服務器正在復制的主服務器的信息。
參數 | 描述 |
S_ip | Sentinel的ip地址 |
S_port | Sentinel的端口號 |
S_runid | Sentinel的運行ID |
S_epoch |
Sentinel 的當前配置紀元 |
m_name | 主服務器的名字 |
M_ip | 主服務器的IP地址 |
M_port | 主服務器的端口號 |
M_epoch | 主服務器的當前配置紀元 |
以下是一條sentinel通過publish命令向主服務器發送的信息示例:
這個示例中sentinel的ip地址為172.0.0.1端口號為26379, 運行ID為后面一串,當前紀元為0。主服務器的名字為mymaster,ip地址為127.0.0.1,端口號為6379, 當前紀元為0。
(4)sentinel接收來自主服務器和從服務器的頻道信息
當sentinel與一個主服務器或者從服務器建立起訂閱連接之后,Sentinel就會通過訂閱連接,向服務器發送以下命令:subscribe_sentinel_:hello 。對於每個與Sentinel連接的服務器,Sentinel既通過命令連向服務器的_sentinel_:hello頻道發送信息,又通過訂閱連接從服務器的_sentinel_:hello頻道接收信息。
當有三個sentinel,分別是sentinel1、sentinel2 、sentinel3。三個sentinel在監視同一個服務器,那么當sentinel1向服務器的_sentinel_:hello頻道發送一條信息時,所有訂閱了_sentinel_:hello頻道的sentinel(包括sentinel1自己在內)都會收到這條信息。
當一個sentinel從_sentinel_:hello頻道收到一條信息時,sentinel會對這條信息進行分析,提取出信息中sentinel 的 ip 、port、runID等8個參數,並進行以下檢查:
(1) 如果信息中記錄的sentinel運行ID和接收信息的sentinel運行ID相同,那么說明這條信息是sentinel自己發送的,sentinel將丟棄這條信息,不做進一步處理。
(2) 相反地,如果信息中記錄的sentinel運行ID和接收信息的sentinel運行ID不相同,那說明這條信息監視同一個服務器的其它sentinel發來的,接收信息的sentinel將根據信息中的參數,對相應主服務器的實例結構進行更新。
(5)sentinel更新自己的sentinels字典
sentinel為主服務器創建實例結構中的sentinels字典,保存了sentinel本身,還監視這個主服務器的其他sentinel的資料。當一個sentinel接收到其他sentinels發來的信息時,接收的sentinel會從信息中分析並提取出兩方面參數:
(1)與sentinel有關的參數,包括sentinel的ip、port、runid、配置紀元。
(2)與主服務器有關的參數, 包括監視主服務器的ip、port、runid、配置紀元。
假設分別有三個sentinel: 127.0.0.1:26379、127.0.0.1:26380、127.0.0.1:26381。三個sentinel正在監視主服務器127.0.0.1:6379, 那么當127.0.0.1:26379這個sentinel接收到以下消息時:
這個sentinel將執行以下動作:
(1) 第一條信息發送者為自己,信息忽略。
(2) 第二條信息發送者為26381, sentinel會根據信息提取出內容,對sentinels字典中26381對應的實例結構進行更新。
(3) 第三條信息發送者為23680,同樣更新字典中的23680對應的實例結構。
每個sentinel都有自己的一個sentinels字典, 對於26379的sentinel它的sentinels字典信息保存了26380和26381兩個sentinel信息。其它sentinel也一樣。
(6)sentinel創建連向其他sentinel的命令連接
當sentinel通過頻道信息發現一個新的sentinel時,不僅更新sentinels字典,還會創建一個連向sentinel命令連接,而新的sentinel也會創建連向這個sentinel的命令連接,最終監視同一個主服務器的多個sentinel將形成相互連接的網絡。如下圖所示:
4.Sentinel的工作原理總結
1):每個Sentinel以每秒鍾一次的頻率向它所知的Master,Slave以及其他 Sentinel 實例發送一個 PING 命令。
2):如果一個實例(instance)距離最后一次有效回復 PING 命令的時間超過 down-after-milliseconds 選項所指定的值, 則這個實例會被 Sentinel 標記為主觀下線。
3):如果一個Master被標記為主觀下線,則正在監視這個Master的所有 Sentinel 要以每秒一次的頻率確認Master的確進入了主觀下線狀態。
4):當有足夠數量的 Sentinel(大於等於配置文件指定的值)在指定的時間范圍內確認Master的確進入了主觀下線狀態, 則Master會被標記為客觀下線 。
5):在一般情況下, 每個 Sentinel 會以每 10 秒一次的頻率向它已知的所有Master,Slave發送 INFO 命令 。
6):當Master被 Sentinel 標記為客觀下線時,Sentinel 向下線的 Master 的所有 Slave 發送 INFO 命令的頻率會從 10 秒一次改為每秒一次 。
7):若沒有足夠數量的 Sentinel 同意 Master 已經下線, Master 的客觀下線狀態就會被移除。
若 Master 重新向 Sentinel 的 PING 命令返回有效回復, Master 的主觀下線狀態就會被移除。
5.參考資料
https://blog.csdn.net/nuomizhende45/article/details/82831966
https://my.oschina.net/u/172871/blog/596976
https://www.cnblogs.com/qinghe123/p/9547884.html
https://www.cnblogs.com/jaycekon/p/6237562.html
https://blog.csdn.net/RobertoHuang/article/details/70768922
https://www.cnblogs.com/leeSmall/p/8398401.html
https://blog.csdn.net/u012240455/article/details/81843714
https://www.cnblogs.com/MrHSR/p/10119843.html