轉(zhuǎn)載:https://www.cnblogs.com/kevingrace/p/12433503.html
關(guān)于集群中的"腦裂"問題掠械,之前已經(jīng)在這里詳細介紹過绪爸,下面重點說下Zookeeper腦裂問題的處理辦法到逊。ooKeeper是用來協(xié)調(diào)(同步)分布式進程的服務(wù)用狱,提供了一個簡單高性能的協(xié)調(diào)內(nèi)核贴膘,用戶可以在此之上構(gòu)建更多復雜的分布式協(xié)調(diào)功能译仗。腦裂通常會出現(xiàn)在集群環(huán)境中抬虽,比如ElasticSearch、Zookeeper集群纵菌,而這些集群環(huán)境有一個統(tǒng)一的特點阐污,就是它們有一個大腦,比如ElasticSearch集群中有Master節(jié)點咱圆,Zookeeper集群中有Leader節(jié)點笛辟。
一、 Zookeeper 集群節(jié)點為什么要部署成奇數(shù)
zookeeper容錯指的是:當宕掉幾個zookeeper節(jié)點服務(wù)器之后序苏,剩下的個數(shù)必須大于宕掉的個數(shù)手幢,也就是剩下的節(jié)點服務(wù)數(shù)必須大于n/2,這樣zookeeper集群才可以繼續(xù)使用忱详,無論奇偶數(shù)都可以選舉leader围来。例如5臺zookeeper節(jié)點機器最多宕掉2臺,還可以繼續(xù)使用匈睁,因為剩下3臺大于5/2管钳。至于為什么最好為奇數(shù)個節(jié)點?這樣是為了以最大容錯服務(wù)器個數(shù)的條件下软舌,能節(jié)省資源才漆。比如,最大容錯為2的情況下佛点,對應(yīng)的zookeeper服務(wù)數(shù)醇滥,奇數(shù)為5黎比,而偶數(shù)為6,也就是6個zookeeper服務(wù)的情況下最多能宕掉2個服務(wù)鸳玩,所以從節(jié)約資源的角度看阅虫,沒必要部署6(偶數(shù))個zookeeper服務(wù)節(jié)點。
zookeeper集群有這樣一個特性:集群中只要有過半的機器是正常工作的不跟,那么整個集群對外就是可用的颓帝。也就是說如果有2個zookeeper節(jié)點,那么只要有1個zookeeper節(jié)點死了窝革,那么zookeeper服務(wù)就不能用了购城,因為1沒有過半,所以2個zookeeper的死亡容忍度為0虐译;同理瘪板,要是有3個zookeeper,一個死了漆诽,還剩下2個正常的侮攀,過半了,所以3個zookeeper的容忍度為1厢拭;同理也可以多列舉幾個:2->0; 3->1; 4->1; 5->2; 6->2 就會發(fā)現(xiàn)一個規(guī)律兰英,2n和2n-1的容忍度是一樣的,都是n-1供鸠,所以為了更加高效畦贸,何必增加那一個不必要的zookeeper呢。所以說回季,根據(jù)以上可以得出結(jié)論:從資源節(jié)省的角度來考慮家制,zookeeper集群的節(jié)點最好要部署成奇數(shù)個正林!
二泡一、 Zookeeper 集群中的"腦裂"場景說明
對于一個集群,想要提高這個集群的可用性觅廓,通常會采用多機房部署鼻忠,比如現(xiàn)在有一個由6臺zkServer所組成的一個集群,部署在了兩個機房:
正常情況下杈绸,此集群只會有一個Leader帖蔓,那么如果機房之間的網(wǎng)絡(luò)斷了之后,兩個機房內(nèi)的zkServer還是可以相互通信的瞳脓,如果不考慮過半機制塑娇,那么就會出現(xiàn)每個機房內(nèi)部都將選出一個Leader。
這就相當于原本一個集群劫侧,被分成了兩個集群埋酬,出現(xiàn)了兩個"大腦",這就是所謂的"腦裂"現(xiàn)象。對于這種情況芦瘾,其實也可以看出來富纸,原本應(yīng)該是統(tǒng)一的一個集群對外提供服務(wù)的,現(xiàn)在變成了兩個集群同時對外提供服務(wù)珍特,如果過了一會祝峻,斷了的網(wǎng)絡(luò)突然聯(lián)通了,那么此時就會出現(xiàn)問題了扎筒,兩個集群剛剛都對外提供服務(wù)了莱找,數(shù)據(jù)該怎么合并,數(shù)據(jù)沖突怎么解決等等問題砸琅。剛剛在說明腦裂場景時有一個前提條件就是沒有考慮過半機制宋距,所以實際上Zookeeper集群中是不會輕易出現(xiàn)腦裂問題的,原因在于過半機制症脂。
zookeeper的過半機制:在領(lǐng)導者選舉的過程中谚赎,如果某臺zkServer獲得了超過半數(shù)的選票,則此zkServer就可以成為Leader了诱篷。舉個簡單的例子:如果現(xiàn)在集群中有5臺zkServer壶唤,那么half=5/2=2,那么也就是說棕所,領(lǐng)導者選舉的過程中至少要有三臺zkServer投了同一個zkServer闸盔,才會符合過半機制,才能選出來一個Leader琳省。
那么zookeeper選舉的過程中為什么一定要有一個過半機制驗證迎吵?
因為這樣不需要等待所有zkServer都投了同一個zkServer就可以選舉出來一個Leader了,這樣比較快针贬,所以叫快速領(lǐng)導者選舉算法击费。
zookeeper過半機制中為什么是大于,而不是大于等于桦他?這就是更腦裂問題有關(guān)系了蔫巩,比如回到上文出現(xiàn)腦裂問題的場景 [如上圖1]:當機房中間的網(wǎng)絡(luò)斷掉之后,機房1內(nèi)的三臺服務(wù)器會進行領(lǐng)導者選舉快压,但是此時過半機制的條件是 "節(jié)點數(shù) > 3"圆仔,也就是說至少要4臺zkServer才能選出來一個Leader,所以對于機房1來說它不能選出一個Leader蔫劣,同樣機房2也不能選出一個Leader坪郭,這種情況下整個集群當機房間的網(wǎng)絡(luò)斷掉后,整個集群將沒有Leader脉幢。而如果過半機制的條件是 "節(jié)點數(shù) >= 3"歪沃,那么機房1和機房2都會選出一個Leader信姓,這樣就出現(xiàn)了腦裂。這就可以解釋為什么過半機制中是大于而不是大于等于绸罗,目的就是為了防止腦裂意推。
如果假設(shè)我們現(xiàn)在只有5臺機器,也部署在兩個機房:
此時過半機制的條件是 "節(jié)點數(shù) > 2"珊蟀,也就是至少要3臺服務(wù)器才能選出一個Leader菊值,此時機房件的網(wǎng)絡(luò)斷開了,對于機房1來說是沒有影響的育灸,Leader依然還是Leader腻窒,對于機房2來說是選不出來Leader的,此時整個集群中只有一個Leader磅崭。因此總結(jié)得出儿子,有了過半機制,對于一個Zookeeper集群來說砸喻,要么沒有Leader柔逼,要么只有1個Leader,這樣zookeeper也就能避免了腦裂問題割岛。
三愉适、 Zookeeper 集群"腦裂"問題處理
1. 什么是腦裂?
簡單點來說癣漆,腦裂(Split-Brain) 就是比如當你的 cluster 里面有兩個節(jié)點维咸,它們都知道在這個 cluster 里需要選舉出一個 master。那么當它們兩個之間的通信完全沒有問題的時候惠爽,就會達成共識癌蓖,選出其中一個作為 master。但是如果它們之間的通信出了問題婚肆,那么兩個結(jié)點都會覺得現(xiàn)在沒有 master租副,所以每個都把自己選舉成 master,于是 cluster 里面就會有兩個 master旬痹。
對于Zookeeper來說有一個很重要的問題附井,就是到底是根據(jù)一個什么樣的情況來判斷一個節(jié)點死亡down掉了讨越?在分布式系統(tǒng)中這些都是有監(jiān)控者來判斷的两残,但是監(jiān)控者也很難判定其他的節(jié)點的狀態(tài),唯一一個可靠的途徑就是心跳把跨,Zookeeper也是使用心跳來判斷客戶端是否仍然活著人弓。
使用ZooKeeper來做Leader HA基本都是同樣的方式:每個節(jié)點都嘗試注冊一個象征leader的臨時節(jié)點,其他沒有注冊成功的則成為follower着逐,并且通過watch機制 (這里有介紹) 監(jiān)控著leader所創(chuàng)建的臨時節(jié)點崔赌,Zookeeper通過內(nèi)部心跳機制來確定leader的狀態(tài)意蛀,一旦leader出現(xiàn)意外Zookeeper能很快獲悉并且通知其他的follower,其他flower在之后作出相關(guān)反應(yīng)健芭,這樣就完成了一個切換县钥,這種模式也是比較通用的模式,基本大部分都是這樣實現(xiàn)的慈迈。但是這里面有個很嚴重的問題若贮,如果注意不到會導致短暫的時間內(nèi)系統(tǒng)出現(xiàn)腦裂,因為心跳出現(xiàn)超時可能是leader掛了痒留,但是也可能是zookeeper節(jié)點之間網(wǎng)絡(luò)出現(xiàn)了問題谴麦,導致leader假死的情況,leader其實并未死掉伸头,但是與ZooKeeper之間的網(wǎng)絡(luò)出現(xiàn)問題導致Zookeeper認為其掛掉了然后通知其他節(jié)點進行切換匾效,這樣follower中就有一個成為了leader,但是原本的leader并未死掉恤磷,這時候client也獲得leader切換的消息面哼,但是仍然會有一些延時,zookeeper需要通訊需要一個一個通知扫步,這時候整個系統(tǒng)就很混亂可能有一部分client已經(jīng)通知到了連接到新的leader上去了精绎,有的client仍然連接在老的leader上,如果同時有兩個client需要對leader的同一個數(shù)據(jù)更新锌妻,并且剛好這兩個client此刻分別連接在新老的leader上代乃,就會出現(xiàn)很嚴重問題。
這里做下小總結(jié):
假死:由于心跳超時(網(wǎng)絡(luò)原因?qū)е碌模┱J為leader死了仿粹,但其實leader還存活著搁吓。
腦裂:由于假死會發(fā)起新的leader選舉,選舉出一個新的leader吭历,但舊的leader網(wǎng)絡(luò)又通了堕仔,導致出現(xiàn)了兩個leader ,有的客戶端連接到老的leader晌区,而有的客戶端則連接到新的leader摩骨。
2. zookeeper腦裂是什么原因?qū)е碌模?/strong>
主要原因是Zookeeper集群和Zookeeper client判斷超時并不能做到完全同步,也就是說可能一前一后朗若,如果是集群先于client發(fā)現(xiàn)恼五,那就會出現(xiàn)上面的情況。同時哭懈,在發(fā)現(xiàn)并切換后通知各個客戶端也有先后快慢灾馒。一般出現(xiàn)這種情況的幾率很小,需要leader節(jié)點與Zookeeper集群網(wǎng)絡(luò)斷開遣总,但是與其他集群角色之間的網(wǎng)絡(luò)沒有問題睬罗,還要滿足上面那些情況轨功,但是一旦出現(xiàn)就會引起很嚴重的后果,數(shù)據(jù)不一致容达。
3. zookeeper是如何解決"腦裂"問題的古涧?
要解決Split-Brain腦裂的問題,一般有下面幾種種方法:
Quorums (法定人數(shù)) 方式: 比如3個節(jié)點的集群花盐,Quorums = 2, 也就是說集群可以容忍1個節(jié)點失效蒿褂,這時候還能選舉出1個lead,集群還可用卒暂。比如4個節(jié)點的集群啄栓,它的Quorums = 3,Quorums要超過3也祠,相當于集群的容忍度還是1昙楚,如果2個節(jié)點失效,那么整個集群還是無效的诈嘿。這是zookeeper防止"腦裂"默認采用的方法堪旧。
采用Redundant communications (冗余通信)方式:集群中采用多種通信方式,防止一種通信方式失效導致集群中的節(jié)點無法通信奖亚。
Fencing (共享資源) 方式:比如能看到共享資源就表示在集群中淳梦,能夠獲得共享資源的鎖的就是Leader,看不到共享資源的昔字,就不在集群中爆袍。
仲裁機制方式。
啟動磁盤鎖定方式作郭。
要想避免zookeeper"腦裂"情況其實也很簡單陨囊,在follower節(jié)點切換的時候不在檢查到老的leader節(jié)點出現(xiàn)問題后馬上切換,而是在休眠一段足夠的時間夹攒,確保老的leader已經(jīng)獲知變更并且做了相關(guān)的shutdown清理工作了然后再注冊成為master就能避免這類問題了蜘醋,這個休眠時間一般定義為與zookeeper定義的超時時間就夠了,但是這段時間內(nèi)系統(tǒng)可能是不可用的咏尝,但是相對于數(shù)據(jù)不一致的后果來說還是值得的压语。
1、zooKeeper默認采用了Quorums這種方式來防止"腦裂"現(xiàn)象编检。即只有集群中超過半數(shù)節(jié)點投票才能選舉出Leader胎食。這樣的方式可以確保leader的唯一性,要么選出唯一的一個leader,要么選舉失敗。在zookeeper中Quorums作用如下:
**1] **集群中最少的節(jié)點數(shù)用來選舉leader保證集群可用蒙谓。
2] 通知客戶端數(shù)據(jù)已經(jīng)安全保存前集群中最少數(shù)量的節(jié)點數(shù)已經(jīng)保存了該數(shù)據(jù)斥季。一旦這些節(jié)點保存了該數(shù)據(jù)训桶,客戶端將被通知已經(jīng)安全保存了累驮,可以繼續(xù)其他任務(wù)酣倾。而集群中剩余的節(jié)點將會最終也保存了該數(shù)據(jù)。
假設(shè)某個leader假死谤专,其余的followers選舉出了一個新的leader躁锡。這時,舊的leader復活并且仍然認為自己是leader置侍,這個時候它向其他followers發(fā)出寫請求也是會被拒絕的映之。因為每當新leader產(chǎn)生時,會生成一個epoch標號(標識當前屬于那個leader的統(tǒng)治時期)蜡坊,這個epoch是遞增的杠输,followers如果確認了新的leader存在,知道其epoch秕衙,就會拒絕epoch小于現(xiàn)任leader epoch的所有請求蠢甲。那有沒有follower不知道新的leader存在呢,有可能据忘,但肯定不是大多數(shù)鹦牛,否則新leader無法產(chǎn)生。Zookeeper的寫也遵循quorum機制勇吊,因此曼追,得不到大多數(shù)支持的寫是無效的,舊leader即使各種認為自己是leader汉规,依然沒有什么作用礼殊。
zookeeper除了可以采用上面默認的Quorums方式來避免出現(xiàn)"腦裂",還可以可采用下面的預(yù)防措施:
2针史、添加冗余的心跳線膏燕,例如雙線條線,盡量減少“裂腦”發(fā)生機會悟民。
3坝辫、啟用磁盤鎖。正在服務(wù)一方鎖住共享磁盤射亏,"裂腦"發(fā)生時近忙,讓對方完全"搶不走"共享磁盤資源。但使用鎖磁盤也會有一個不小的問題智润,如果占用共享盤的一方不主動"解鎖"及舍,另一方就永遠得不到共享磁盤。現(xiàn)實中假如服務(wù)節(jié)點突然死機或崩潰窟绷,就不可能執(zhí)行解鎖命令锯玛。后備節(jié)點也就接管不了共享資源和應(yīng)用服務(wù)。于是有人在HA中設(shè)計了"智能"鎖。即正在服務(wù)的一方只在發(fā)現(xiàn)心跳線全部斷開(察覺不到對端)時才啟用磁盤鎖攘残。平時就不上鎖了拙友。
4、設(shè)置仲裁機制歼郭。例如設(shè)置參考IP(如網(wǎng)關(guān)IP)遗契,當心跳線完全斷開時,2個節(jié)點都各自ping一下 參考IP病曾,不通則表明斷點就出在本端牍蜂,不僅"心跳"、還兼對外"服務(wù)"的本端網(wǎng)絡(luò)鏈路斷了泰涂,即使啟動(或繼續(xù))應(yīng)用服務(wù)也沒有用了鲫竞,那就主動放棄競爭,讓能夠ping通參考IP的一端去起服務(wù)逼蒙。更保險一些贡茅,ping不通參考IP的一方干脆就自我重啟,以徹底釋放有可能還占用著的那些共享資源其做。