Redis主從複製架構和Sentinel哨兵機制

Redis專題地址:https://www.cnblogs.com/hello-shf/category/1615909.htmlhtml

SpringBoot讀源碼系列:https://www.cnblogs.com/hello-shf/category/1456313.htmljava

Elasticsearch系列:https://www.cnblogs.com/hello-shf/category/1550315.htmlnode

數據結構系列:https://www.cnblogs.com/hello-shf/category/1519192.htmlgit

1、redis主從複製原理

redis主從同步策略:slave剛加入集羣會觸發一次全量同步(全量複製)。全量同步以後,進行增量複製。slave優先是增量同步,若是增量同步失敗會嘗試從master節點進行全量複製。
全量複製:slave初始化階段github

如上圖redis

  1. slave服務器首先鏈接master節點,發送SYNC命令。
  2. master節點收到SYNC命令開始指令BGSAVE(延遲寫,讀正常)命令生成RDB(快照)文件,在此期間master的寫請求會被緩存。
  3. RDB生成,master會將該RDB發送給全部的slave。
  4. slave收到RDB文件會拋棄以前的舊數據,而後載入新的RDB。
  5. master完成RDB發送,會執行以前阻塞的寫命令,並將這些命令同步到slave節點。(增量複製)
  6. 以上步驟完成後master和slave開始正常工做。

值得注意的是,全量複製對主從都是非阻塞的,是異步複製。算法


增量複製:master每次的寫命令會同步到slave,slave收到命令執行對應命令。緩存

斷點續傳:在步驟3步驟中,master發送給slave的文件過程當中,網絡故障了,重連後,master僅會複製給slave缺乏的部分(會記錄offset偏移量)。服務器

master node 會在內存中維護一個 backlog,master 和 slave 都會保存一個 replica offset 還有一個 master run id,offset 就是保存在 backlog 中的。若是 master 和 slave 網絡鏈接斷掉了,slave 會讓 master 從上次 replica offset 開始繼續複製,若是沒有找到對應的 offset,那麼就會執行一次 resynchronization。網絡

主從複製中的內存淘汰策略:slave不會主動淘汰過時key,master處理掉的過時key,會向slave發送一個del命令,同步淘汰的數據。

心跳數據:master 默認每隔 10秒 發送一次 heartbeat,slave node 每隔 1秒 發送一個 heartbeat。

注意,若是採用了主從架構,那麼建議必須開啓 master node 的持久化,不建議用 slave node 做爲 master node 的數據熱備,由於那樣的話,若是你關掉 master 的持久化,可能在 master 宕機重啓的時候數據是空的,而後可能一通過複製, slave node 的數據也丟了。
另外,master 的各類備份方案,也須要作。萬一本地的全部文件丟失了,從備份中挑選一份 rdb 去恢復 master,這樣才能確保啓動的時候,是有數據的,即便採用了高可用機制,slave node 能夠自動接管 master node,但也可能 sentinel 還沒檢測到 master failure,master node 就自動重啓了,仍是可能致使上面全部的 slave node 數據被清空。

2、哨兵機制

哨兵以前的主從架構是須要在各自的配置文件中手動配置本身的master或者slave節點。(方便理解後面的Configuration傳播)
假如採用了redis的主從方案,那麼當master節點宕機,主備切換的過程是須要運維人員手動完成的,人工的故障轉移是十分的耗時並且對運維人員的要求是極高的。
因此就有了基於redis哨兵(Sentinel)機制搭建的高可用架構。

1,sentinel

中文哨兵。哨兵是 redis 集羣機構中很是重要的一個組件,主要有如下功能:

  • 集羣監控:負責監控 redis master 和 slave 進程是否正常工做。
  • 消息通知:若是某個 redis 實例有故障,那麼哨兵負責發送消息做爲報警通知給管理員。
  • 故障轉移:若是 master node 掛掉了,會自動轉移到 slave node 上。
  • 配置中心:若是故障轉移發生了,通知 client 客戶端新的 master 地址。

哨兵用於實現 redis 集羣的高可用,自己也是分佈式的,做爲一個哨兵集羣去運行,互相協同工做。

  • 故障轉移時,判斷一個 master node 是否宕機了,須要大部分的哨兵都贊成才行,涉及到了分佈式選舉的問題。
  • 即便部分哨兵節點掛掉了,哨兵集羣仍是能正常工做的,由於若是一個做爲高可用機制重要組成部分的故障轉移系統自己是單點的,那就很坑爹了。

2,核心知識

  • 哨兵至少須要 3 個實例,來保證本身的健壯性。
  • 哨兵 + redis 主從的部署架構,是不保證數據零丟失的,只能保證 redis 集羣的高可用性。
  • 對於哨兵 + redis 主從這種複雜的部署架構,儘可能在測試環境和生產環境,都進行充足的測試和演練。

3,故障轉移

  • sdown 是主觀宕機,就一個哨兵若是本身以爲一個 master 宕機了,那麼就是主觀宕機
  • odown 是客觀宕機,若是 quorum 數量的哨兵都以爲一個 master 宕機了,那麼就是客觀宕機

