1啥辨、腦裂和假死
1.1 腦裂
官方定義:當一個集群的不同部分在同一時間都認為自己是活動的時候涡匀,我們就可以將這個現(xiàn)象稱為腦裂癥狀。通俗的說溉知,就是比如當你的 cluster 里面有兩個結(jié)點陨瘩,它們都知道在這個 cluster 里需要選舉出一個 master。那么當它們兩之間的通信完全沒有問題的時候级乍,就會達成共識舌劳,選出其中一個作為 master。但是如果它們之間的通信出了問題玫荣,那么兩個結(jié)點都會覺得現(xiàn)在沒有 master甚淡,所以每個都把自己選舉成 master。于是 cluster 里面就會有兩個 master捅厂。舉例:
UserA和UserB分別將自己的信息注冊在RouterA和RouterB中贯卦。RouterA和RouterB使用數(shù)據(jù)同步(2PC),來同步信息焙贷。那么當UserA想要向UserB發(fā)送一個消息的時候撵割,需要現(xiàn)在RouterA中查詢出UserA到UserB的消息路由路徑,然后再交付給相應的路徑進行路由辙芍。
當腦裂發(fā)生的時候啡彬,相當RouterA和RouterB直接的聯(lián)系丟失了,RouterA認為整個系統(tǒng)中只有它一個Router,RouterB也是這樣認為的庶灿。那么相當于RouterA中沒有UserB的信息注簿,RouterB中沒有UserA的信息了,此時UserA再發(fā)送消息給UserB的時候跳仿,RouterA會認為UserB已經(jīng)離線了,然后將該信息進行離線持久化捐晶,這樣整個網(wǎng)絡的路由是不是就亂掉了菲语。
對于Zookeeper來說有一個很重要的問題,就是到底是根據(jù)一個什么樣的情況來判斷一個節(jié)點死亡down掉了惑灵。 在分布式系統(tǒng)中這些都是有監(jiān)控者來判斷的山上,但是監(jiān)控者也很難判定其他的節(jié)點的狀態(tài),唯一一個可靠的途徑就是心跳英支,Zookeeper也是使用心跳來判斷客戶端是否仍然活著佩憾,但是使用心跳機制來判斷節(jié)點的存活狀態(tài)也帶來了假死問題。
1.2 假死
ZooKeeper每個節(jié)點都嘗試注冊一個象征master的臨時節(jié)點干花,其他沒有注冊成功的則稱為slaver妄帘,并且通過watch機制監(jiān)控著master所創(chuàng)建的臨時節(jié)點,Zookeeper通過內(nèi)部心跳機制來確定master的狀態(tài)池凄,一旦master出現(xiàn)意外Zookeeper能很快獲悉并且通知其他的slaver抡驼,其他slaver在之后作出相關(guān)反應。這樣就完成了一個切換肿仑。
這種模式也是比較通用的模式致盟,基本大部分都是這樣實現(xiàn)的,但是這里面有個很嚴重的問題尤慰,如果注意不到會導致短暫的時間內(nèi)系統(tǒng)出現(xiàn)腦裂馏锡,因為心跳出現(xiàn)超時可能是master掛了,但是也可能是master伟端,zookeeper之間網(wǎng)絡出現(xiàn)了問題杯道,也同樣可能導致。這種情況就是假死荔泳,master并未死掉蕉饼,但是與ZooKeeper之間的網(wǎng)絡出現(xiàn)問題導致Zookeeper認為其掛掉了然后通知其他節(jié)點進行切換,這樣slaver中就有一個成為了master玛歌,但是原本的master并未死掉昧港,這時候client也獲得master切換的消息,但是仍然會有一些延時支子,zookeeper需要通訊需要一個一個通知创肥,這時候整個系統(tǒng)就很混亂可能有一部分client已經(jīng)通知到了連接到新的master上去了,有的client仍然連接在老的master上如果同時有兩個client需要對master的同一個數(shù)據(jù)更新并且剛好這兩個client此刻分別連接在新老的master上,就會出現(xiàn)很嚴重問題叹侄。
1.3 總結(jié)
假死:由于心跳超時(網(wǎng)絡原因?qū)е碌模┱J為master死了巩搏,但其實master還存活著。腦裂:由于假死會發(fā)起新的master選舉趾代,選舉出一個新的master贯底,但舊的master網(wǎng)絡又通了,導致出現(xiàn)了兩個master 撒强,有的客戶端連接到老的master 有的客戶端鏈接到新的master禽捆。
2、Zookeeper的解決方案
要解決Split-Brain的問題飘哨,一般有3種方式:
- Quorums(?kw?r?m 法定人數(shù)) :比如3個節(jié)點的集群胚想,Quorums = 2, 也就是說集群可以容忍1個節(jié)點失效,這時候還能選舉出1個lead芽隆,集群還可用浊服。比如4個節(jié)點的集群,它的Quorums = 3胚吁,Quorums要超過3牙躺,相當于集群的容忍度還是1,如果2個節(jié)點失效囤采,那么整個集群還是無效的
- Redundant communications:冗余通信的方式述呐,集群中采用多種通信方式,防止一種通信方式失效導致集群中的節(jié)點無法通信蕉毯。
- Fencing, 共享資源的方式:比如能看到共享資源就表示在集群中乓搬,能夠獲得共享資源的說的就是Leader,看不到共享資源的代虾,就不在集群中进肯。
ZooKeeper默認采用了Quorums這種方式,即只有集群中超過半數(shù)節(jié)點投票才能選舉出Leader棉磨。這樣的方式可以確保leader的唯一性,要么選出唯一的一個leader,要么選舉失敗江掩。在ZooKeeper中Quorums有2個作用:
- 集群中最少的節(jié)點數(shù)用來選舉Leader保證集群可用:通知客戶端數(shù)據(jù)已經(jīng)安全保存前集群中最少數(shù)量的節(jié)點數(shù)已經(jīng)保存了該數(shù)據(jù)。一旦這些節(jié)點保存了該數(shù)據(jù)乘瓤,客戶端將被通知已經(jīng)安全保存了环形,可以繼續(xù)其他任務。而集群中剩余的節(jié)點將會最終也保存了該數(shù)據(jù)衙傀。
- 假設某個leader假死抬吟,其余的followers選舉出了一個新的leader。這時统抬,舊的leader復活并且仍然認為自己是leader火本,這個時候它向其他followers發(fā)出寫請求也是會被拒絕的危队。因為每當新leader產(chǎn)生時,會生成一個epoch钙畔,這個epoch是遞增的茫陆,followers如果確認了新的leader存在,知道其epoch擎析,就會拒絕epoch小于現(xiàn)任leader epoch的所有請求簿盅。那有沒有follower不知道新的leader存在呢,有可能揍魂,但肯定不是大多數(shù)挪鹏,否則新leader無法產(chǎn)生。Zookeeper的寫也遵循quorum機制愉烙,因此,得不到大多數(shù)支持的寫是無效的解取,舊leader即使各種認為自己是leader步责,依然沒有什么作用。
3禀苦、總結(jié)
總結(jié)一下就是蔓肯,通過Quorums機制來防止腦裂和假死,當leader掛掉之后振乏,可以重新選舉出新的leader節(jié)點使整個集群達成一致蔗包;當出現(xiàn)假死現(xiàn)象時,通過epoch大小來拒絕舊的leader發(fā)起的請求慧邮,在前面也已經(jīng)講到過调限,這個時候,重新恢復通信的老的leader節(jié)點會進入恢復模式误澳,與新的leader節(jié)點做數(shù)據(jù)同步耻矮,perfect。
感謝你看到這里忆谓,我是程序員麥冬 裆装,一個java開發(fā)從業(yè)者,深耕行業(yè)六年了倡缠,每天都會分享java相關(guān)技術(shù)文章或行業(yè)資訊
歡迎大家關(guān)注和轉(zhuǎn)發(fā)文章哨免,后期還有福利贈送!