ES 集群脑裂问题详解
一、什么是 ES 集群脑裂问题?
在 ES 集群中,主节点产生分歧,导致多个主节点存在,使集群分裂处于异常状态,就像精神分裂一样,不同节点对集群状态的理解不一致,导致操作混乱。
二、脑裂问题的示例(两节点集群)
假设有一个两节点的 elasticsearch 集群,维护一个单一索引,有 1 个分片和 1 个复制节点。节点 1 启动时被选举为主节点并保存主分片,节点 2 保存复制分片。若两节点通讯中断,节点 1 认为自己是 master 无需动作,节点 2 在单节点集群中认为自己是 master 并提升复制节点为主节点,此时整个 es 集群出现两个 master,索引请求分配到不同节点的不同分片,数据分散,不重索引难以排序,查询集群数据时结果不一致,集群状态和可用节点数也不同。
三、解决脑裂问题的主要思路
1. 网络稳定性:保证网络稳定,及时预警,必要时重启集群。
2. 避免 master 节点负载过大:通过增加堆内存大小、调整 GC 处理器,或进行读写分离,让 master 节点负责集群管理,其他节点负责数据存储和请求处理。
3. 优化配置:
elasticsearch6.X 配置:
`discovery.zen.ping.multicast.enabled`:将 data 节点的 master 发现方式由 multicast 修改为 unicast,提高节点发现速度。
`discovery.zen.ping.unicast.hosts`:配置其他 Elasticsearch 服务节点的广播发现功能。
`discovery.zen.ping_timeout`:增加节点等待响应的时间,减少误判。
`discovery.zen.minimum_master_nodes`:设置足够的 master 候选节点才能选举出 master。
elasticsearch7.X 配置:在默认配置下,集群自动引导,方便开发环境和实验,但可能存在节点发现不及时的问题。需要配置`discovery.seed_hosts`在无网络配置情况下,扫描本地端口快速发现集群中节点;`cluster.initial_master_nodes`使用一组初始符合主节点条件的节点引导集群。
四、脑裂修复
当集群重新选举出 master 节点时,需要给所有数据重新索引,逐个关闭节点并备份数据,分析比对数据是否最新,以确保正确性,避免数据丢失。启动节点并让其被选为主节点,然后启动集群的其他节点。
五、Zookeeper 中的脑裂问题及过半机制
(一)Zookeeper 集群中的脑裂场景
对于一个由 6 台 zkServer 组成的集群,部署在两个机房。正常情况下只有一个 Leader,若机房间网络断了,两个机房内的 zkServer 仍可通信,若不考虑过半机制,每个机房内部都会选出一个 Leader,相当于一个集群被分成两个,出现两个“大脑”。原本统一集群对外服务,现在变成两个集群同时提供服务,网络联通后会出现数据合并和冲突解决等问题。

(二)过半机制
在领导者选举过程中,某台 zkServer 获得超过半数选票可成为 Leader。过半机制源码实现简单,如`this.half = n/2; return(set.size> half);`。举个例子,若集群中有 5 台 zkServer,half = 5/2 = 2,即至少要有 3 台 zkServer 投同一个 zkServer 才符合过半机制。选举过程中要有过半机制验证是为了快速选出 Leader,而过半机制中是大于而不是大于等于是为了防止脑裂。如机房网络断开,机房 1 内三台服务器选举,因过半机制条件是 set.size>3,至少要 4 台 zkServer 才能选出 Leader,所以机房 1 选不出 Leader,机房 2 也选不出,整个集群当机房间网络断开后无 Leader;若过半机制条件是 set.size>=3,机房 1 和机房 2 都会选出 Leader,就出现脑裂。
六、ES 磁盘分配分片导致的脑裂相关问题
(一)现象
后台启动 ES 集群,由三个节点组成,集群健康值为 yellow,节点只有主分片,副本状态为:Unassigned。
(二)原因
在 ES 磁盘分配分片控制策略中,为保护数据节点安全,对磁盘进行限额并定时检查各节点数据目录使用情况。达到`cluster.routing.allocation.disk.watermark.low`(默认 85%)时,新索引分片不会分配到该节点;达到`cluster.routing.allocation.disk.watermark.high`(默认 90%)时,会触发现存分片数据均衡。通过 shell 客户端执行 df -h ,查询到 es 集群所在路径/home/app 的磁盘使用率 Use%值为 86%,超过最低值 85%,导致重启后副本索引分片不会分配到节点上。
(三)如何修改
方案一:删除 es 集群所在路径不必要大文件,如旧日志文件、临时文件等,使 Use%值小于 85%。
方案二:修改 ES 分片控制策略,提高`cluster.routing.allocation.disk.watermark.low`的值,该值大于当前 ES 集群所在路径%Use 的值。
修改示例:
`curl -XPUT localhost:9200/_cluster/settings -d '{
"transient":{
"cluster.routing.allocation.disk.watermark.low":"90%",
"cluster.routing.allocation.disk.watermark.high":"95%"
}
}'`
或使用 postman。
参考:elasticsearch 问题解决之分片副本 Unassigned;《kibana 中文指南》中 ElasticSearch 架构原理 shard 的 allocate 控制章节。