sdown 達成的條件很簡單,若是一個哨兵 ping 一個 master,超過了 is-master-down-after-milliseconds 指定的毫秒數以後,就主觀認爲 master 宕機了;若是一個哨兵在指定時間內,收到了 quorum 數量的其它哨兵也認爲那個 master 是 sdown 的,那麼就認爲是 odown 了。

3、slave->master 選舉算法

若是一個 master 被認爲 odown 了,並且 majority 數量的哨兵都容許主備切換,那麼某個哨兵就會執行主備切換操做,此時首先要選舉一個 slave 來,會考慮 slave 的一些信息:

  • 跟 master 斷開鏈接的時長
  • slave 優先級
  • 複製 offset
  • run id

若是一個 slave 跟 master 斷開鏈接的時間已經超過了 down-after-milliseconds 的 10 倍,外加 master 宕機的時長,那麼 slave 就被認爲不適合選舉爲 master。
(down-after-milliseconds * 10) + milliseconds_since_master_is_in_SDOWN_state

接下來會對 slave 進行排序:

  • 按照 slave 優先級進行排序,slave priority 越低,優先級就越高。
  • 若是 slave priority 相同,那麼看 replica offset,哪一個 slave 複製了越多的數據,offset 越靠後,優先級就越高。
  • 若是上面兩個條件都相同,那麼選擇一個 run id 比較小的那個 slave。

quorum 和 majority:


每次一個哨兵要作主備切換,首先須要 quorum 數量的哨兵認爲 odown,而後選舉出一個哨兵來作切換,這個哨兵還須要獲得 majority 哨兵的受權,才能正式執行切換。
若是 quorum < majority,好比 5 個哨兵,majority 就是 3,quorum 設置爲 2,那麼就 3 個哨兵受權就能夠執行切換。
可是若是 quorum >= majority,那麼必須 quorum 數量的哨兵都受權,好比 5 個哨兵,quorum 是 5,那麼必須 5 個哨兵都贊成受權,才能執行切換。


主備切換帶來的數據丟失問題


數據丟失的兩種狀況:

  • 異步複製致使的數據丟失

由於 master->slave 的複製是異步的,因此可能有部分數據還沒複製到 slave,master 就宕機了,此時這部分數據就丟失了。

  • 腦裂致使的數據丟失

腦裂,也就是說,某個 master 所在機器忽然脫離了正常的網絡,跟其餘 slave 機器不能鏈接,可是實際上 master 還運行着。此時哨兵可能就會認爲 master 宕機了,而後開啓選舉,將其餘 slave 切換成了 master。這個時候,集羣裏就會有兩個 master ,也就是所謂的腦裂。
此時雖然某個 slave 被切換成了 master,可是可能 client 還沒來得及切換到新的 master,還繼續向舊 master 寫數據。所以舊 master 再次恢復的時候,會被做爲一個 slave 掛到新的 master 上去,本身的數據會清空,從新重新的 master 複製數據。而新的 master 並無後來 client 寫入的數據,所以,這部分數據也就丟失了。


解決方案:


進行以下配置:

1 min-slaves-to-write 1
2 min-slaves-max-lag 10

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

  • 減小異步複製數據的丟失

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

  • 減小腦裂的數據丟失

若是一個 master 出現了腦裂,跟其餘 slave 丟了鏈接,那麼上面兩個配置能夠確保說,若是不能繼續給指定數量的 slave 發送數據,並且 slave 超過 10 秒沒有給本身 ack 消息,那麼就直接拒絕客戶端的寫請求。所以在腦裂場景下,最多就丟失 10 秒的數據。


4、哨兵集羣的自動發現機制


哨兵互相之間的發現,是經過 redis 的 pub/sub 系統實現的,每一個哨兵都會往 __sentinel__:hello 這個 channel 裏發送一個消息,這時候全部其餘哨兵均可以消費到這個消息,並感知到其餘的哨兵的存在。
每隔兩秒鐘,每一個哨兵都會往本身監控的某個 master+slaves 對應的 __sentinel__:hello channel 裏發送一個消息,內容是本身的 host、ip 和 runid 還有對這個 master 的監控配置。
每一個哨兵也會去監聽本身監控的每一個 master+slaves 對應的 __sentinel__:hello channel,而後去感知到一樣在監聽這個 master+slaves 的其餘哨兵的存在。
每一個哨兵還會跟其餘哨兵交換對 master 的監控配置,互相進行監控配置的同步。


5、configuration 傳播


哨兵完成切換以後,會在本身本地更新生成最新的 master 配置,而後同步給其餘的哨兵,就是經過以前說的 pub/sub 消息機制。
這裏以前的 version 號就很重要了,由於各類消息都是經過一個 channel 去發佈和監聽的,因此一個哨兵完成一次新的切換以後,新的 master 配置是跟着新的 version 號的。其餘的哨兵都是根據版本號的大小來更新本身的 master 配置的。


參考文獻:
  https://github.com/hello-shf/advanced-java
  https://www.cnblogs.com/daofaziran/p/10978628.html

  若有錯誤的地方還請留言指正。
  原創不易,轉載請註明原文地址:http://www.javashuo.com/article/p-oqimlcrb-hs.html

相關文章
相關標籤/搜索