文章目录
- Redis 中的脑裂是什么?
- 脑裂有什么影响?
- 数据丢失一定是发生了脑裂吗?
- 如何解决脑裂问题?
Redis 中的脑裂是什么?
从名字分析,脑裂现象就是大脑裂开了,一个人如果有两个大脑,就出现了两个决策者,此时身体就不知道该听谁的了,势必会造成混乱。
对应到 Redis 上,就是指在主从集群中,同时有两个主节点,它们都能接收写请求,那么什么时候会出现这种情况呢?
就是如果当前主库突然出现暂时性 “失联”,而并不是真的发生了故障,此时监听的哨兵会自动启动主从切换机制。当这个原始的主库从假故障中恢复后,又开始处理请求,但是哨兵已经选出了新的主库,这样一来,旧的主库和新主库就会同时存在,这就是脑裂现象。
脑裂有什么影响?
脑裂最直接的影响,就是客户端不知道应该往哪个主节点写入数据,结果就是不同的客户端会往不同的主节点上写入数据。严重的话,脑裂会进一步导致数据丢失。也就是说,等到哨兵让原主库和新主库做全量同步后,原主库在切换期间保存的数据就丢失了。
详细点来说,当主从切换后,从库升级为新主库,原主库和新主库会重新进行数据的全量同步,在这个过程中会发生数据的丢失,过程如下所示:
- 从服务器 Slave 向主服务器 Master 发送数据同步命令;
- Master 主服务器接收到同步命令后,保存快照生成 RDB 文件,同时使用缓冲区记录从现在开始执行的所有写命令;
- Master 主服务器将快照文件(RDB文件)发送给 Slave 从服务器,Slave 从服务器接收到后,清空旧数据,载入新数据;
- Master 主服务器快照发送完后开始向 Slave 从服务器发送缓冲区的写命令,Slave 从服务器接收命令并执行,完成复制初始化;
- 此后 Master 主服务器每次执行一个写命令都会同步发送给 Slave 从服务器,保持相互之间数据的一致性;
上述步骤中的关键一步就是,原主库需要清空本地的数据后加载新主库发送的 RDB 文件,这样一来,原主库在主从切换期间保存的新写数据就丢失了。
数据丢失一定是发生了脑裂吗?
那可能你想问了,数据丢失一定是发生了脑裂吗?如何判断发生了脑裂?
数据丢失不一定是发生了脑裂,最常见的原因是主库的数据还没有同步到从库,结果主库发生了故障,等从库升级为主库后,未同步的数据就丢失了。
如果是这种情况的数据丢失,我们可以通过比对主从库上的复制进度差值来进行判断,也就是计算 master_repl_offset 和 slave_repl_offset 的差值。如果从库上的 slave_repl_offset 小于原主库的 master_repl_offset,那么,我们就可以认定数据丢失是由数据同步未完成导致的。
而判断是否发生了脑裂,可以采取排查客户端的操作日志的方式。
通过看日志能够发现,在主从切换后的一段时间内,会有客户端仍然在和原主库通信,并没有和升级的新主库进行交互,这就相当于主从集群中同时有了两个主库。根据这个迹象,我们就可以判断可能是发生了脑裂。
如何解决脑裂问题?
Redis 中有两个关键的配置项可以解决这个问题,分别是 min-slaves-to-write(最小从服务器数) 和 min-slaves-max-lag(从连接的最大延迟时间)。
min-slaves-to-write 是指主库最少得有 N 个健康的从库存活才能执行写命令。
这个配置虽然不能保证 N 个从库都一定能接收到主库的写操作,但是能避免当没有足够健康的从库时,主库无法正常写入,以此来避免数据的丢失 ,如果设置为 0 则表示关闭该功能。
min-slaves-max-lag :是指从库和主库进行数据复制时的 ACK 消息延迟的最大时间;
可以确保从库在指定的时间内,如果 ACK 时间没在规定时间内,则拒绝写入。
这两个配置项组合后的要求是,主库连接的从库中至少有 N 个从库,和主库进行数据复制时的 ACK 消息延迟不能超过 T 秒,否则,主库就不会再接收客户端的请求了。
这样一来,即使原主库是假故障,它在假故障期间也无法响应哨兵发出的心跳测试,也不能和从库进行同步,自然也就无法和从库进行 ACK 确认了。
此时的 min-slaves-to-write 和 min-slaves-max-lag 的组合要求就无法得到满足,原主库就会被限制接收客户端请求,客户端也就不能在原主库中写入新数据,就可以避免脑裂现象的发生了。
参考文献
- https://www.jianshu.com/p/e12608ee15a5
- https://zhuanlan.zhihu.com/p/308534431
- https://time.geekbang.org/column/article/303568