zookeeper 的容错与脑裂问题

本贴最后更新于 1911 天前,其中的信息可能已经东海扬尘

一 、zookeeper 的容错机制

1.由于在增删改查操作中需要半数以上的服务器通过,来分析一下情况

1主节点挂了,另外一个备节点因为没有过半,无法对外提供集群服务,容错数为0

3节点zookeeper,一个主节点挂了,另外两个备节点过半,顺利选出Leader对外提供集群服务,容错数为1

5节点zookeeper,两个主节点挂了,另外三个备节点过半,对外提供集群服务,容错数为2

6节点zookeeper,两个主节点挂了,另外四个备节点过半,对外提供集群服务,容错数为2,

 起第三个主节点,另外三个备节点没有过半,也就无法梳理选举出Leader。

2.总结:

​ 如果有 2 个 zookeeper,那么只要有 1 个死了 zookeeper 就不能用了,因为 1 没有过半,所以 2 个 zookeeper 的死亡容忍度为 0;同理,要是有 3 个 zookeeper,一个死了,还剩下 2 个正常的,过半了,所以 3 个 zookeeper 的容忍度为 1;同理你多列举几个:2->0;3->1;4->1;5->2;6->2 会发现一个规律,2n 和 2n-1 的容忍度是一样的,都是 n-1,所以为了更加高效,何必增加那一个不必要的 zookeeper 呢。

二、zookeeper 脑裂(Split-Brain)问题

1.什么是脑裂?

​ 比如当你的 cluster 里面有两个结点,它们都知道在这个 cluster 里需要选举出一个 master。那么当它们两之间的通信完全没有问题的时候,就会达成共识,选出其中一个作为 master。但是如果它们之间的通信出了问题,那么两个结点都会觉得现在没有 master,所以每个都把自己选举成 master。于是 cluster 里面就会有两个 master。

​ 对于 Zookeeper 来说有一个很重要的问题,就是到底是根据一个什么样的情况来判断一个节点死亡 down 掉了。 在分布式系统中这些都是有监控者来判断的,但是监控者也很难判定其他的节点的状态,唯一一个可靠的途径就是心跳,Zookeeper 也是使用心跳来判断客户端是否仍然活着。

​ 使用 ZooKeeper 来做 master HA 基本都是同样的方式,每个节点都尝试注册一个象征 master 的临时节点其他没有注册成功的则成为 slaver,并且通过 watch 机制监控着 master 所创建的临时节点,Zookeeper 通过内部心跳机制来确定 master 的状态,一旦 master 出现意外 Zookeeper 能很快获悉并且通知其他的 slaver,其他 slaver 在之后作出相关反应。这样就完成了一个切换。这种模式也是比较通用的模式,基本大部分都是这样实现的,但是这里面有个很严重的问题,如果注意不到会导致短暂的时间内系统出现脑裂,因为心跳出现超时可能是 master 挂了,但是也可能是 master,zookeeper 之间网络出现了问题,也同样可能导致。这种情况就是假死,master 并未死掉,但是与 ZooKeeper 之间的网络出现问题导致 Zookeeper 认为其挂掉了然后通知其他节点进行切换,这样 slaver 中就有一个成为了 master,但是原本的 master 并未死掉,这时候 client 也获得 master 切换的消息,但是仍然会有一些延时,zookeeper 需要通讯需要一个一个通知,这时候整个系统就很混乱可能有一部分 client 已经通知到了连接到新的 master 上去了,有的 client 仍然连接在老的 master 上如果同时有两个 client 需要对 master 的同一个数据更新并且刚好这两个 client 此刻分别连接在新老的 master 上,就会出现很严重问题。

2.总结

​ 假死:由于心跳超时(网络原因导致的)认为 master 死了,但其实 master 还存活着。

​ 脑裂:由于假死会发起新的 master 选举,选举出一个新的 master,但旧的 master 网络又通了,导致出现了两个 master ,有的客户端连接到老的 master 有的客户端链接到新的 master。

3.出现原因

​ 在搭建 hadoop 的 HA 集群环境后,由于两个 namenode 的状态不一,当 active 的 namenode 由于网络等原因出现假死状态,standby 接收不到 active 的心跳,因此判断 active 的 namenode 宕机,但实际上 active 并没有死亡。此时 standby 的 namenode 就会切换成 active 的状态,保证服务能够正常使用。若原来的 namenode 复活,此时在整个集群中就出现 2 个 active 状态的 namenode,该状态成为脑裂。脑裂现象可能导致这 2 个 namenode 争抢资源,从节点不知道该连接哪一台 namenode,导致节点的数据不统一,这在企业生产中是不可以容忍的。

4.解决方案(三种)

​ 1、添加心跳线。

            原来两个 namenode 之间只有一条心跳线路,此时若断开,则接收不到心跳报告,判断对方已经死亡。此时若有 2 条心跳线路,一条断开,另一条仍然能够接收心跳报告,能保证集群服务正常运行。2 条心跳线路同时断开的可能性比 1 条心跳线路断开的小得多。再有,心跳线路之间也可以 HA(高可用),这两条心跳线路之间也可以互相检测,若一条断开,则另一条马上起作用。正常情况下,则不起作用,节约资源。

​ 2、启用磁盘锁。

            由于两个 active 会争抢资源,导致从节点不知道该连接哪一台 namenode,可以使用磁盘锁的形式,保证集群中只能有一台 namenode 获取磁盘锁,对外提供服务,避免数据错乱的情况发生。但是,也会存在一个问题,若该 namenode 节点宕机,则不能主动释放锁,那么其他的 namenode 就永远获取不了共享资源。因此,在 HA 上使用"智能锁"就成为了必要措施。"智能锁"是指 active 的 namenode 检测到了心跳线全部断开时才启动磁盘锁,正常情况下不上锁。保证了假死状态下,仍然只有一台 namenode 的节点提供服务。

​ 3、设置仲裁机制

            脑裂导致的后果最主要的原因就是从节点不知道该连接哪一台 namenode,此时如果有一方来决定谁留下,谁放弃就最好了。因此出现了仲裁机制,比如提供一个参考的 IP 地址,当出现脑裂现象时,双方接收不到对方的心跳机制,但是能同时 ping 参考 IP,如果有一方 ping 不通,那么表示该节点网络已经出现问题,则该节点需要自行退出争抢资源的行列,或者更好的方法是直接强制重启,这样能更好的释放曾经占有的共享资源,将服务的提供功能让给功能更全面的 namenode 节点。

以上的 3 种方式可以同时使用,这样更能减少集群中脑裂情况的发生。但是还是不能保证完全不出现,如果仲裁机制中 2 台机器同时宕机,那么此时集群中没有 namenode 可以使用。此时需要运维人员人工的抢修,或者提供一台新的机器作为 namenode,这个时间是不可避免的。希望未来能有更好的解决办法,能彻底杜绝这类情况的发生吧~

  • ZooKeeper

    ZooKeeper 是一个分布式的,开放源码的分布式应用程序协调服务,是 Google 的 Chubby 一个开源的实现,是 Hadoop 和 HBase 的重要组件。它是一个为分布式应用提供一致性服务的软件,提供的功能包括:配置维护、域名服务、分布式同步、组服务等。

    59 引用 • 29 回帖 • 14 关注
  • 脑裂
    1 引用

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...