一、什么是Elasticsearch的脑裂,为啥说它防不胜防

你可以把Elasticsearch(以下简称ES)想象成一个多人团队:团队里有个核心角色叫主节点(master),负责定规则、管整体架构,比如哪个节点存什么数据、集群整体状态是否正常;其他节点是数据节点,负责存具体的搜索数据、处理用户的搜索请求。

脑裂就是这个团队突然分裂成了好几个独立的小团队,每个小团队都有自己的“主节点”,各自定规则、管数据,谁也不认谁。举个生活化的例子:你开了一家连锁超市,总公司(原主节点)在上海,负责给全国门店定进货规则、管库存;突然网络断了,北京的门店连不上上海总公司,自己拉了个小团队,推了个新的北京区域“总公司”;广州的门店也连不上上海,自己也推了个广州的“总公司”。这时候全国有三个“总公司”,各自定的规则不一样,比如上海定了A商品卖10块,北京定了卖8块,广州定了卖12块,库存也各管各的,整个超市体系直接乱了套——这就是ES的脑裂。

为啥说它防不胜防?很多人以为只要加了“主节点最少票数”的配置就没事了,结果还是出问题。本质是大家没搞懂两个核心:一是ES的主节点选举逻辑到底是怎么运行的,二是那些用来防脑裂的配置,到底是在什么场景下才会生效。

二、搞懂主节点选举:脑裂问题的核心源头

要防脑裂,首先得知道主节点是怎么选出来的,就像要解决团队分裂的问题,得先搞懂团队选领导的规则。

2.1 主节点选举的基本逻辑

ES的主节点选举,本质是“多数派同意”的机制。就像班级选班长,得有超过一半的同学投票同意,新班长才能上任。ES里的“同学”,指的是有资格竞选主节点的节点——默认情况下,所有节点都有这个资格,你也可以手动指定哪些节点能竞选。

选举的触发条件也很简单:当现有主节点失联超过一定时间,或者集群刚启动的时候,就会触发选举。

2.2 选举的具体过程(用生活化例子拆解)

我们用一个有5个节点的ES集群来举例,节点分别叫node1、node2、node3、node4、node5,默认都有竞选主节点的资格。

第一步:触发选举。假设原来的主节点是node1,突然node1失联了,剩下的4个节点会在一段时间后发现node1没回应了,触发选举。

第二步:竞选报名。所有有资格的节点(node2、node3、node4、node5)都可以报名竞选主节点。

第三步:投票环节。每个节点都会给自己投一票,然后给其他报名的节点投票。这时候有个关键规则:必须有超过一半的总竞选资格节点数同意,新主节点才能上任。

第四步:结果确认。假设node2拿到了3票(自己+node3+node4),总共有4个竞选节点,一半是2,超过一半的话需要至少3票,所以node2成为新的主节点;如果node2只拿到2票,那这次选举失败,重新触发下一轮选举。

2.3 脑裂发生的具体场景

还是用上面5个节点的集群,假设网络出了问题,分成了两个部分:A部分是node1、node2、node3,B部分是node4、node5。

这时候会发生什么?A部分的三个节点发现主节点node1还在,所以不会触发选举;B部分的两个节点发现node1失联了,触发选举。B部分总共有2个竞选节点,超过一半需要至少2票,node4和node5互相投票,都拿到了2票,所以B部分自己选了一个主节点(比如node4)。

这时候整个集群就分裂成了两个独立的集群:一个是A部分(node1、node2、node3),一个是B部分(node4、node5),这就是脑裂。

三、核心配置解析:那些被误解的防脑裂配置

很多人会在ES的配置文件里加两个配置:discovery.zen.minimum_master_nodes和discovery.zen.ping_timeout,以为加了就万事大吉,其实不然,得搞懂每个配置的作用和生效条件。

3.1 discovery.zen.minimum_master_nodes:最关键的防脑裂配置

这个配置的意思是:集群里必须有至少多少个有竞选主节点资格的节点在线,才能选出来一个主节点。就像班级选班长,必须有至少3个同学到场(总共有5个同学的话,超过一半是3),选出来的班长才有效。

