脑裂(split-brain)就是“大脑分裂”,也就是原本一个“大脑”被拆分了两个或多个“大脑”,咱们都知道,若是一我的有多个大脑,而且相互独立的话,那么会致使人体“手舞足蹈”,“不听使唤”。java
脑裂一般会出如今集群环境中,好比ElasticSearch、Zookeeper集群,而这些集群环境有一个统一的特色,就是它们有一个大脑,好比ElasticSearch集群中有Master节点,Zookeeper集群中有Leader节点。算法
本篇文章着重来给你们讲一下Zookeeper中的脑裂问题,以及是若是解决脑裂问题的。服务器
对于一个集群,想要提升这个集群的可用性,一般会采用多机房部署,好比如今有一个由6台zkServer所组成的一个集群,部署在了两个机房: 微信
正常状况下,此集群只会有一个Leader,那么若是机房之间的网络断了以后,两个机房内的zkServer仍是能够相互通讯的,若是不考虑过半机制,那么就会出现每一个机房内部都将选出一个Leader。 网络
这就至关于本来一个集群,被分红了两个集群,出现了两个“大脑”,这就是脑裂。学习
对于这种状况,咱们也能够看出来,本来应该是统一的一个集群对外提供服务的,如今变成了两个集群同时对外提供服务,若是过了一会,断了的网络忽然联通了,那么此时就会出现问题了,两个集群刚刚都对外提供服务了,数据该怎么合并,数据冲突怎么解决等等问题。this
刚刚在说明脑裂场景时,有一个前提条件就是没有考虑过半机制,因此实际上Zookeeper集群中是不会出现脑裂问题的,而不会出现的缘由就跟过半机制有关。3d
在领导者选举的过程当中,若是某台zkServer得到了超过半数的选票,则此zkServer就能够成为Leader了。code
过半机制的源码实现其实很是简单:blog
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,这样就避免了脑裂问题。
有痛点才有创新,一个技术确定都是为了解决某个痛点才出现的。
请帮忙转发一下,若是想第一时间学习更多的精彩的内容,请关注微信公众号:1点25