写点什么

【Redis 集群原理专题】分析一下相关的 Redis 集群模式下的脑裂问题!

作者:浩宇天尚
  • 2021 年 12 月 04 日
  • 本文字数:2602 字

    阅读完需:约 9 分钟

【Redis集群原理专题】分析一下相关的Redis集群模式下的脑裂问题!

技术格言

世界上并没有完美的程序,但是我们并不因此而沮丧,因为写程序就是一个不断追求完美的过程。

什么是脑裂

字面含义

首先,脑裂从字面上理解就是脑袋裂开了,就是思想分家了,就是有了两个山头,就是有了两个主思想。

技术定义

在高可用集群中,当两台高可用服务器在指定的时间内,由于网络的原因无法互相检测到对方心跳而各自启动故障转移功能,取得了资源以及服务的所有权,而此时的两台高可用服务器对都还活着并作正常运行,这样就会导致同一个服务在两端同时启动而发生冲突的严重问题,最严重的就是两台主机同时占用一个 VIP 的地址(类似双端导入概念),当用户写入数据的时候可能会分别写入到两端,这样可能会导致服务器两端的数据不一致或造成数据的丢失,这种情况就称为裂脑,也有的人称之为分区集群或者大脑垂直分隔,互相接管对方的资源,出现多个 Master 的情况,称为脑裂。


脑裂导致的问题

引起数据的不完整性:在集群节点出现脑裂的时候,如果外部无法判断哪个为主节点,脑裂的集群都可以正常访问的时候,这时候就会出现数据不完整的可能性。


  • 服务异常:对外提供服务出现异常。

导致裂脑发生的原因

优先考虑心跳线路上的问题,在可能是心跳服务,软件层面的问题


  • 1)高可用服务器对之间心跳线路故障,导致无法正常的通信。原因比如:

  • 1——心跳线本身就坏了(包括断了,老化);

  • 2——网卡以及相关驱动坏了,IP 配置及冲突问题;

  • 3——心跳线间连接的设备故障(交换机的故障或者是网卡的故障);

  • 4——仲裁的服务器出现问题。

  • 2)高可用服务器对上开启了防火墙阻挡了心跳消息的传输;

  • 3)高可用服务器对上的心跳网卡地址等信息配置的不正确,导致发送心跳失败;

  • 4)其他服务配置不当等原因,如心跳的方式不同,心跳广播冲突,软件出现了 BUG 等。

解决脑裂所出现的问题

  • 添加冗余的心跳线,尽量减少“脑裂”的机会

  • 启用磁盘锁:在发生脑裂的时候可以协调控制对资源的访问设置仲裁机制


实际的生产环境中,我们可以从以下几个方面来防止裂脑的发生:


  • 1)同时使用串行电缆和以太网电缆连接,同时用两条心跳线路,这样一条线路坏了,另一个线路还是好的,依然能传送消息(推荐的)

  • 2)检测到裂脑的时候强行的关闭一个心跳节点(需要特殊的节点支持,如 stonith,fence),相当于程序上备节点发现心跳线故障,发送关机命令到主节点。

  • 3)多节点集群中,可以通过增加仲裁的机制,确定谁该获得资源,这里面有几个参考的思路:

  • 1——增加一个仲裁机制。例如设置参考的 IP,当心跳完全断开的时候,2 个节点各自都 ping 一下参考的 IP,不同则表明断点就出现在本段,这样就主动放弃竞争,让能够 ping 通参考 IP 的一端去接管服务。

  • 2——通过第三方软件仲裁谁该获得资源,这个在阿里有类似的软件应用

  • 4)做好对裂脑的监控报警(如邮件以及手机短信等),在问题发生的时候能够人为的介入到仲裁,降低损失。当然,在实施高可用方案的时候,要根据业务的实际需求确定是否能够容忍这样的损失。对于一般的网站业务,这个损失是可控的(公司使用)

  • 5)启用磁盘锁。正在服务一方锁住共享磁盘,脑裂发生的时候,让对方完全抢不走共享的磁盘资源。但使用锁磁盘也会有一个不小的问题,如果占用共享盘的乙方不主动解锁,另一方就永远得不到共享磁盘。现实中介入服务节点突然死机或者崩溃,另一方就永远不可能执行解锁命令。后备节点也就截关不了共享的资源和应用服务。于是有人在 HA 中涉及了“智能”锁,正在服务的一方只在发现心跳线全部断开时才启用磁盘锁,平时就不上锁了

