Redis的哨兵

Redis-Sentinel簡介

Redis Sentinel是一個分佈式架構,其中包含若干個 Sentinel 節點和 Redis 數據節點,每一個 Sentinel 節點會對數據節點和其他 Sentinel 節點進行監控,當它發現節點不可達時,會對節點作下線標識。若是被標識的是主節點,它還會和其餘 Sentinel 節點進行「協商」,當大多數 Sentinel 節點都認爲主節點不可達時,它們會選舉出一個 Sentinel 節點來完成自動故障轉移的工做(這個選舉機制一會介紹),同時會將這個變化實時通知給 Redis 應用方。整個過程徹底是自動的,不須要人工來介入,因此這套方案頗有效地解決了 Redis高可用問題,能夠理解爲:以前的主從複製中增長了幾個哨兵(這裏注意是幾個而不是一個)來監控redis,若是主機掛了,哨兵會通過選舉在從機中選出一個redis做爲主機,這樣就沒必要手動切換了。php

clipboard.png

Redis Sentinel 的功能

監控:Sentinel 節點會按期檢測 Redis 數據節點、其他 Sentinel 節點是否可達。
通知:Sentinel 節點會將故障轉移的結果通知給應用方。
主節點故障轉移:實現從節點晉升爲主節點並維護後續正確的主從關係。
配置提供者:在 Redis Sentinel 結構中,客戶端在初始化的時候鏈接的是 Sentinel 節點集合,從中獲取主節點信息。
同時Redis Sentinel 包含了若個 Sentinel 節點,這樣作也帶來了兩個好處:
對於節點的故障判斷是由多個 Sentinel 節點共同完成,這樣能夠有效地防止誤判。
Sentinel 節點集合是由若干個 Sentinel 節點組成的,這樣即便個別 Sentinel 節點不可用,整個 Sentinel 節點集合依然是健壯的。
Sentinel 節點自己就是獨立的 Redis 節點,只不過它們有一些特殊,它們不存儲數據,只支持部分命令node

基本的故障轉移流程:

1.主節點出現故障,此時兩個從節點與主節點失去鏈接,主從複製失敗。
2.每一個Sentinel 節點經過按期監控發現主節點出現了故障。
3.多個 Sentinel 節點對主節點的故障達成一致會選舉出其中一個節點做爲領導者負責故障轉移。
4.Sentinel 領導者節點執行了故障轉移,整個過程基本是跟咱們手動調整一致的slaveof no one,只不過是自動化完成的。
5.故障轉移後整個 Redis Sentinel 的結構,從新選舉了新的主節點,而且會通知給客戶端。redis

Sentinel 的配置

  1. sentinel monitor <master-name> <ip> <port> <count>

監控的主節點的名字IP端口,最後一個count的意思是有幾臺 Sentinel 發現有問題,就會發生故障轉移,例如 配置爲2,表明至少有2個 Sentinel 節點認爲主節點不可達,那麼這個不可達的斷定纔是客觀的。對於設置的越小,那麼達到下線的條件越寬鬆,反之越嚴格。通常建議將其設置爲 Sentinel 節點的一半加1
注意:最後的參數不得大於conut(sentinel)緩存

  1. sentinel down-after-millseconds <master-name> 30000

這個是超時的時間(單位爲毫秒)。打個比方,當你去 ping 一個機器的時候,多長時間後仍 ping 不通,那麼就認爲它是有問題
3.sentinel parallel-syncs <master-name> 1
當 Sentinel 節點集合對主節點故障斷定達成一致時,Sentinel 領導者節點會作故障轉移操做,選出新的主節點,原來的從節點會向新的主節點發起復制操做,parallel-syncs 就是用來限制在一次故障轉移以後,每次向新的主節點發起復制操做的從節點個數,指出 Sentinel 屬於併發仍是串行。1表明每次只能複製一個,能夠減輕 Master 的壓力;swoole

4.sentinel auth-pass <master-name> <password>網絡

若是 Sentinel 監控的主節點配置了密碼,sentinel auth-pass 配置經過添加主節點的密碼,防止 Sentinel 節點對主節點沒法監控。
5.sentinel failover-timeout mymaster 180000
表示故障轉移的時間。
6.sentinel支持的合法命令以下:
SENTINEL masters 顯示被監控的全部master以及它們的狀態.
SENTINEL master <master name> 顯示指定master的信息和狀態;
SENTINEL slaves <master name> 顯示指定master的全部slave以及它們的狀態;
SENTINEL get-master-addr-by-name <master name> 返回指定master的ip和端口,若是正在進行failover或者failover已經完成,將會顯示被提高爲masterslaveip和端口。
SENTINEL failover <master name> 強制sentinel執行failover,而且不須要獲得其餘sentinel的贊成。可是failover後會將最新的配置發送給其餘sentinel架構

