建議前面文章沒看過的同窗先看下前面的文章:java
「老司機帶你玩轉面試(1):緩存中間件 Redis 基礎知識以及數據持久化」node
「老司機帶你玩轉面試(2):Redis 過時策略以及緩存雪崩、擊穿、穿透」git
「老司機帶你玩轉面試(3):Redis 高可用之主從模式」github
前面介紹了 Redis 的主從模式,主從模式只能實現讀高可用,致命的弱點是寫沒法高可用,一旦 master 節點掛了,整個集羣將沒法寫入數據,這並不符合咱們對 Redis 高可用集羣的指望。面試
那麼,是否是有一種方法,能夠作到不只僅讀高可用,寫同樣要高可用,固然有,這就是咱們今天要介紹的哨兵模式。redis
哨兵模式能夠理解成主從模式的一個升級版,主從模式 master 節點和 slave 節點是一開始就定好的,而在哨兵模式中, master 節點是能夠轉移,一旦發現當前的 master 節點掛掉,經過選舉能夠指定一個 slave 節點晉升成爲 master ,保證在任何狀況下,都有 master 節點能夠支持寫入操做,也間接實現了寫高可用。shell
哨兵模式能夠看作是前面主從模式的一個升級版,主從模式沒有故障轉移, master 節點掛了就掛了,而哨兵模式就是爲了解決這個問題而出現的。緩存
假如咱們如今有兩個哨兵實例,就長下面這樣:網絡
+----+ +----+
| M1 |---------| R1 |
| S1 | | S2 |
+----+ +----+
複製代碼
再瞭解兩個參數: quorum 、 majority架構
在只有兩個節點的狀況下,若是 master 宕機, s1 和 s2 中只要有 1 個哨兵認爲 master 宕機了,就能夠進行切換,同時 s1 和 s2 會選舉出一個哨兵來執行故障轉移。
這時,須要 majority,也就是大多數哨兵都是運行的。
因此此時,若是此時僅僅是 M1 進程宕機了,哨兵 s1 正常運行,那麼故障轉移是 OK 的。可是若是是整個 M1 和 S1 運行的機器宕機了,那麼哨兵只有 1 個,此時就沒有 majority 來容許執行故障轉移,雖然另一臺機器上還有一個 R1,可是故障轉移不會執行。
因此就有了如下這一條建議:
由於在進行選舉的時候,須要超過一半的哨兵贊成,也就是 majority 。
2 個哨兵,majority=2
3 個哨兵,majority=2
4 個哨兵,majority=2
5 個哨兵,majority=3
6 個哨兵,majority=3
7 個哨兵,majority=4
...
複製代碼
能夠看到,只有在奇數的時候,是能夠最大化的利用 majority 數量。
經典的三哨兵模型下面這樣:
+----+
| M1 |
| S1 |
+----+
|
+----+ | +----+
| R2 |----+----| R3 |
| S2 | | S3 |
+----+ +----+
複製代碼
若是 M1 所在機器宕機了,那麼三個哨兵還剩下 2 個,S2 和 S3 能夠一致認爲 master 宕機了,而後選舉出一個來執行故障轉移,同時 3 個哨兵的 majority 是 2,因此還剩下的 2 個哨兵運行着,就能夠容許執行故障轉移。
首先先說一個結論:
而後咱們再說兩種會致使數據丟失的狀況:
第一種:是異步複製可能會致使數據丟失
因爲 master 向 salve 複製數據是異步,有可能,有部分數據尚未向 salve 複製,這時 master 宕機了,那麼這部分數據就丟失了。
第二種:腦裂致使的數據丟失
腦裂是指,因爲網絡波動或者其餘因素影響, master 所在的機器忽然間沒法被其餘哨兵梭訪問到,可是實際上這個 master 節點還在正常運行中。
此時哨兵會覺得這個 master 節點已經宕機,開始進行新的 master 節點的選舉,將其餘的 salve 節點切換成了 master 節點,這時集羣中就會存在兩個 master 節點,也就是腦裂產生了。
這時雖然產生了新的 master 節點,可是客戶端可能還沒進行切換,還在像老的 master 寫數據,可是當老的 master 恢復訪問的時候,會被做爲一個 salve 掛載到新的 master 節點上,本身的數據會被清空,從新重新的 master 複製數據,而在腦裂過程當中寫入老的 master 的數據就這麼沒了。
數據丟失的解決方案有麼?沒有,由於這個問題是客觀存在的,咱們解決不了這個問題,只能儘可能的去減小這個問題帶來的損失,這時,可使用下面這兩個配置:
min-slaves-to-write 1
min-slaves-max-lag 10
複製代碼
這兩個配置的意思是:
兩個參數的意思:
(1) 減小異步複製的數據丟失:
有了 min-slaves-max-lag
這個配置,就能夠確保說,一旦 slave 複製數據和 ack 延時太長,就認爲可能 master 宕機後損失的數據太多了,那麼就拒絕寫請求,這樣能夠把 master 宕機時因爲部分數據未同步到 slave 致使的數據丟失下降的可控範圍內。
(2) 減小腦裂的數據丟失:
若是一個 master 出現了腦裂,跟其餘 slave 丟了鏈接,那麼上面兩個配置能夠確保說,若是不能繼續給指定數量的 slave 發送數據,並且 slave 超過 10 秒沒有給本身 ack 消息,那麼就直接拒絕客戶端的寫請求。
這樣腦裂後的舊 master 就不會接受 client 的新數據,也就避免了數據丟失。
上面的配置就確保了,若是跟任何一個 slave 丟了鏈接,在 10 秒後發現沒有 slave 給本身 ack ,那麼就拒絕新的寫請求
所以在腦裂場景下,最多就丟失 10 秒的數據。
sdown 達成的條件很簡單,若是一個哨兵 ping 一個 master,超過了 is-master-down-after-milliseconds
指定的毫秒數以後,就主觀認爲 master 宕機了;若是一個哨兵在指定時間內,收到了 quorum 數量的其它哨兵也認爲那個 master 是 sdown 的,那麼就認爲是 odown 了。