什么是 redis 脑裂?

如果在 redis 中,形式上就是有了两个 master,记住两个 master 才是脑裂的前提。

哨兵(sentinel)模式下的脑裂


1 个 master 与 3 个 slave 组成的哨兵模式(哨兵独立部署于其它机器),刚开始时,2 个应用服务器 server1、server2 都连接在 master 上,如果 master 与 slave 及哨兵之间的网络发生故障,但是哨兵与 slave 之间通讯正常,这时 3 个 slave 其中 1 个经过哨兵投票后,提升为新 master,如果恰好此时 server1 仍然连接的是旧的 master,而 server2 连接到了新的 master 上。


数据就不一致了,基于 setNX 指令的分布式锁,可能会拿到相同的锁;基于 incr 生成的全局唯一 id,也可能出现重复。

集群(cluster)模式下的脑裂


cluster 模式下,这种情况要更复杂,例如集群中有 6 组分片,每给分片节点都有 1 主 1 从,如果出现网络分区时,各种节点之间的分区组合都有可能。

手动解决问题

在正常情况下,如果 master 挂了,那么写入就会失败,如果是手动解决,那么人为会检测 master 以及 slave 的网络状况,然后视情况,如果是 master 挂了,重启 master,如果是 master 与 slave 之间的连接断了,可以调试网络,这样虽然麻烦,但是是可以保证只有一个 master 的,所以只要认真负责,不会出现脑裂。

自动解决问题

Redis 中有一个哨兵机制,哨兵机制的作用就是通过 redis 哨兵来检测 redis 服务的状态,如果一旦发现 master 挂了,就在 slave 中选举新的 master 节点以实现故障自动转移。


问题,就出现在这个自动故障转移上,如果是哨兵和 slave 同时与 master 断了联系,即哨兵可以监测到 slave,但是监测不到 master,而 master 虽然连接不上 slave 和哨兵,但是还是在正常运行,这样如果哨兵因为监测不到 master,认为它挂了,会在 slave 中选举新的 master,而有一部分应用仍然与旧的 master 交互。当旧的 master 与新的 master 重新建立连接,旧的 master 会同步新的 master 中的数据,而旧的 master 中的数据就会丢失。所以我认为 redis 脑裂就是自动故障转移造成的。

总结梳理解决方案

如何解决脑裂?


设置每个 master 限制 slave 的数量


redis 的配置文件中,存在两个参数


min-slaves-to-write 3min-slaves-max-lag 10
复制代码


  • 第一个参数表示连接到 master 的最少 slave 数量

  • 第二个参数表示 slave 连接到 master 的最大延迟时间


按照上面的配置,要求至少 3 个 slave 节点,且数据复制和同步的延迟不能超过 10 秒,否则的话 master 就会拒绝写请求,配置了这两个参数之后,如果发生集群脑裂,原先的 master 节点接收到客户端的写入请求会拒绝,就可以减少数据同步之后的数据丢失。


注意:较新版本的 redis.conf 文件中的参数变成了


min-replicas-to-write 3min-replicas-max-lag 10
复制代码


redis 中的异步复制情况下的数据丢失问题也能使用这两个参数

总结

官方文档所言,redis 并不能保证强一致性(Redis Cluster is not able to guarantee strong consistency. / In general Redis + Sentinel as a whole are a an eventually consistent system) 对于要求强一致性的应用,更应该倾向于相信 RDBMS(传统关系型数据库)。

发布于: 5 小时前阅读数: 6
用户头像

浩宇天尚

关注

🏆 InfoQ写作平台-签约作者 🏆 2020.03.25 加入

【个人简介】酷爱计算机技术、醉心开发编程、喜爱健身运动、热衷悬疑推理的”极客狂人“ 【技术格言】任何足够先进的技术都与魔法无异 【技术范畴】Java领域、Spring生态、MySQL专项、APM专题及微服务/分布式体系等

评论

发布
暂无评论
【Redis集群原理专题】分析一下相关的Redis集群模式下的脑裂问题!