ZK关于zk2单点故障导致集群无法选主的问题分析

探讨3节点zk集群中,zk2(leader)节点宕机后,集群无法选主的问题分析,以及避免相关问题的实践。

1. 问题说明

1.1 配置说明

环境使用的版本是3.4.14,对应的配置如下

zoo.cfg配置

cat /data/zookeeper-3.4.14/conf/zoo.cfg 
# The number of milliseconds of each tick
tickTime=2000
# The number of ticks that the initial 
# synchronization phase can take
initLimit=16
# The number of ticks that can pass between 
# sending a request and getting an acknowledgement
syncLimit=8
# the directory where the snapshot is stored.
# do not use /tmp for storage, /tmp here is just 
# example sakes.
dataDir=/data/zookeeper-3.4.14/data
dataLogDir=/data/zookeeper-3.4.14/log
# the port at which the clients will connect
clientPort=2181
# the maximum number of client connections.
# increase this if you need to handle more clients
maxClientCnxns=10000
#
# Be sure to read the maintenance section of the 
# administrator guide before turning on autopurge.
#
# http://zookeeper.apache.org/doc/current/zookeeperAdmin.html#sc_maintenance
#
# The number of snapshots to retain in dataDir
autopurge.snapRetainCount=50
# Purge task interval in hours
# Set to "0" to disable auto purge feature
autopurge.purgeInterval=1
# 配置允许删除临时数据
extendedTypesEnabled=true

# 注意该配置
cnxTimeout=5000
# Add default super user to zookeeper for administration.
# if you want the passwd. please contact to administration.
DigestAuthenticationProvider.superDigest=super:2bS8Usm0IRIIwal5O1c6meW8uxI=

server.1=xx.xx.xx.xx:2888:3888
server.2=xx.xx.xx.xx:2888:3888
server.3=xx.xx.xx.xx:2888:3888

为了便于和节省日常运维成本,在每台zk的机器上配置了定时任务,每1min检查zk的状态,如果zk状态异常,会执行重启动作,便于自动快速恢复。

1.2 触发条件

在故障前,zk2是集群的leader,zk1和zk3是follow。 由于机器底层硬件故障,导致zk2机器宕机,由于zk2正好是leader节点,因此理论上应该由zk1,zk3完成投票,重新选择一个Leader,并提供集群服务。但是实际上zk2宕机后,zk1和zk3并不能选举Leader,需要后续人工干预后才能恢复。

2. 原因分析

2.1 原因1:zk3应该成为Leader

原因分析分为多个环节进行,根据zk的选举Leader流程

按照zk的设计,成为Leader的节点应该满足如下条件,在同一个选主周期过程中

  • zxid(事务id)越大,越容易成为Leader(通常写入的数据越多)
  • 如果zxid相同,sid(配置的myid)越大,越容易成为Leader(没有特别原因,长者为尊,避免多次选举)
  • 获取超过集群半数节点的选票的节点,成为Leader

事后分析,zk1和zk3的zxid相同,因此按照目标,zk3应当成为Leader。

2.3 原因2:zk在投票后进行广播是按照sid排序,从小到大串行执行。

按照zk的选举逻辑,在阶段1完成投票后,需要通过广播的方式给其他节点告知选票。

根据代码分析,在进行广播时,节点编列的代码如下
在这里插入图片描述
虽然使用了Map,但是由于key是sid(数字类型),进行遍历时,会呈现有序性,结果上看就是,从小到大进行排序,并且是完成一个节点的选票同步后,在进行下一个节点同步,整体上是串行进行的。

2.3 原因3:zk2宕机导致zk3收到广播选票的时间延迟

我们分开看zk1和zk3的节点行为以及相关的时间线,有2个时间我们做一下说明
timeout: 如果服务不响应的超时时间,根据zk配置,5s
exchangeTime: 交换选票的时间,大约3ms

1,zk1的视角
t0: zk1给自己投票(1,zxid),然后通过广播的方式通知其他节点自己的选票信息
t0 到 t0 + 5s: zk1通知zk2,并等待5s超时,继续通知zk3
t0 + 5s 到 t0 + 5s + exchangeTime: zk1通知zk3并快速返回

2,zk3的视角
t0: zk3给自己投票(3,zxid),然后通过广播的方式通知其他节点自己的选票信息
t0 到 t0+ exchangeTime: zk3通知zk1,并快速返回,此时zk1已经获取到zk3的选票,并将自己的选票更改为(3,zxid)
t0+ exchangeTime 到 t0+ exchangeTime + 5s: zk1通知zk2,并等待5s超时

3, 完成一轮投票后,各自统计手上的选票
zk1的选票(3,zxid),zk1成为Follower
zk3的选票分为2个阶段
t0 (3,zxid) * 1
t0 + 5s + exchangeTime: (3,zxid) * 2
也就是说,zk3需要再t0 + 5s + exchangeTime 才能成为Leader,并且集群也只能是zk3成为Leader

2.4 原因4:Follower链接Leader通讯时间短于超时时间,导致集群无法选出Leader

在zk1成为Follower后,需要跟zk3进行数据通信确认后,确认集群已经有了Leader,选主才算结束。

但是,根据代码逻辑,Follower跟Leader通信的时间只有4s,但是此时zk3由于还没有接收到zk1的选票,因此zk3不能成为Leader,4s后zk1认为集群还没有Leader,因此就会进行下一轮投票。因此选入陷入了死循环,无法选出Leader。
在这里插入图片描述

该问题在 issues ZOOKEEPER-2164中有说明
在这里插入图片描述

3. 优化建议

1, 设置cnxTimeout=3000进行规避,绕开4s的限制。
2, 该问题的修复版本在3.5.8以后,也可以升级到3.5.8以后的版本规避

4. 疑问和思考

4.1 Follower和Leader等待时间的差异

follower会主动连接leader的数据同步端口, 如果失败会重试4次, 总共耗时大约4s.
leader等待follower来连接的时间是initLimit(默认10)乘以tickTime(默认2s),大约是20s。

4.3 如果zk1和zk3(非中间节点)宕机是否能够触发该风险

1, 中间节点宕机都有有概率触发该问题,导致集群无法选主
2, 边缘节点zk1、zk3不会有该风险

相关推荐

  1. zk--同步

    2024-01-26 11:36:02       28 阅读
  2. 超实用Kafka搭建(有zk版)

    2024-01-26 11:36:02       48 阅读
  3. <span style='color:red;'>zk</span>_dubbo

    zk_dubbo

    2024-01-26 11:36:02      41 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-01-26 11:36:02       18 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-01-26 11:36:02       19 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-01-26 11:36:02       18 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-01-26 11:36:02       20 阅读

热门阅读

  1. C Primer Plus(第六版)13.11 编程练习 第13题

    2024-01-26 11:36:02       31 阅读
  2. C语言——栈的实现

    2024-01-26 11:36:02       35 阅读
  3. Nginx location 使用正则匹配路径

    2024-01-26 11:36:02       35 阅读
  4. 前端学习-0125

    2024-01-26 11:36:02       33 阅读
  5. 服务器宝塔安全需要修改的设置

    2024-01-26 11:36:02       37 阅读
  6. UnityUI看向相机

    2024-01-26 11:36:02       33 阅读
  7. mysql更新charset

    2024-01-26 11:36:02       29 阅读
  8. sealos apt&&yum安装 && sealos 部署k8s

    2024-01-26 11:36:02       37 阅读
  9. GET基于报错的sql注入利用-脱库

    2024-01-26 11:36:02       36 阅读
  10. 优雅的控制协程(goroutine)的并发数量

    2024-01-26 11:36:02       33 阅读