3.1.1 正确的配置方法

配置这个值的公式是:(有竞选资格的节点总数 ÷ 2) + 1。

比如:

  • 有3个竞选资格节点,配置值是(3÷2)+1=2.5,取整是2;
  • 有5个竞选资格节点,配置值是(5÷2)+1=3.5,取整是3;
  • 有2个竞选资格节点,配置值是(2÷2)+1=2。

3.1.2 配置错误的后果

还是用5个节点的集群,假设我们错误地把这个配置值设成了2,而不是正确的3。

当集群分裂成A部分(3个节点)和B部分(2个节点)时:

  • A部分有3个节点,满足至少2个的要求,选node1为主节点;
  • B部分有2个节点,也满足至少2个的要求,选node4为主节点;
  • 直接发生脑裂。

如果配置正确,设成3:

  • A部分有3个节点,满足要求,选node1为主节点;
  • B部分只有2个节点,不满足至少3个的要求,选不出主节点;
  • B部分会一直尝试选举,不会形成独立的集群,不会发生脑裂。

3.1.3 配置示例(技术栈:Elasticsearch 7.x)

我们给一个有5个竞选资格节点的集群配置这个参数,配置文件是elasticsearch.yml:

# 配置有竞选主节点资格的节点总数为5
node.master: true
# 配置minimum_master_nodes为3,公式是(5÷2)+1=3.5,取整为3
discovery.zen.minimum_master_nodes: 3
# 配置节点之间的ping超时时间,单位是毫秒,这里设为3000毫秒(3秒)
discovery.zen.ping_timeout: 3000

3.2 discovery.zen.ping_timeout:辅助配置,不是防脑裂的核心

这个配置的意思是:每个节点每隔一段时间会给其他节点发一个“我还活着”的ping包,如果超过这个时间没收到回应,就认为对方失联了。

很多人以为把这个值设得越大,就越不容易发生脑裂,其实不对。这个配置的作用是调整“判断节点失联的速度”,而不是从根本上防止脑裂。

比如把这个值设成10秒,那么节点要等10秒没收到回应才会认为对方失联,触发选举的时间会变慢;但如果minimum_master_nodes配置错了,还是会发生脑裂。

四、实战场景:常见的脑裂场景和解决方案

我们来看几个实际工作中常见的脑裂场景,以及对应的解决方案。

4.1 场景一:集群节点数量为偶数,配置错误

假设我们有一个4个节点的集群,所有节点都有竞选主节点的资格,正确的minimum_master_nodes配置应该是(4÷2)+1=3。如果错误地设成了2,就会发生脑裂。

解决方案

  1. 把4个节点分成两组:2个节点设为有竞选资格(node.master: true),另外2个设为没有竞选资格(node.master: false);
  2. 这时候有竞选资格的节点总数是2,配置minimum_master_nodes为(2÷2)+1=2;
  3. 这样当集群分裂成2个节点的组时,每个组都有2个竞选资格节点,满足要求,会发生脑裂?不对,这时候应该调整:把有竞选资格的节点总数设为3,其中1个设为没有竞选资格,这样有竞选资格的节点总数是3,配置minimum_master_nodes为2,当集群分裂成2个节点的组时,最多有2个竞选资格节点,不满足至少2个的要求?不对,重新来:

正确的方案是:如果集群节点数是偶数,要么把有竞选资格的节点总数设为奇数,要么把minimum_master_nodes设为正确的值。比如4个节点的集群,设3个节点有竞选资格,配置minimum_master_nodes为2,这样当集群分裂成2个节点的组时,最多有2个竞选资格节点,不满足至少2个的要求?不对,公式是(有竞选资格的节点总数÷2)+1,3个的话是(3÷2)+1=2.5,取整是3,所以配置minimum_master_nodes为3,这样任何分裂的组只要少于3个竞选资格节点,就选不出主节点,不会发生脑裂。

4.2 场景二:网络分区导致的脑裂

网络分区是指网络突然断开,把集群分成两个或多个部分,这是最常见的脑裂原因。

