Redis詳解(六)——哨兵機制 一、概述 Redis Sentinel是一個分散式系統,為Redis提供高可用性解決方案。可以在一個架構中運行多個 Sentinel 進程(progress), 這些進程使用流言協議(gossip protocols)來 接收關於主伺服器是否下線的信息, 並使用投票 ...
Redis詳解(六)——哨兵機制
一、概述
Redis Sentinel是一個分散式系統,為Redis提供高可用性解決方案。可以在一個架構中運行多個 Sentinel 進程(progress), 這些進程使用流言協議(gossip protocols)來 接收關於主伺服器是否下線的信息, 並使用投票協議(agreement protocols)來決定是否執行自動故 障遷移, 以及選擇哪個從伺服器作為新的主伺服器。
Redis 的 Sentinel 系統用於管理多個 Redis 伺服器(instance) 該系統執行以下三個任務:
- 監控(Monitoring): Sentinel 會不斷地定期檢查你的主伺服器和從伺服器是否運作正常。
- 提醒(Notification): 當被監控的某個 Redis 伺服器出現問題時, Sentinel 可以通過 API 向管理員或者其他應用程式發送通知。
- 自動故障遷移(Automaticfailover): 當一個主伺服器不能正常工作時, Sentinel 會開始一次自動故障遷移操作, 它會將失效主伺服器的其中 一個從伺服器升級為新的主伺服器, 並讓失效主伺服器的其他從伺服器改為複製新的主伺服器; 當客 戶端試圖連接失效的主伺服器時, 集群也會向客戶端返回新主伺服器的地址, 使得集群可以使用新主 伺服器代替失效伺服器。
二、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命令,讓其成為新主的從
三、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將形成相互連接的網路。如下圖所示:
四、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 的主觀下線狀態就會被移除。
五、參考資料
https://www.cnblogs.com/Eugene-Jin/p/10819601.html