【Redis叢集原理專題】分析一下相關的Redis叢集模式下的腦裂問題!

浩宇天尚發表於2021-12-04

技術格言

世界上並沒有完美的程式,但是我們並不因此而沮喪,因為寫程式就是一個不斷追求完美的過程。

什麼是腦裂

字面含義

首先,腦裂從字面上理解就是腦袋裂開了,就是思想分家了,就是有了兩個山頭,就是有了兩個主思想。

技術定義

在高可用叢集中,當兩臺高可用伺服器在指定的時間內,由於網路的原因無法互相檢測到對方心跳而各自啟動故障轉移功能,取得了資源以及服務的所有權,而此時的兩臺高可用伺服器對都還活著並作正常執行,這樣就會導致同一個服務在兩端同時啟動而發生衝突的嚴重問題,最嚴重的就是兩臺主機同時佔用一個VIP的地址(類似雙端匯入概念),當使用者寫入資料的時候可能會分別寫入到兩端,這樣可能會導致伺服器兩端的資料不一致或造成資料的丟失,這種情況就稱為裂腦,也有的人稱之為分割槽叢集或者大腦垂直分隔,互相接管對方的資源,出現多個Master的情況,稱為腦裂。

腦裂導致的問題

引起資料的不完整性:在叢集節點出現腦裂的時候,如果外部無法判斷哪個為主節點,腦裂的叢集都可以正常訪問的時候,這時候就會出現資料不完整的可能性。

  • 服務異常:對外提供服務出現異常。

導致裂腦發生的原因

優先考慮心跳線路上的問題,在可能是心跳服務,軟體層面的問題

  • 1)高可用伺服器對之間心跳線路故障,導致無法正常的通訊。原因比如:

    • 1——心跳線本身就壞了(包括斷了,老化);

    • 2——網路卡以及相關驅動壞了,IP配置及衝突問題;

    • 3——心跳線間連線的裝置故障(交換機的故障或者是網路卡的故障);

    • 4——仲裁的伺服器出現問題。

  • 2)高可用伺服器對上開啟了防火牆阻擋了心跳訊息的傳輸;

  • 3)高可用伺服器對上的心跳網路卡地址等資訊配置的不正確,導致傳送心跳失敗;

  • 4)其他服務配置不當等原因,如心跳的方式不同,心跳廣播衝突,軟體出現了BUG等。

解決腦裂所出現的問題

  • 新增冗餘的心跳線,儘量減少“腦裂”的機會

  • 啟用磁碟鎖:在發生腦裂的時候可以協調控制對資源的訪問設定仲裁機制

實際的生產環境中,我們可以從以下幾個方面來防止裂腦的發生:

  • 1)同時使用序列電纜和乙太網電纜連線,同時用兩條心跳線路,這樣一條線路壞了,另一個線路還是好的,依然能傳送訊息(推薦的)

  • 2)檢測到裂腦的時候強行的關閉一個心跳節點(需要特殊的節點支援,如stonith,fence),相當於程式上備節點發現心跳線故障,傳送關機命令到主節點。

  • 3)多節點叢集中,可以通過增加仲裁的機制,確定誰該獲得資源,這裡面有幾個參考的思路:

    1——增加一個仲裁機制。例如設定參考的IP,當心跳完全斷開的時候,2個節點各自都ping一下參考的IP,不同則表明斷點就出現在本段,這樣就主動放棄競爭,讓能夠ping通參考IP的一端去接管服務。

    2——通過第三方軟體仲裁誰該獲得資源,這個在阿里有類似的軟體應用

  • 4)做好對裂腦的監控報警(如郵件以及手機簡訊等),在問題發生的時候能夠人為的介入到仲裁,降低損失。當然,在實施高可用方案的時候,要根據業務的實際需求確定是否能夠容忍這樣的損失。對於一般的網站業務,這個損失是可控的(公司使用)

  • 5)啟用磁碟鎖。正在服務一方鎖住共享磁碟,腦裂發生的時候,讓對方完全搶不走共享的磁碟資源。但使用鎖磁碟也會有一個不小的問題,如果佔用共享盤的乙方不主動解鎖,另一方就永遠得不到共享磁碟。現實中介入服務節點突然當機或者崩潰,另一方就永遠不可能執行解鎖命令。後備節點也就截關不了共享的資源和應用服務。於是有人在HA中涉及了“智慧”鎖,正在服務的一方只在發現心跳線全部斷開時才啟用磁碟鎖,平時就不上鎖了

什麼是redis腦裂?

如果在redis中,形式上就是有了兩個master,記住兩個master才是腦裂的前提。

哨兵(sentinel)模式下的腦裂

1個master與3個slave組成的哨兵模式(哨兵獨立部署於其它機器),剛開始時,2個應用伺服器server1、server2都連線在master上,如果master與slave及哨兵之間的網路發生故障,但是哨兵與slave之間通訊正常,這時3個slave其中1個經過哨兵投票後,提升為新master,如果恰好此時server1仍然連線的是舊的master,而server2連線到了新的master上。

資料就不一致了,基於setNX指令的分散式鎖,可能會拿到相同的鎖;基於incr生成的全域性唯一id,也可能出現重複。

叢集(cluster)模式下的腦裂

cluster模式下,這種情況要更復雜,例如叢集中有6組分片,每給分片節點都有1主1從,如果出現網路分割槽時,各種節點之間的分割槽組合都有可能。

手動解決問題

在正常情況下,如果master掛了,那麼寫入就會失敗,如果是手動解決,那麼人為會檢測master以及slave的網路狀況,然後視情況,如果是master掛了,重啟master,如果是master與slave之間的連線斷了,可以除錯網路,這樣雖然麻煩,但是是可以保證只有一個master的,所以只要認真負責,不會出現腦裂。

自動解決問題

Redis中有一個哨兵機制,哨兵機制的作用就是通過redis哨兵來檢測redis服務的狀態,如果一旦發現master掛了,就在slave中選舉新的master節點以實現故障自動轉移。

問題,就出現在這個自動故障轉移上,如果是哨兵和slave同時與master斷了聯絡,即哨兵可以監測到slave,但是監測不到master,而master雖然連線不上slave和哨兵,但是還是在正常執行,這樣如果哨兵因為監測不到master,認為它掛了,會在slave中選舉新的master,而有一部分應用仍然與舊的master互動。當舊的master與新的master重新建立連線,舊的master會同步新的master中的資料,而舊的master中的資料就會丟失。所以我認為redis腦裂就是自動故障轉移造成的。

總結梳理解決方案

如何解決腦裂?

設定每個master限制slave的數量

redis的配置檔案中,存在兩個引數

min-slaves-to-write 3
min-slaves-max-lag 10
  • 第一個參數列示連線到master的最少slave數量
  • 第二個參數列示slave連線到master的最大延遲時間

按照上面的配置,要求至少3個slave節點,且資料複製和同步的延遲不能超過10秒,否則的話master就會拒絕寫請求,配置了這兩個引數之後,如果發生叢集腦裂,原先的master節點接收到客戶端的寫入請求會拒絕,就可以減少資料同步之後的資料丟失。

注意:較新版本的redis.conf檔案中的引數變成了

min-replicas-to-write 3
min-replicas-max-lag 10

redis中的非同步複製情況下的資料丟失問題也能使用這兩個引數

總結

官方文件所言,redis並不能保證強一致性(Redis Cluster is not able to guarantee strong consistency. / In general Redis + Sentinel as a whole are a an eventually consistent system) 對於要求強一致性的應用,更應該傾向於相信RDBMS(傳統關係型資料庫)。

相關文章