Categories
程式開發

超全面分佈式緩存高可用方案:哨兵機制


開發工作中對於分佈式緩存高可用方案(搭建Redis緩存高可用方案),Redis主從架構下是如何保證高可用的呢?

我們知道是應用了哨兵機制來實現。 那Redis 服務部署的哨兵模式主要是什麼,又解決了什麼問題呢,於是利用周末時間整理了下,相信看完這篇文章,你也可以去給別人做技術分享了。 O(∩_∩)O哈哈~

問題鋪墊

在討論哨兵模式之前,我們先來看一個應用問題:Redis服務主機宕機

實際使用過程中,會出現master宕機的情況(這樣會導致沒有寫服務,只有讀服務)。 那我們要保證服務的可用,就需要從其他salve節點中選取一個來作為master節點,來繼續提供服務能力。

那主要的動作抽像下:

將宕機的master下線找一個slave作為master通知所有的slave連接新的master全量數據或者部分數據同步

其中存在幾個問題:

誰來確認master宕機? (假如僅僅是網絡抖動了一下,就把我宕掉麼?)如何從slave中找一個master代替,誰來找? 怎麼找? 有什麼依據? 修改配置後,原始的主恢復了怎麼辦?

其實引入哨兵機制,就可以很好的解決上述問題。

超全面分佈式緩存高可用方案:哨兵機制 1

什麼是哨兵?

Sentinel(哨兵)是Redis 的高可用性解決方案:由一個或多個Sentinel 實例組成的Sentinel 系統可以監視任意多個主服務,以及這些主服務器屬下的所有從服務,並在被監視的主服務進入下線(不可服務)狀態時,自動將下線主服務器屬下的某個從服務器升級為新的主服務器。

總結一下哨兵的作用:

集群監控

不斷的檢查master和slave是否正常運行(master存活檢測、master與slave運行情況檢測)

消息通知

當被監控的服務器出現問題時,向其他哨兵、客戶端發送通知

自動故障轉移

斷開故障master與slave的連接,選取一個slave作為新master,將其他slave連接到新的master並告知客戶端新的服務器地址。

注意:哨兵也是一台Redis服務器,只是不提供數據服務;通常哨兵配置的數量為單數。

哨兵的工作原理

下面主要針對哨兵在進行主從切換過程中經歷的三個階段分別進行闡述。

1、集群監控

step1:哨兵1連接到Redis集群

發送info命令到master,並建立cmd連接;哨兵端保存哨兵狀態(SentinelStatus),保存所有哨兵狀態,主節點和從節點的信息;master端會記錄redis 實例的信息(SentinelRedisInstance);哨兵根據master中獲取的每個slave信息,去連接每個slave,發送同樣也是info命令。

超全面分佈式緩存高可用方案:哨兵機制 2

step2:哨兵2加入進來後

同樣會發送info命令到master節點,並建立cmd連接;發現master中存在其他哨兵節點的信息,哨兵2中保存哨兵信息(區別與哨兵1的是它保存了哨兵1和哨兵2的2個哨兵節點信息);為了每個哨兵的信息都一致它們之間建立了一個發布訂閱。 為了哨兵之間的信息長期對稱它們之間也會互發ping 命令。

超全面分佈式緩存高可用方案:哨兵機制 3

step3:哨兵3加入後

同樣進行哨兵1、2的動作,會發送info命令到master節點,並建立cmd連接;為了保證哨兵1-哨兵2之間的信息是同步的,建立了一個發布訂閱的一個隊列(可以互發ping命令)

超全面分佈式緩存高可用方案:哨兵機制 4

小結一下:

Sentinel會向master、slave以及其他Sentinel獲取狀態Sentinel之間會組建“對應頻道”,大家一起發布信息、訂閱信息、收信息、同步信息等。

2、消息通知

1)Sentinel節點會通過master/slave 節點建立的cmd連接獲取其工作狀態

2)Sentinel收到反饋結果之後,會在哨兵內部進行信息的互通

