1. 前言

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

2. 为什么会发生脑裂?

第一步:确认是不是数据同步出现了问题
  在主从集群中发生数据丢失,最常见的原因就主库的数据还没有同步到从库,结果主库发生了故障,等从库升级为主库后,未同步的数据就丢失了。

  如果是这种情况的数据丢失,我们可以通过比对主从库上的复制进度差值来进行判断,也就是计算 master_repl_offset 和 slave_repl_offset 的差值。如果从库上的slave_repl_offset 小于原主库的 master_repl_offset,那么,我们就可以认定数据丢失是由数据同步未完成导致的。

第二步:排查客户端的操作日志,发现脑裂现象
  在排查客户端的操作日志时,我们发现,在主从切换后的一段时间内,有一个客户端仍然在和原主库通信,并没有和升级的新主库进行交互。这就相当于主从集群中同时有了两个主库。根据这个迹象,我们就想到了在分布式主从集群发生故障时会出现的一个问题:脑裂。
  但是,不同客户端给两个主库发送数据写操作,按道理来说,只会导致新数据会分布在不同的主库上,并不会造成数据丢失。那么,为什么我们的数据仍然丢失了呢?到这里,我们的排查思路又一次中断了。
  不过,在分析问题时,我们一直认为“从原理出发是追本溯源的好方法”。脑裂是发生在主从切换的过程中,我们猜测,肯定是漏掉了主从集群切换过程中的某个环节,所以,我们把研究的焦点投向了主从切换的执行过程。

第三步:发现是原主库假故障导致的脑裂
  我们是采用哨兵机制进行主从切换的,当主从切换发生时,一定是有超过预设数量(quorum 配置项)的哨兵实例和主库的心跳都超时了,才会把主库判断为客观下线,然后,哨兵开始执行切换操作。哨兵切换完成后,客户端会和新主库进行通信,发送请求操作。
  但是,在切换过程中,既然客户端仍然和原主库通信,这就表明,原主库并没有真的发生故障(例如主库进程挂掉)。我们猜测,主库是由于某些原因无法处理请求,也没有响应哨兵的心跳,才被哨兵错误地判断为客观下线的。结果,在被判断下线之后,原主库又重新开始处理请求了,而此时,哨兵还没有完成主从切换,客户端仍然可以和原主库通信,客户端发送的写操作就会在原主库上写入数据了。

3. 为什么脑裂会导致数据丢失

  主从切换后,从库一旦升级为新主库,哨兵就会让原主库执行 slave of 命令,和新主库重新进行全量同步。而在全量同步执行的最后阶段,原主库需要清空本地的数据,加载新主库发送的 RDB 文件,这样一来,原主库在主从切换期间保存的新写数据就丢失了。

  在主从切换的过程中,如果原主库只是“假故障”,它会触发哨兵启动主从切换,一旦等它从假故障中恢复后,又开始处理请求,这样一来,就会和新主库同时存在,形成脑裂。等到哨兵让原主库和新主库做全量同步后,原主库在切换期间保存的数据就丢失了。

4. 如何应对脑裂问题

  既然问题是出在原主库发生假故障后仍然能接收请求上,我们就开始在主从集群机制的配置项中查找是否有限制主库接收请求的设置。Redis 已经提供了两个配置项来限制主库的请求处理,分别是 min-slaves-to-write 和 min-slaves-max-lag。

  • min-slaves-to-write:这个配置项设置了主库能进行数据同步的最少从库数量;
  • min-slaves-max-lag:这个配置项设置了主从库间进行数据复制时,从库给主库发送ACK 消息的最大延迟(以秒为单位)。

  我们可以把 min-slaves-to-write 和 min-slaves-max-lag 这两个配置项搭配起来使用,分别给它们设置一定的阈值,假设为 N 和 T。这两个配置项组合后的要求是,主库连接的从库中至少有 N 个从库,和主库进行数据复制时的 ACK 消息延迟不能超过 T 秒,否则,主库就不会再接收客户端的请求了。
  等到新主库上线时,就只有新主库能接收和处理客户端请求,此时,新写的数据会被直接写到新主库中。而原主库会被哨兵降为从库,即使它的数据被清空了,也不会有新数据丢失。
  假设我们将 min-slaves-to-write 设置为 1,把 min-slaves-max-lag 设置为 12s,把哨兵的 down-after-milliseconds 设置为 10s,主库因为某些原因卡住了 15s,导致哨兵判断主库客观下线,开始进行主从切换。同时,因为原主库卡住了 15s,没有一个从库能和原主库在 12s 内进行数据复制,原主库也无法接收客户端请求了。这样一来,主从切换完成后,也只有新主库能接收请求,不会发生脑裂,也就不会发生数据丢失的问题了。

小结

  这节课,我们学习了主从切换时可能遇到的脑裂问题。脑裂是指在主从集群中,同时有两个主库都能接收写请求。在 Redis 的主从切换过程中,如果发生了脑裂,客户端数据就会写入到原主库,如果原主库被降为从库,这些新写入的数据就丢失了。
  为了应对脑裂,你可以在主从集群部署时,
