shoufeng

瘦风的南墙

ZooKeeper 05 - ZooKeeper 集群的脑裂问题(Split Brain)

首发于 2018-12-08,修改于 2021-12-12。

1 - ZooKeeper的主从机制

在绝大部分通过主从实现高可用的系统中,Leader == Master,Follower == Slaver。

集群中的各个节点都会尝试注册为 leader 节点,其他没有注册成功的则成为 follower(随从)节点。

这些 follower 节点通过 watcher(观察者)监控着 leader 节点:

—— ZooKeeper 内部通过心跳机制来确定 leader 的状态,一旦 leader 节点出现问题,集群内部就能立即获悉并迅速通知其他 follower 节点来选出新的 leader。

2 - 什么是 ZooKeeper 的脑裂

2.1 脑裂现象的表现

ZooKeeper 集群中,各个节点间的网络通信不良时,容易出现脑裂(split-brain)现象。

1)集群中的部分 follower 节点监听不到 leader 节点的心跳,就会认为 leader 节点出了问题;

2)这些监听不到 leader 节点心跳的 follower 节点就会选举出新 leader 节点;

3)新的 leader 和旧 leader 节点 和各自的 follower 节点组成多个小集群。

—— 一个集群中有多个 leader 节点,这就是脑裂现象。

2.2 为什么会出现脑裂

设想这样一种情况:

① 集群中网络通信不好,导致心跳监测超时 —— follower 认为 leader 节点由于某种原因挂掉了,可其实 leader 节点并未真正挂掉 —— 这就是假死现象

② leader 节点假死后,ZooKeeper 通知所有 follower 节点进行新的选举 ==> 某个 follower 节点升级为新的 leader —— 此时集群中存在2个leader节点

③ 此时 ZooKeeper 需要将新 leader 节点的信息通知给所有 follower 节点,还要通知到所有的 client(比如 Kafka 集群中的 Kafka 节点就是一个 client),这个过程由于网络等因素的影响,消息到达肯定存在不同程度的延迟。

④ 如果部分 client 获得了新 leader 节点的信息,而部分没有获得,恰好此时 client 向 ZooKeeper 发起读写请求,ZooKeeper 内部的不一致就会导致:部分 client 连接到了新的 leader 节点,而部分 client 连接到了旧的 leader节点 —— 服务中出现了2个leader,client 不知道听谁好,就像1个大脑被分裂成2个,很形象吧O(∩_∩)O

3 - ZooKeeper如何解决"脑裂"

3.1 3种可行的思路

(1) Quorums(ˈkwɔrəm,法定人数)

通过设置法定人数,进而确定集群的容忍度,当集群中存活的节点少于法定人数,集群将不可用。比如:

3个节点的集群中,Quorums = 2 —— 集群可以容忍 (3 - 2 = 1) 个节点失败,这时候还能选举出 leader,集群仍然可用;
4个节点的集群中,Quorums = 3 —— 集群同样可以容忍 1 个节点失败,如果2个节点失败,那整个集群就不可用了。

(2) Redundant communications(冗余通信)

集群中采用多种通信方式,防止一种通信方式失效导致集群中的节点无法通信。

(3) Fencing(隔离,即共享资源)

通过隔离的方式,将所有共享资源隔离起来,能对共享资源进行写操作(即加锁)的节点就是 leader 节点。

3.2 ZooKeeper 的做法

ZooKeeper 默认采用了Quorums 的方式:只有获得超过半数节点的投票,才能选举出 leader。

这种方式可以确保要么选出唯一的 leader,要么选举失败。

ZooKeeper 中 Quorums 的作用:

① 指定集群中选举 leader 所需的最少节点数,保证集群可用;

② client 的数据被安全保存到集群中所需的最少节点数,一旦这些节点保存了数据,客户端将被通知数据已经安全保存,可以继续其他任务 —— 基于最终一致性,集群中剩余的节点最终也会保存相关的数据。

ZooKeeper的写也遵循quorum机制,因此得不到大多数支持的写是无效的。

3.3 ZooKeeper 的具体解决思路

假设:leader 发生了假死,followers 选举出了一个新的 leader。

当旧的 leader 复活并认为自己仍然是 leader,它向其他 followers 发出写请求时,会被拒绝。

—— 因为 ZooKeeper 维护了一个叫 epoch 的变量,每当新 leader 产生时,epoch 就会递增,followers 如果确认了新的 leader,同时也会知道其 epoch 的值 —— 它们会拒绝所有 epoch 小于现任 leader 的 epoch 的旧 leader 的请求。

注意:仍然会存在有部分 followers 不知道新 leader 的存在,但肯定不是大多数,否则新 leader 将无法产生。

参考资料

zookeeper(二)常见问题汇总

Zookeeper集群节点数量为什么要是奇数个?


版权声明

作者:瘦风(https://healchow.com)

出处:博客园-瘦风的南墙(https://www.cnblogs.com/shoufeng)

感谢阅读,公众号 「瘦风的南墙」 ,手机端阅读更佳,还有其他福利和心得输出,欢迎扫码关注🤝

本文版权归博主所有,欢迎转载,但 [必须在页面明显位置标明原文链接],否则博主保留追究相关人士法律责任的权利。

posted @ 2021-12-06 14:03  瘦风  阅读(1586)  评论(0编辑  收藏  举报