脑裂

来自百度百科的定义

脑裂-计算机术语,英文称为“Split-Brain”。

脑裂是因为cluster集群分裂导致的,cluster集群中节点因为处理器忙或者其他原因暂时停止响应时,
其他节点可能误认为该节点“已死”,从而夺取共享磁盘(即资源)的访问权,此时极有可能假死节点重新对共享文件系统产生读写操作,从而导致共享磁盘文件系统损坏。

分析

脑裂出现在高可用(HA)集群中,如果集群中的服务属于无状态的,那么则无需关注此问题,但是在某些集群中为了保证数据的一致性,
使用了不同的主从策略(比如Zookeeper的leader节点、ElasticSearch里的master节点、Redis里的master节点),假设作为集群的主节点挂掉或者挂起,
而后出现了多个节点被重新选举为主节点的情况下,那么这里面的数据绝大部分情况下不会一致。而在真实的场景中不会出现这写问题,
那么这个问题是如何解决的呢?

解决方案

为了解决脑裂的问题,一般可以从两个方面进行入手

  1. 添加冗余的心跳检测,采用双心跳检测,减少脑裂的产生
  2. 仲裁,使用仲裁服务或者资源锁,避免多个节点进入临界区
redis脑裂问题

假设redis集群部署采用了master1、slave1、slave2、slave3的一主三从节点个数,并且使用哨兵模式进行部署,
客户端采用client1,client2进行了水平部署,如果master1与slave1、slave2、slave3以及哨兵节点的网络连接断开,
但是master1与client1,client2之间的通信没有发生异常;

在这种情况下,一方面哨兵节点会认为master1不可用,并且从slave1、slave2、slave3中选取新的master,
假设slave1被选举成功并且记为master2,则新的集群变为master2、slave2、slave3。
另一方面client1可以访问到master1,假设此时client1访问到master1,client2访问到master2;

此时master1和master2之间的内存数据并不会同步,client1和client2如果针对相同的redis key进行分布式锁操作,则有可能会全部获取到锁。

redis并不能解决脑裂问题。

Zookeeper脑裂问题

如果在A、B双机房中部署了Zookeeper,每个机房3个实例,共6个,正常情况下,两个机房会作为一个集群对外提供服务,但是如果AB机房之间的通信出现故障,
假设原本的leader在A1节点,此时B机房中的B1、B2、B3会发现连接不到leader,并进行选举,假如选举B1为leader。此时问题出现在两个地方,
一个AB机房之间的通讯虽然断了,但是客户端还是可以访问到任何一个机房,在通讯恢复之前会出现数据不一致的情况,
另外,当通讯恢复正常,两个集群可以感知到对方。

为了解决这个问题,Zookeeper做了一个很简单的解决方案,那就是不提供服务,为什么会这么说呢,相信大家还记得Zookeeper选举leader的一个重要条件:
过半机制,只有半数以上的节点投票给某个服务,才能选举为leader节点,而在这种情况下,即使B机房进行了选举,在唱票阶段,B1节点至多获得3票,
无法满足过半机制,也就是>3=false。

ElasticSearch脑裂问题

ES节点的脑裂问题和zk问题基本一致,由于ES可以使用2个节点作为集群,所以针对ES描述双节点的情景,假设部署了ES的节点N1,N2。
在启动时N1选为master节点而N2节点成为slave节点。如果N1和N2之间的通讯断掉,那么N1和N2都会认为对方出现故障,N1不变而N2选举自己为master,此时客户端可以访问到不同的节点,造成数据不一致的问题。

ES对于这个问题有两种解决方案:

一种是指定discovery.zen.minimum_master_nodes配置,这个参数相当于zk的最小票数,只不过不是自动计算的,我们可以配置成2,
这样在2个节点的情况下,N2不会自我选举成master。

另一种是指定discovery.zen.ping.timeout配置,这个配置用于决定网络超时的时间,默认值为3秒,通过延长这个时间可以减少因为网络问题带来的误测,
从而减少脑裂出现的概率。

在2节点以上的情况下,并没有什么特殊的问题,但是要注意,ES也无法保证解决脑裂问题,所以也存在着数据不一致的极端情况。