1.概述

所谓的脑裂,就是指在主从集群中,同时有两个主节点,它们都能接收写请求。而脑裂最直接的影响,就是客户端不知道应该往哪个主节点写入数据,结果就是不同的客户端会往不同的主节点上写入数据。而且,严重的话,脑裂会进一步导致数据丢失。

2.主从集群中的数据丢失

2.1 数据同步未完成

最常见的原因就是主库的数据还没有同步到从库,结果主库发生了故障,等从库升级为主库后,未同步的数据就丢失了。
排查:
比对主从库上的复制进度差值来进行判断,也就是计算 master_repl_offset和 slave_repl_offset 的差值。
image.png

  1. if(slave_repl_offset < master_repl_offset){
  2. //认定数据丢失是由数据同步未完成导致的。
  3. }else if(slave_repl_offset = master_repl_offset){
  4. //集群脑裂
  5. }

2.2 原主库加故障导致的集群脑裂

在哨兵机制将主库判断为客观下线后,哨兵开始执行切换操作,客户端与新主库通信,但是切换过程中,客户端仍然和原主库通信,这就表明原主库并没有真的发生故障。正因为原主库并没有真的发生故障,我们在客户端操作日志中就看到了和原主库的通信记录。等到从库被升级为新主库后,主从集群里就有两个主库了。

假故障的两个原因:

1.和主库部署在同一台服务器上的其他程序临时占用了大量资源(例如 CPU 资源),导致主库资源使用受限,短时间内无法响应心跳。其它程序不再使用资源时,主库又恢复正常。
2.主库自身遇到了阻塞的情况,例如,处理 bigkey 或是发生内存 swap,短时间内无法响应心跳,等主库阻塞解除后,又恢复正常的请求处理了。

bigkey删除导致的阻塞

删除操作的本质是要释放键值对占用的内存空间。释放内存只是第一步,为了更高效地管理内存空间,在应用程序释放内存时,操作系统需要把释放掉的内存块插入一个空闲内存块的链表,以便后续进行管理和再分配。这个过程本身需要一定时间,而且会阻塞当前释放内存的应用程序,所以,如果一下子释放了大量内存,空闲内存块链表操作时间就会增加,相应地就会造成 Redis 主线程的阻塞
image.png
image.png

脑裂是如何导致数据丢失的

image.png

如何应对脑裂问题

min-slaves-to-write:这个配置项设置了主库能进行数据同步的最少从库数量
min-slaves-max-lag:这个配置项设置了主从库间进行数据复制时,从库给主库发送ACK 消息的最大延迟(以秒为单位)。
这两个配置项组合后的要求是,主库连接的从库中至少有 N 个从库,和主库进行数据复制时的 ACK 消息延迟不能超过 T 秒,否则,主库就不会再接收客户端的请求即使原主库是假故障,它在假故障期间也无法响应哨兵心跳,也不能和从库进行同步,自然也就无法和从库进行 ACK 确认了。这样一来,min-slaves-to-write 和 min-slaves-max-lag 的组合要求就无法得到满足,原主库就会被限制接收客户端请求,客户端也就不能在原主库中写入新数据了。