超全面分佈式緩存高可用方案:哨兵機制 5

3、故障轉移

關於故障轉移,嚴格來講可劃分兩個步驟:故障判定、故障轉移。

Q1:如何判斷一個節點出現故障?

哨兵會一直給主節點發送publish sentinel:hello

直到主節點故障,哨兵報出sdown,同時此哨兵還會向其他哨兵發布消息說這個主節點掛了。 發送的指令是sentinel is-master-down-by-address-port。

其餘的哨兵接收到指令後,主節點掛了嗎? 讓我去看看到底掛沒掛。 發送的信息也是hello。

其餘的哨兵也會發送他們收到的信息並且發送指令sentinel is-master-down-by-address-port 到自己的內網,確認一下第一個發送sentinel is-master-down-by-address-port的哨兵說你說的對,這個傢伙確實掛了。

當所有人都認為主節點掛了後就會修改其狀態為odown。

當一個哨兵認為主節點掛了標記的是sdown,當半數哨兵都認為掛了其標記的狀態是odown。

一個哨兵認為master節點掛了稱為主觀下線(sdown),超半數哨兵認為master節點掛了則稱為客觀下線(odown)。

超全面分佈式緩存高可用方案:哨兵機制 6

Q2:如何進行故障轉移?

1)首先,哨兵選舉出哨兵Leader去處理故障轉移

此時選舉方式應用的是Raft協議,這個之前有過介紹,感興趣的同學可以移步了解:https://xie.infoq.cn/article/266bb921802ee3c3fb37c8c5d

2)其次,哨兵Leader從所有的slave節點找出一個作為master節點

主要的規則:

選擇在線的節點,pass掉已下線的節點;選擇響應速度快的,pass掉響應慢的節點選擇與原master斷開時間短的,pass掉斷開時間較長的;

假如以上優先級均一致,會考慮其他優先原則:

偏移量較大

假如說slave1 的offset 為50,slave2 偏移量為55,則哨兵就會選擇slave2 為新的主節點。

runid偏大的

這點類似於職場中的論資排輩,也就說根據runid 的創建時間來判斷,時間早的先上位。

3)數據轉移

新master上任:Sentinel向新的master發送slaveof no one其他slave周知:向其他slave發送slaveof 新master IP端口

總結

Redis 主從復制的作用中有這麼一句話“主從復制是高可用的基石”,那實現高可用必不可少的就是哨兵和集群。

1、Sentinel的作用

集群監控

不斷的檢查master和slave是否正常運行(master存活檢測、master與slave運行情況檢測)

消息通知

當被監控的服務器出現問題時,向其他哨兵、客戶端發送通知

自動故障轉移

斷開故障master與slave的連接,選取一個slave作為新master,將其他slave連接到新的master並告知客戶端新的服務器地址。

2、Sentinel的工作方式

每個Sentinel以每秒鐘一次的頻率向它所知的Master,Slave以及其他Sentinel 實例發送一個PING 命令如果一個實例(Instance)距離最後一次有效回复PING 命令的時間超過down-after-milliseconds 選項所指定的值, 則這個實例會被Sentinel 標記為主觀下線。

若Master 重新向Sentinel 的PING 命令返回有效回复, Master 的主觀下線狀態就會被移除。

如果一個Master被標記為主觀下線,則正在監視這個Master的所有Sentinel 要以每秒一次的頻率確認Master的確進入了主觀下線狀態。 當有足夠數量的Sentinel(>=配置文件指定的值)在指定的時間範圍內確認Master的確進入了主觀下線狀態, 則Master會被標記為客觀下線

若沒有足夠數量的Sentinel 同意Master 已經下線, Master 的客觀下線狀態就會被移除。

在一般情況下, 每個Sentinel 會以每10 秒一次的頻率向它已知的所有Master,Slave發送INFO 命令當Master被Sentinel 標記為客觀下線時,Sentinel 向下線的Master 的所有Slave 發送INFO命令的頻率會從10 秒一次改為每秒一次