解决方案

  1. 配置正确的minimum_master_nodes;
  2. 调整discovery.zen.ping_timeout的值,不要设得太小,比如设为3000-5000毫秒,避免因为网络抖动导致误判节点失联;
  3. 监控集群的健康状态,一旦发现集群变成黄色或红色,及时排查网络问题。

4.3 场景三:主节点压力过大导致的脑裂

主节点压力过大,比如处理太多的元数据更新,导致无法及时响应其他节点的ping包,其他节点会认为主节点失联,触发选举,导致脑裂。

解决方案

  1. 把主节点和数据节点分开部署,主节点不存数据,只负责管理集群,减轻主节点的压力;
  2. 配置node.master: true的节点只负责竞选主节点,node.data: true的节点只负责存数据,node.master: false;
  3. 示例配置(主节点配置):
# 主节点配置:只负责竞选主节点,不存数据
node.master: true
node.data: false
# 有3个主节点,配置minimum_master_nodes为2
discovery.zen.minimum_master_nodes: 2
discovery.zen.ping_timeout: 3000
  1. 示例配置(数据节点配置):
# 数据节点配置:只负责存数据,不竞选主节点
node.master: false
node.data: true
discovery.zen.ping_timeout: 3000

五、重建高可用防线:从配置到监控的完整方案

要彻底防住脑裂,不能只靠配置,得从多个层面搭建防线。

5.1 配置层面:正确配置主节点和minimum_master_nodes

  1. 主节点数量设为奇数:比如3个、5个,避免因为节点数量为偶数导致的配置问题;
  2. 严格按照公式配置minimum_master_nodes:(主节点总数÷2)+1;
  3. 主节点和数据节点分开部署,主节点不承担数据存储任务。

5.2 网络层面:避免网络分区

  1. 把ES集群部署在同一个局域网内,避免跨地域部署导致的网络不稳定;
  2. 用高可用的网络设备,比如冗余的交换机、路由器,避免单点故障;
  3. 监控网络的连通性,一旦发现网络延迟过高或断开,及时处理。

5.3 监控层面:及时发现脑裂的前兆

  1. 监控集群的健康状态:ES的集群健康状态有绿色(正常)、黄色(部分副本不可用)、红色(部分主分片不可用),一旦变成黄色或红色,及时排查;
  2. 监控主节点的状态:比如主节点的CPU、内存、磁盘使用率,以及主节点的响应时间;
  3. 监控选举事件:一旦发现集群频繁触发选举,说明可能有节点失联或网络问题,及时处理。

5.4 应急层面:脑裂发生后的处理

如果真的发生了脑裂,不要慌,按照以下步骤处理:

  1. 先停止所有的ES节点,避免数据冲突;
  2. 检查每个分裂的集群,找到数据最新的那个集群;
  3. 把其他分裂的集群的数据备份后删除;
  4. 重新启动所有节点,确保集群合并成一个。

六、技术优缺点和注意事项

6.1 主节点选举机制的优缺点

优点:

  1. 多数派同意的机制,能有效保证集群的一致性,避免多个主节点同时存在;
  2. 选举过程自动完成,不需要人工干预,集群的可用性高。

缺点:

  1. 对网络的依赖很高,一旦网络出现问题,容易触发选举;
  2. 主节点的压力过大时,会导致选举失败或脑裂。

6.2 防脑裂配置的注意事项

  1. 配置minimum_master_nodes时,必须严格按照公式来,不能凭感觉设;
  2. 调整discovery.zen.ping_timeout的值时,要根据实际的网络情况来,不要设得太小或太大;
  3. 主节点数量不要太多,一般3-5个就足够了,太多会增加选举的复杂度。

七、文章总结

脑裂不是不可避免的,很多时候是因为我们对主节点选举机制的误解和配置的错误导致的。要防住脑裂,首先得搞懂主节点选举的逻辑,然后正确配置minimum_master_nodes,把主节点和数据节点分开部署,再加上网络层面的保障和监控层面的预警,就能搭建起一套完整的高可用防线。

很多人觉得ES的脑裂问题复杂,其实本质就是“团队分裂”的问题,只要把背后的逻辑搞懂,再结合正确的配置和监控,就能轻松解决。