腦裂(split-brain)就是「大腦分裂」,也就是原本一個「大腦」被拆分了兩個或多個「大腦」,咱們都知道,若是一我的有多個大腦,而且相互獨立的話,那麼會致使人體「手舞足蹈」,「不聽使喚」。算法
腦裂一般會出如今集羣環境中,好比ElasticSearch、Zookeeper集羣,而這些集羣環境有一個統一的特色,就是它們有一個大腦,好比ElasticSearch集羣中有Master節點,Zookeeper集羣中有Leader節點。編程
本篇文章着重來給你們講一下Zookeeper中的腦裂問題,以及是若是解決腦裂問題的。服務器
(想自學習編程的小夥伴請搜索圈T社區,更多行業相關資訊更有行業相關免費視頻教程。徹底免費哦!)網絡
對於一個集羣,想要提升這個集羣的可用性,一般會採用多機房部署,好比如今有一個由6臺zkServer所組成的一個集羣,部署在了兩個機房:
正常狀況下,此集羣只會有一個Leader,那麼若是機房之間的網絡斷了以後,兩個機房內的zkServer仍是能夠相互通訊的,若是不考慮過半機制,那麼就會出現每一個機房內部都將選出一個Leader。
這就至關於本來一個集羣,被分紅了兩個集羣,出現了兩個「大腦」,這就是腦裂。學習
對於這種狀況,咱們也能夠看出來,本來應該是統一的一個集羣對外提供服務的,如今變成了兩個集羣同時對外提供服務,若是過了一會,斷了的網絡忽然聯通了,那麼此時就會出現問題了,兩個集羣剛剛都對外提供服務了,數據該怎麼合併,數據衝突怎麼解決等等問題。this
剛剛在說明腦裂場景時,有一個前提條件就是沒有考慮過半機制,因此實際上Zookeeper集羣中是不會出現腦裂問題的,而不會出現的緣由就跟過半機制有關。spa
在領導者選舉的過程當中,若是某臺zkServer得到了超過半數的選票,則此zkServer就能夠成爲Leader了。3d
過半機制的源碼實現其實很是簡單:code
public class QuorumMaj implements QuorumVerifier { private static final Logger LOG = LoggerFactory.getLogger(QuorumMaj.class); int half; // n表示集羣中zkServer的個數(準確的說是參與者的個數,參與者不包括觀察者節點) public QuorumMaj(int n){ this.half = n/2; } // 驗證是否符合過半機制 public boolean containsQuorum(Set<Long> set){ // half是在構造方法裏賦值的 // set.size()表示某臺zkServer得到的票數 return (set.size() > half); } }
你們仔細看一下上面方法中的註釋,核心代碼就是下面兩行:視頻
this.half = n/2; return (set.size() > half);
舉個簡單的例子:
若是如今集羣中有5臺zkServer,那麼half=5/2=2,那麼也就是說,領導者選舉的過程當中至少要有三臺zkServer投了同一個zkServer,纔會符合過半機制,才能選出來一個Leader。
那麼有一個問題咱們想一下,選舉的過程當中爲何必定要有一個過半機制驗證?
由於這樣不須要等待全部zkServer都投了同一個zkServer就能夠選舉出來一個Leader了,這樣比較快,因此叫快速領導者選舉算法唄。
那麼再來想一個問題,過半機制中爲何是大於,而不是大於等於呢?
這就是更腦裂問題有關係了,好比回到上文出現腦裂問題的場景:
當機房中間的網絡斷掉以後,機房1內的三臺服務器會進行領導者選舉,可是此時過半機制的條件是set.size() > 3,也就是說至少要4臺zkServer才能選出來一個Leader,因此對於機房1來講它不能選出一個Leader,一樣機房2也不能選出一個Leader,這種狀況下整個集羣當機房間的網絡斷掉後,整個集羣將沒有Leader。
而若是過半機制的條件是set.size() >= 3,那麼機房1和機房2都會選出一個Leader,這樣就出現了腦裂。因此咱們就知道了,爲何過半機制中是大於,而不是大於等於。就是爲了防止腦裂。
若是假設咱們如今只有5臺機器,也部署在兩個機房:
此時過半機制的條件是set.size() > 2,也就是至少要3臺服務器才能選出一個Leader,此時機房件的網絡斷開了,對於機房1來講是沒有影響的,Leader依然仍是Leader,對於機房2來講是選不出來Leader的,此時整個集羣中只有一個Leader。
因此,咱們能夠總結得出,有了過半機制,對於一個Zookeeper集羣,要麼沒有Leader,要沒只有1個Leader,這樣就避免了腦裂問題。
有痛點纔有創新,一個技術確定都是爲了解決某個痛點纔出現的。