通过合理地配置参数 min-slaves-to-write 和min-slaves-max-lag,来预防脑裂的发生。
  在实际应用中,可能会因为网络暂时拥塞导致从库暂时和主库的 ACK 消息超时。在这种情况下,并不是主库假故障,我们也不用禁止主库接收请求。
  所以,我给你的建议是,假设从库有 K 个,可以将 min-slaves-to-write 设置为K/2+1(如果 K 等于 1,就设为 1),将 min-slaves-max-lag 设置为十几秒(例如 10~20s),在这个配置下,如果有一半以上的从库和主库进行的 ACK 消息延迟超过十几秒,我们就禁止主库接收客户端写请求。

11 | 脑裂: 一次奇怪的数据丢失相关推荐

  1. Redis集群脑裂导致数据丢失问题处理

    什么是Redis的集群脑裂: Redis的集群脑裂指在主从集群中,同时有两个master主节点,它们都能接收写请求.而脑裂最直接的影响,就是客户端不知道应该往哪个master主节点写入数据,结果就是不 ...

  2. Redis集群脑裂、Redis主从同步的异步丢数据问题

    什么是Redis的集群脑裂? Redis的集群脑裂指在主从集群中,同时有两个master主节点,它们都能接收写请求.而脑裂最直接的影响,就是客户端不知道应该往哪个master主节点写入数据,结果就是不 ...

  3. 中发生数据丢失_如何防止Redis脑裂导致数据丢失?

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

  4. REDIS哨兵【Sentinel】模式+哨兵的核心知识点+redis哨兵主从切换的数据丢失问题+上一章铺垫的【异步复制数据丢失问题】+【集群脑裂】

    1.redis哨兵模式的前言: 一年一度的问题来了,为啥子要用redis的哨兵模式的呢? 简单粗暴的理解下子,顺带开个玩笑,没有理解好,还望不要见笑: 其实redis的哨兵模式,个人理解:只是说法搞大 ...

  5. Elasticsearch:理解 Master,Elections,Quorum 及 脑裂

    集群中的每个节点都可以分配多个角色:master.data.ingest.ml(机器学习)等. 我们在当前讨论中感兴趣的角色之一是 master 角色. 在 Elasticsearch 的配置中,我们 ...

  6. keepalived高可用解决脑裂,nginx高可用配置详细篇

    第一章 keepalived介绍 keepalived软件起初是专为LVS负载均衡软件设计的,用来管理并监控LVS集群系统中各个服务节点状态,后来又加入了可以实现高可用的VRRP功能.此,keepal ...

  7. mysql 脑裂的问题,DRBD脑裂问题故障处理

    环境:Mysql+heartbeat+drbd 架构 问题:mysql-主 宕机 mysql-从接替之后,再恢复Mysql-主之后,发现主的drbd启动不了,而且从上面也无法辨识对方,从的状态是Pri ...

  8. Oracle脑裂 驱逐,了解Oracle RAC Brain Split Resolution集群脑裂协议

    当实际的NM Reconfiguration集群重置情况发生时所有的active节点和正在加入集群的节点都会参与到reconfig中,那些没有应答(ack)的节点都将不再被归入新的集群关系中.实际上r ...

  9. Elasticsearch master节点的作用以及脑裂现象

    Master节点 Master节点的主要职责是和集群操作相关的内容,例如创建或删除索引.跟踪哪些节点是集群的一部分,并决定哪些分片分配给相关的节点. 稳定的主节点对集群的健康是非常重要的.默认情况下任 ...

最新文章

  1. LINUX下直接使用ISO文件
  2. for each....in、for in、for of
  3. hbase里插入big int数据用Phoenix查看的报错问题
  4. 很强大的FFMPEG API Documentation
  5. python flask和django_真正搞明白Python中Django和Flask框架的区别
  6. 网络视频ts格式文件下载及将其合成单一视频文件
  7. 我为什么觉得程序员是个高危职业
  8. php中开通短信验证码,php利用云片网实现短信验证码功能的示例代码
  9. 跟随阿里云贾扬清,走近AI开发者的奇幻漂流
  10. Python/用 Pgzrun 库做一个简单小游戏
  11. linux重启关机命令
  12. IOS开发工具介绍之Xcode开发工具使用
  13. STL--String类的常用功能复写
  14. linux dev sda 不存在,我查看linux分区情况为什么不是dev/hda而是dev/sda阿
  15. 查看window7开机日志
  16. linux 更改Chrome 默认下载器为uGet
  17. Android 2020年夏招面试题(一)
  18. [DEP_WEBPACK_COMPILATION_ASSETS] DeprecationWarning: Compilation.assets will be frozen in future
  19. 软件测试_笔记(完整版)
  20. Android开启telnet服务

热门文章

  1. 面向对象三大特性 -- 继承,封装,多态
  2. [异能程序员]第五章 出手(第一更)
  3. 让IE6支持图片半透明
  4. 如何在三个月掌握三年的经验
  5. linux 脚本 if else,基于shell的if和else详解
  6. 前端获取后端传来的session_java后台如何获取,前台传来的表单数据
  7. 线性代数知识点总结_考研数学线性代数部分怎样复习
  8. android.mk编译动态库,安卓之Android.mk多文件以及动态库编译
  9. 用c语言编程矩阵乘法,c语言矩阵相乘
  10. 计算机开机跳过硬盘检查,电脑开机后如何跳过磁盘检查过程?