ZooKeeper 的节点通常可以作为分布式锁来使用。比如可以多个服务对同时竞争申请一个节点 “/test/lock”,创建成功的服务获取到这个锁,其他没创建成功的监听这个锁,等到这个锁释放后再重新申请该锁。这样就实现了简单的分布式锁。
但同时在大量锁的情况下会有**“惊群”**的问题。“惊群”就是在一个节点删除的时候,大量对这个节点的删除动作有订阅Watcher的线程会进行回调,这对Zk集群是十分不利的。所以需要避免这种现象的发生。
为了解决“惊群“问题,我们需要放弃订阅一个节点的策略,那么怎么做呢?
脑裂 (split-brain),就是“大脑分裂”,也就是本来一个“大脑”被拆分了两个或多个“大脑”。我们都知道,如果一个人有多个大脑,并且相互独立的话,那么会导致人体“手舞足蹈”,“不听使唤”。这种现象经常出现于集群情况。
对于一个集群,想要提高这个集群的可用性,通常会采用多机房部署,比如现在有一个由6台 zkServer 所组成的一个集群,部署在了两个机房。正常情况下,此集群只会有一个 Leader。那么如果机房之间的网络断了之后,两个机房内的 zkServer 还是可以相互通信的,如果不考虑过半机制,那么就会出现每个机房内部都将选出一个 Leader,如下图所示:
实际上 Zookeeper 集群中是不会出现脑裂问题的,而不会出现的原因就跟过半机制有关。Zookeeper 选举时,必须接收到超过一半节点选择同样的节点,超过一半节点意味着不能等于一半节点。这里的原因用上面的问题可以很好的解释:
假设允许等于一半节点,那么假设两个机房都是三台服务器,中间两个机房的连接断了,那么两个机房内部选举,都会选出分别的 master,即出现了脑裂现象。
但是如果只允许大于一半节点,不允许等于,那么上面的情况,两边机房都不会选出新的 master。如果两个机房分别是 4 台,2 台节点,那么机房一所有节点的投票最终会相同,投票数量为 4,大于总服务器的一半,所以新的 master 节点只可能出现在机房一中。