Redis腦裂現象

語言: CN / TW / HK

持續創作,加速成長!這是我參與「掘金日新計劃 · 6 月更文挑戰」的第21天,點選檢視活動詳情

Redis腦裂現象

什麼是Redis的腦裂現象

當Redis主從叢集環境出現兩個主節點為客戶端提供服務,這時客戶端請求命令可能會發生資料丟失的情況。

腦裂出現的場景

場景一

主從哨兵叢集中如果當發生主從叢集切換時,那麼一定是超過預設quorum數量的哨兵和主庫連線超時了,這時哨兵叢集才會將主庫判斷為客觀下線,然後哨兵開始選舉新的主節點,進行故障轉移,轉移完畢後客戶端和新的主節點通訊恢復正常請求。

如果在哨兵進行選舉,故障轉移的過程中原主節點恢復和客戶端的通訊,那麼證明原主節點沒有真正的故障,這時客戶端依舊可以向原主節點正常通訊,這就是腦裂產生的第一個場景,示意圖如下

假故障:

1、同伺服器其它程序佔用大量CPU資源,導致主節點短時間無法響應心跳,CPU資源空閒後恢復正常。

2、主庫自身阻塞,如處理bigkey或者發生記憶體swap時,短時間無法響應心跳,阻塞解決後心跳恢復正常。

真故障:

1、伺服器宕機。

2、例項程序掛了。

場景二

網路分割槽,主節點和客戶端,哨兵和從庫分割為了兩個網路,主庫和客戶端處在一個網路中,從庫和哨兵在另外一個網路中,此時哨兵也會發起主從切換,出現兩個主節點的情況。

腦裂帶來的影響

腦裂出現後帶來最嚴重的後果就是資料丟失,為什麼會出現資料丟失的問題呢,主要原因是新主庫確定後會向所有的例項傳送slave of命令,讓所有例項重新進行全量同步,而全量同步首先就會將例項上的資料先清空,所以在主從同步期間在原主庫執行的命令將會被清空(上面場景二是同樣的道理,在網路分割槽恢復後原主節點將被降級為從節點,並且執行全量同步導致資料丟失),所以這就是資料丟失的具體原因。

如何應對腦裂

腦裂的主要原因其實就是哨兵叢集認為主節點已經出現故障了,重新選舉其它從節點作為主節點,而原主節點其實是假故障,從而導致短暫的出現兩個主節點,那麼在主從切換期間客戶端一旦給原主節點發送命令,就會造成資料丟失。

所以應對腦裂的解決辦法應該是去限制原主庫接收請求,Redis提供了兩個配置項。

  • min-slaves-to-write:與主節點通訊的從節點數量必須大於等於該值主節點,否則主節點拒絕寫入。

  • min-slaves-max-lag:主節點與從節點通訊的ACK訊息延遲必須小於該值,否則主節點拒絕寫入。

這兩個配置項必須同時滿足,不然主節點拒絕寫入。

在假故障期間滿足min-slaves-to-write和min-slaves-max-lag的要求,那麼主節點就會被禁止寫入,腦裂造成的資料丟失情況自然也就解決了。

腦裂可以完全解決嗎

通過上面的學習我們知道了腦裂出現的場景,帶來的問題,以及解決辦法,那麼腦裂問題可以完全被解決嗎?我們直接看下面的場景

為了防止腦裂我們將min-slaves-to-write設定為1,min-slaves-max-lag設定為12s,down-after-milliseconds哨兵判斷主節點客觀下線的限制為10s,主節點因為某些原因卡住了15s,導致哨兵叢集判斷主節點為主觀下線,主從切換,因為沒有一個從節點與主節點之間的資料複製在12s內,這樣就規避腦裂的情況。

但是我們再看另外一個場景

我們同樣將min-slaves-to-write設定為1,min-slaves-max-lag 設定為 15s,down-after-milliseconds哨兵判斷主節點客觀下線的限制為10s,哨兵主從切換需要 5s。主節點因為某些原因卡住了 12s,這時還會發生腦裂嗎?

主節點卡住12s這時哨兵叢集判斷主節點下線,同時哨兵叢集做主從切換需要5s,這就意味著主從切換過程中,主節點恢復執行,而min-slaves-max-lag設定為15s那麼主節點還是可寫,也就是說在12s~15s這期間如果有客戶端寫入原主節點,那麼這段時間的資料會丟失。

總結

Redis腦裂可以採用min-slaves-to-write和min-slaves-max-lag合理配置儘量規避,但無法徹底解決,Redis腦裂最本質的問題是主從叢集內部沒有共識演算法來維護多個節點的強一致性,它不像Zookeeper那樣,每次寫入必須大多數節點成功後才算成功,當腦裂發生時,Zookeeper節點被孤立,此時無法寫入大多數節點,寫請求會直接失敗,因此Zookeeper才能保證叢集的強一致性。