修改配置
sentinel monitor <master-name> <ip> <port> <count> 添加新的監聽併發

SENTINEL REMOVE <master-name> 放棄對某個master監聽異步

SENTINEL set failover-timeout <master-name> 180000 設置配置選項分佈式

應用端調用

`Master`可能會由於某些狀況宕機了,若是在客戶端是固定一個地址去訪問,確定是不合理的,因此客戶端請求是請求哨兵,從哨兵獲取主機地址的信息,或者是從機的信息。能夠實現一個例子

一、隨機選擇一個哨兵鏈接,獲取主機、從機信息
二、模擬客戶端定時訪問,實現簡單輪訓效果,輪訓從節點
三、鏈接失敗重試訪問
這裏我簡單寫個例子,這裏我用了swoole的定時器

<?php
class Round{
    static  $lastIndex=0;

    public  function select($list){
        $currentIndex=self::$lastIndex; //當前的index
        $value=$list[$currentIndex];
        if($currentIndex+1>count($list)-1){
            self::$lastIndex=0;
        }else{
            self::$lastIndex++;
        }
        return $value;
    }
}

$sentinelConf=[
    ['ip'=>'xxx','port'=>xxx],
    ['ip'=>'xxx','port'=>xxx],
    ['ip'=>'xxx','port'=>xxx]
];
//隨機訪問
$sentinelInfo=$sentinelConf[array_rand($sentinelConf)];

$redis=new Redis();
$redis->connect($sentinelInfo['ip'],$sentinelInfo['port']);
//rawCommand參數 1 command 2 arguments 3.
$slavesInfo=$redis->rawCommand('SENTINEL','slaves','mymaster');
$slaves=[];
foreach ($slavesInfo as $val){
    $slaves[]=['ip'=>$val[3],'port'=>$val[5]];
}

//加載到緩存當中,能夠記錄此次訪問的時間跟上次的訪問時間

//模擬客戶端訪問
swoole_timer_tick(600,function () use($slaves) {
       //輪訓
        $slave=(new Round())->select($slaves);
        try{
            $redis=new Redis();
            $redis->connect($slave['ip'],$slave['port']);
            var_dump($slave,$redis->get('username'));
        }catch (\RedisException $e){

        }

});

Sentinel 實現原理三步驟

說完了 Sentinel 的代碼實現,不少人對 Sentinel 還不懂其原理。那麼接下來就來看下 Sentinel 的實現原理,主要分爲如下三個步驟。

1.檢測問題之三個定時任務

10秒每一個 SentinelMasterSlave 執行一次 Info Replication
2秒每一個 Sentinel 經過 Master 節點的 channel 交換信息(pub/sub)。
1秒每一個 Sentinel 對其餘 SentinelRedis 執行 ping
第一個定時任務,指的是 Redis Sentinel 能夠對 Redis 節點作失敗判斷和故障轉移,在 Redis 內部有三個定時任務做爲基礎,來 Info Replication 發現 Slave 節點,這個命令能夠肯定主從關係。
第兩個定時任務,相似於發佈訂閱,Sentinel 會對主從關係進行斷定,經過 _sentinel_:hello 頻道交互。瞭解主從關係能夠幫助更好的自動化操做 Redis。而後 Sentinel 會告知系統消息給其它 Sentinel 節點,最終達到共識,同時 Sentinel 節點可以互相感知到對方。
第三個定時任務,指的是對每一個節點和其它 Sentinel 進行心跳檢測,它是失敗斷定的依據。

2.發現問題之主觀下線和客觀下線

當有一臺 Sentinel 機器發現問題時,它就會主觀對它主觀下線,可是當多個 Sentinel 都發現有問題的時候,纔會出現客觀下線。
咱們先來回顧一下 Sentinel 的配置。

sentinel monitor <master-name>  <ip> <port>   <count>

sentinel down-after-milliseconds <master-name> 30000

Sentinelping 每一個節點,若是超過30秒,依然沒有回覆的話,作下線的判斷。

什麼是主觀下線呢?

每一個 Sentinel 節點對 Redis 節點失敗的「偏見」。之因此是偏見,只是由於某一臺機器30秒內沒有獲得回覆。

