技術格言
世界上并沒有完美的程序,但是我們并不因此而沮喪步悠,因為寫程序就是一個不斷追求完美的過程签杈。
什么是腦裂
字面含義
首先,腦裂從字面上理解就是腦袋裂開了鼎兽,就是思想分家了答姥,就是有了兩個山頭,就是有了兩個主思想谚咬。
技術定義
在高可用集群中鹦付,當兩臺高可用服務器在指定的時間內,由于網絡的原因無法互相檢測到對方心跳而各自啟動故障轉移功能择卦,取得了資源以及服務的所有權敲长,而此時的兩臺高可用服務器對都還活著并作正常運行,這樣就會導致同一個服務在兩端同時啟動而發(fā)生沖突的嚴重問題互捌,最嚴重的就是兩臺主機同時占用一個VIP的地址(類似雙端導入概念)潘明,當用戶寫入數(shù)據(jù)的時候可能會分別寫入到兩端,這樣可能會導致服務器兩端的數(shù)據(jù)不一致或造成數(shù)據(jù)的丟失秕噪,這種情況就稱為裂腦钳降,也有的人稱之為分區(qū)集群或者大腦垂直分隔,互相接管對方的資源腌巾,出現(xiàn)多個Master的情況遂填,稱為腦裂。
腦裂導致的問題
引起數(shù)據(jù)的不完整性:在集群節(jié)點出現(xiàn)腦裂的時候澈蝙,如果外部無法判斷哪個為主節(jié)點吓坚,腦裂的集群都可以正常訪問的時候,這時候就會出現(xiàn)數(shù)據(jù)不完整的可能性灯荧。
- 服務異常:對外提供服務出現(xiàn)異常礁击。
導致裂腦發(fā)生的原因
優(yōu)先考慮心跳線路上的問題,在可能是心跳服務逗载,軟件層面的問題
-
1)高可用服務器對之間心跳線路故障哆窿,導致無法正常的通信。原因比如:
1——心跳線本身就壞了(包括斷了厉斟,老化)挚躯;
2——網卡以及相關驅動壞了,IP配置及沖突問題;
3——心跳線間連接的設備故障(交換機的故障或者是網卡的故障)擦秽;
4——仲裁的服務器出現(xiàn)問題码荔。
2)高可用服務器對上開啟了防火墻阻擋了心跳消息的傳輸漩勤;
3)高可用服務器對上的心跳網卡地址等信息配置的不正確,導致發(fā)送心跳失斔踅痢越败;
4)其他服務配置不當?shù)仍颍缧奶姆绞讲煌海奶鴱V播沖突眉尸,軟件出現(xiàn)了BUG等域蜗。
解決腦裂所出現(xiàn)的問題
添加冗余的心跳線巨双,盡量減少“腦裂”的機會
啟用磁盤鎖:在發(fā)生腦裂的時候可以協(xié)調控制對資源的訪問設置仲裁機制
實際的生產環(huán)境中,我們可以從以下幾個方面來防止裂腦的發(fā)生:
1)同時使用串行電纜和以太網電纜連接霉祸,同時用兩條心跳線路筑累,這樣一條線路壞了,另一個線路還是好的丝蹭,依然能傳送消息(推薦的)
2)檢測到裂腦的時候強行的關閉一個心跳節(jié)點(需要特殊的節(jié)點支持慢宗,如stonith,fence)奔穿,相當于程序上備節(jié)點發(fā)現(xiàn)心跳線故障镜沽,發(fā)送關機命令到主節(jié)點。
-
3)多節(jié)點集群中贱田,可以通過增加仲裁的機制缅茉,確定誰該獲得資源,這里面有幾個參考的思路:
1——增加一個仲裁機制男摧。例如設置參考的IP蔬墩,當心跳完全斷開的時候,2個節(jié)點各自都ping一下參考的IP耗拓,不同則表明斷點就出現(xiàn)在本段拇颅,這樣就主動放棄競爭,讓能夠ping通參考IP的一端去接管服務乔询。
2——通過第三方軟件仲裁誰該獲得資源樟插,這個在阿里有類似的軟件應用
4)做好對裂腦的監(jiān)控報警(如郵件以及手機短信等),在問題發(fā)生的時候能夠人為的介入到仲裁竿刁,降低損失黄锤。當然,在實施高可用方案的時候们妥,要根據(jù)業(yè)務的實際需求確定是否能夠容忍這樣的損失猜扮。對于一般的網站業(yè)務,這個損失是可控的(公司使用)
5)啟用磁盤鎖监婶。正在服務一方鎖住共享磁盤旅赢,腦裂發(fā)生的時候齿桃,讓對方完全搶不走共享的磁盤資源。但使用鎖磁盤也會有一個不小的問題煮盼,如果占用共享盤的乙方不主動解鎖短纵,另一方就永遠得不到共享磁盤。現(xiàn)實中介入服務節(jié)點突然死機或者崩潰僵控,另一方就永遠不可能執(zhí)行解鎖命令香到。后備節(jié)點也就截關不了共享的資源和應用服務。于是有人在HA中涉及了“智能”鎖报破,正在服務的一方只在發(fā)現(xiàn)心跳線全部斷開時才啟用磁盤鎖悠就,平時就不上鎖了
什么是redis腦裂?
如果在redis中充易,形式上就是有了兩個master梗脾,記住兩個master才是腦裂的前提。
哨兵(sentinel)模式下的腦裂
1個master與3個slave組成的哨兵模式(哨兵獨立部署于其它機器)盹靴,剛開始時炸茧,2個應用服務器server1、server2都連接在master上稿静,如果master與slave及哨兵之間的網絡發(fā)生故障梭冠,但是哨兵與slave之間通訊正常,這時3個slave其中1個經過哨兵投票后改备,提升為新master控漠,如果恰好此時server1仍然連接的是舊的master,而server2連接到了新的master上绍妨。
數(shù)據(jù)就不一致了润脸,基于setNX指令的分布式鎖,可能會拿到相同的鎖他去;基于incr生成的全局唯一id毙驯,也可能出現(xiàn)重復。
集群(cluster)模式下的腦裂
cluster模式下灾测,這種情況要更復雜爆价,例如集群中有6組分片,每給分片節(jié)點都有1主1從媳搪,如果出現(xiàn)網絡分區(qū)時铭段,各種節(jié)點之間的分區(qū)組合都有可能。
手動解決問題
在正常情況下秦爆,如果master掛了序愚,那么寫入就會失敗,如果是手動解決等限,那么人為會檢測master以及slave的網絡狀況爸吮,然后視情況芬膝,如果是master掛了,重啟master形娇,如果是master與slave之間的連接斷了锰霜,可以調試網絡,這樣雖然麻煩桐早,但是是可以保證只有一個master的癣缅,所以只要認真負責,不會出現(xiàn)腦裂哄酝。
自動解決問題
Redis中有一個哨兵機制友存,哨兵機制的作用就是通過redis哨兵來檢測redis服務的狀態(tài),如果一旦發(fā)現(xiàn)master掛了炫七,就在slave中選舉新的master節(jié)點以實現(xiàn)故障自動轉移爬立。
問題钾唬,就出現(xiàn)在這個自動故障轉移上万哪,如果是哨兵和slave同時與master斷了聯(lián)系,即哨兵可以監(jiān)測到slave抡秆,但是監(jiān)測不到master奕巍,而master雖然連接不上slave和哨兵,但是還是在正常運行儒士,這樣如果哨兵因為監(jiān)測不到master的止,認為它掛了,會在slave中選舉新的master着撩,而有一部分應用仍然與舊的master交互诅福。當舊的master與新的master重新建立連接,舊的master會同步新的master中的數(shù)據(jù)拖叙,而舊的master中的數(shù)據(jù)就會丟失氓润。所以我認為redis腦裂就是自動故障轉移造成的。
總結梳理解決方案
如何解決腦裂薯鳍?
設置每個master限制slave的數(shù)量
redis的配置文件中咖气,存在兩個參數(shù)
min-slaves-to-write 3
min-slaves-max-lag 10
- 第一個參數(shù)表示連接到master的最少slave數(shù)量
- 第二個參數(shù)表示slave連接到master的最大延遲時間
按照上面的配置,要求至少3個slave節(jié)點挖滤,且數(shù)據(jù)復制和同步的延遲不能超過10秒崩溪,否則的話master就會拒絕寫請求,配置了這兩個參數(shù)之后斩松,如果發(fā)生集群腦裂伶唯,原先的master節(jié)點接收到客戶端的寫入請求會拒絕,就可以減少數(shù)據(jù)同步之后的數(shù)據(jù)丟失惧盹。
注意:較新版本的redis.conf文件中的參數(shù)變成了
min-replicas-to-write 3
min-replicas-max-lag 10
redis中的異步復制情況下的數(shù)據(jù)丟失問題也能使用這兩個參數(shù)
總結
官方文檔所言乳幸,redis并不能保證強一致性(Redis Cluster is not able to guarantee strong consistency. / In general Redis + Sentinel as a whole are a an eventually consistent system) 對于要求強一致性的應用奋救,更應該傾向于相信RDBMS(傳統(tǒng)關系型數(shù)據(jù)庫)。