如何作到客觀下線?

這個時候須要全部 Sentinel 節點都發現它30秒內無回覆,纔會達到共識。

3.找到解決問題的人之領導者選舉

1.每一個作主觀下線的sentinel節點,會向其餘的sentinel節點發送命令,要求將它設置成爲領導者
2.收到命令sentinel節點,若是沒有贊成經過其它節點發送的命令,那麼就會贊成請求,不然就會拒絕
3.若是sentinel節點發現本身票數超過半數,同時也超過了sentinel monitor <master-name> <ip> <port> <count> 超過count個的時候,就會成爲領導者

4.解決問題之故障轉移

如何選擇「合適的」Slave 節點
Redis 內部實際上是有一個優先級配置的,在配置文件中 slave-priority,這個參數是 Salve 節點的優先級配置,若是存在則返回,若是不存在則繼續。
當上面這個優先級不知足的時候,Redis 還會選擇複製偏移量最大的 Slave節點,若是存在則返回,若是不存在則繼續。之因此選擇偏移量最大,這是由於偏移量越小,和 Master 的數據越不接近,如今 Master掛掉了,說明這個偏移量小的機器數據也可能存在問題,這就是爲何要選偏移量最大的 Slave 的緣由。
若是發現偏移量都同樣,這個時候 Redis 會默認選擇 runid 最小的節點。

生產環境中部署注意事項

1.Sentinel 節點不該該部署在一臺物理「機器」上。
這裏特地強調物理機是由於一臺物理機作成了若干虛擬機或者現今比較流行的容器,它們雖然有不一樣的 IP 地址,但實際上它們都是同一臺物理機,同一臺物理機意味着若是這臺機器有什麼硬件故障,全部的虛擬機都會受到影響,爲了實現 Sentinel 節點集合真正的高可用,請勿將 Sentinel 節點部署在同一臺物理機器上。
2.部署至少三個且奇數個的 Sentinel 節點。
3.個以上是經過增長 Sentinel 節點的個數提升對於故障斷定的準確性,由於領導者選舉須要至少一半加1個節點,奇數個節點能夠在知足該條件的基礎上節省一個節點。

哨兵常見問題

哨兵集羣在發現master node掛掉後會進行故障轉移,也就是啓動其中一個slave nodemaster node。在這過程當中,可能會致使數據丟失的狀況。

一、異步複製致使數據丟失

由於master->slave的複製是異步,因此可能有部分還沒來得及複製到slave就宕機了,此時這些部分數據就丟失了,這個我至今沒找到解決的辦法,但願有人更正。

二、集羣腦裂致使數據丟失

腦裂,也就是說,某個master所在機器忽然脫離了正常的網絡,跟其它slave機器不能鏈接,可是實際上master還運行着。

形成的問題

此時哨兵可能就會認爲master宕機了,而後開始選舉,講其它slave切換成master。這時候集羣裏就會有2個master,也就是所謂的腦裂。
此時雖然某個slave被切換成了master,可是可能client還沒來得及切換成新的master,還繼續寫向舊的master的數據可能就丟失了。
所以舊master再次恢復的時候,會被做爲一個slave掛到新的master上去,本身的數據會被清空,從新重新的master複製數據。

怎麼解決?

min-slaves-to-write 1

min-slaves-max-lag  10

要求至少有1個slave,數據複製和同步的延遲不能超過10
若是說一旦全部的slave,數據複製和同步的延遲都超過了10秒鐘,那麼這個時候,master就不會再接收任何請求了

上面兩個配置能夠減小異步複製和腦裂致使的數據丟失

一、異步複製致使的數據丟失

在異步複製的過程中,經過min-slaves-max-lag這個配置,就能夠確保的說,一旦slave複製數據和ack延遲時間太長,就認爲可能master宕機後損失的數據太多了,那麼就拒絕寫請求,這樣就能夠把master宕機時因爲部分數據未同步到slave致使的數據丟失下降到可控範圍內

二、集羣腦裂致使的數據丟失

集羣腦裂由於client還沒來得及切換成新的master,還繼續寫向舊的master的數據可能就丟失了經過min-slaves-to-write 確保必須是有多少個從節點鏈接,而且延遲時間小於min-slaves-max-lag多少秒。

客戶端怎麼作

對於client來說,就須要作些處理,好比先將數據緩存到內存當中,而後過一段時間處理,或者鏈接失敗,接收到錯誤切換新的master處理。

相關文章
相關標籤/搜索