热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

主从同步_百度QA金BUG集锦之《Redis主从同步失败案例的步步深入》

篇首语:本文由编程笔记#小编为大家整理,主要介绍了百度QA金BUG集锦之《Redis主从同步失败案例的步步深入》相关的知识,希望对你有一定的参考价值。

篇首语:本文由编程笔记#小编为大家整理,主要介绍了百度QA金BUG集锦之《Redis主从同步失败案例的步步深入》相关的知识,希望对你有一定的参考价值。




在百度质量部,QA的看家本领之一就是发现问题、定位问题、推动问题的妥善修复。本期《金BUG》专辑汇总了几例BUG发现分析解决的案例,欢迎各路英雄关注并讨论




一、背景

2015.7.31 某网段的TOR故障一小时,网络故障恢复后,redis 多个从主从同步异常:除slave0外,其他slave的offset均比master大。


注:redis的主从之间通过offset进行增量同步,即从向主发送它当前存储数据的offset,主将这个offset之后的增量数据同步给从,以保证主从数据一致。然而线上出现从的offset比主大,说明主从同步的逻辑存在问题。



二、问题影响

Redis主从同步分三种:



  1. 全量同步(主从首次连接或者增量同步失败) —— redis主dump出所有的数据发给从;


  2. 增量同步(主从连接瞬断)—— redis主将slave发送的offset之后的数据发给从;


  3. 长连接同步(正常情况) —— redis主从维护一个长连接,redis主将所有写请求发给从;



该问题只会影响redis主和从的增量同步,即网络瞬断时会影响同步,影响分为两种:



  1. 发生问题后,进行增量同步时从的offset比主大:增量同步失败,进行全量同步,对redis从中的数据不影响;


  2. 发生问题后,进行增量同步时从的offset比主小(出现问题时从的offset比主大,但是随着主写入数据,offset可能会超过从):主从增量同步异常,从中的数据比主少。




三、Bug定位



  • 异常原因


由问题背景可看出bug由从的replica_offset引起,分析代码中会修改从的offset的逻辑:




  • 初始化:从的offset是在向主请求增量同步失败后由主返回:百度QA金BUG集锦之《Redis主从同步失败案例的步步深入》


  • 从接受到”+FULLRESYNC”响应后,更新offset:


百度QA金BUG集锦之《Redis主从同步失败案例的步步深入》



  • Offset更新:全量同步完成后,主从长连接正常同步时,每次请求offset均自增:


百度QA金BUG集锦之《Redis主从同步失败案例的步步深入》

结合offset初始化和更新的代码逻辑,可以推断offset异常由主从全量同步引起,原因如下:



  1. 如背景所述,发生问题时主从连接断开,无法进行正常同步,因此不存在正常同步导致offset异常;


  2. 正常同步中offset只会比主少,不会比主多。





  • 源码分析



分析redis主处理增量同步的代码逻辑,画出简化的流程图如下:

百度QA金BUG集锦之《Redis主从同步失败案例的步步深入》

抽出master返回offset逻辑如下:

百度QA金BUG集锦之《Redis主从同步失败案例的步步深入》

Master会先设置psync_offset(要发给从的offset)为master当前的offset,然后判断是否有在做bgsave操作,如果已经有从在做bgsave,则复制已经在做bgsave的从的outputbuffer(这个buffer会作为dump同步完后的新增数据发送给从)——至此,问题已出现:

百度QA金BUG集锦之《Redis主从同步失败案例的步步深入》

当第一个从进行全量同步时,主将它当前的offseto1返回给从,并且开始做bgsave同时将新增的写请求数据写入第一个从的repl_buffer中,同步完dump数据后,从repl_buffer中发送增量数据,此时o1+增量数据刚好等于master的offset;而在第一个从的bgsave未完成时,若第一个从申请全量同步,则主返回它当前的offset o2(必然比o1大),判断到slave1已在做bgsave,此时不再做bgsave,直接复制s1的repl_buffer到s2的repl_buffer中,并且master新增的数据也开始写到s2的repl_buffer中,同步完dump数据后,从repl_buffer发送增量数据并同步offset。

注意:



  1. 此时s1和s2的增量数据完全相同;


  2. o2 > o1;


  3. o1 + 增量数据 = master的offset;


因此从2的offset比主大。



四、问题修复

确定问题后,RD对代码进行了修复:需要做全量同步时,master不再返回当前的offset,而是返回首次做bgsave时保存的offset:

百度QA金BUG集锦之《Redis主从同步失败案例的步步深入》

缓存server.fullsync_repl_offset,每次全量同步时返回同样的offset。



五、测试

问题已修复,需要回归测试,测试做CR时仔细核对主从同步过程,发现有如下逻辑:


若第一个从申请全量同步时,主已经在做bgsave(请注意,这里的bgsave是主自动触发的),这时会将从的offset标记为主当前的,并且标记从为WAIT_BGSAVE_START,等待bgsave结束后再次开启bgsave,而这时从的offset比主小。



六、新的问题

这种情况下,若主已在做bgsave:



  1. 从请求做全量同步,则主会返回从一个offset o1,并且标记从为WAIT_BGSAVE_START;


  2. 等bgsave结束后再次开启bgsave,记此时主的offset为o2,并将主的增量数据写到从的buffer中;


  3. 同步完dump的数据后同步增量数据,此时主的offset为o2+增量数据,而从的offset为o1+增量数据;


  4. 显然,o1



事实上,这个问题若出现,将比上一个问题影响更大:从的offset比主小,只要网络瞬断,则从的数据必然异常,并且会重复写一部分数据(o2-o1对应的数据段),造成线上主从数据不一致。


七、修复方案

可幸的是,在我们发现第二个问题后,redis官方给出了这一系列问题的解决方法:https://github.com/antirez/redis/commit/bea1259190a9f3c3850b074ef7d0af0bc3ea36a7

官方的解决方法为:从申请做全量同步时,不再立即返回主的offset,而是放在buffer中作为增量数据发送。


八、总结

这个bug算是隐藏很深的一个超大bug了,在作者修复前,开源社区使用redis的公司应该都或多或少的受到了这个问题的影响。

目前来看,底层服务的这种bug很难发现:



  1. 功能测试实在无法覆盖层出不穷的异常场景,redis开源社区已有的自动化case数已达200多项,然而这个bug还是隐藏了很久;


  2. QA和RD没有足够的精力去CR整个服务的代码。



测试中应注意的问题




  1. 测试应加大CR力度,对代码足够了解才能写出足够完善的case;


  2. CR时应尽可能分析代码的所有逻辑,避免出现特殊情况;对QA来说,CR不只是阅读代码逻辑,也要检查代码逻辑的问题——CR代码时尽量画出一个流程图(至少大脑里要有一个),之后分析代码逻辑:



    1. 检查各个变量的初始化及调用位置,判断是否会有脏值;


    2. 检查动态内存的申请和释放位置,判断是否会内存泄漏或者使用野指针;


    3. 检查代码分支,不同的分支是否能做正确的响应;




问题定位应注意的问题:



  1. 分析bug产生的原因,尽可能详细到变量或者函数;


  2. 阅读代码逻辑,查看变量/函数的初始化位置/调用位置或改变位置;


  3. 分析变量/函数出错可能的原因,检查对应的代码逻辑;






推荐阅读
  • 图解redis的持久化存储机制RDB和AOF的原理和优缺点
    本文通过图解的方式介绍了redis的持久化存储机制RDB和AOF的原理和优缺点。RDB是将redis内存中的数据保存为快照文件,恢复速度较快但不支持拉链式快照。AOF是将操作日志保存到磁盘,实时存储数据但恢复速度较慢。文章详细分析了两种机制的优缺点,帮助读者更好地理解redis的持久化存储策略。 ... [详细]
  • 计算机存储系统的层次结构及其优势
    本文介绍了计算机存储系统的层次结构,包括高速缓存、主存储器和辅助存储器三个层次。通过分层存储数据可以提高程序的执行效率。计算机存储系统的层次结构将各种不同存储容量、存取速度和价格的存储器有机组合成整体,形成可寻址存储空间比主存储器空间大得多的存储整体。由于辅助存储器容量大、价格低,使得整体存储系统的平均价格降低。同时,高速缓存的存取速度可以和CPU的工作速度相匹配,进一步提高程序执行效率。 ... [详细]
  • 本文介绍了Redis的基础数据结构string的应用场景,并以面试的形式进行问答讲解,帮助读者更好地理解和应用Redis。同时,描述了一位面试者的心理状态和面试官的行为。 ... [详细]
  • 解决Cydia数据库错误:could not open file /var/lib/dpkg/status 的方法
    本文介绍了解决iOS系统中Cydia数据库错误的方法。通过使用苹果电脑上的Impactor工具和NewTerm软件,以及ifunbox工具和终端命令,可以解决该问题。具体步骤包括下载所需工具、连接手机到电脑、安装NewTerm、下载ifunbox并注册Dropbox账号、下载并解压lib.zip文件、将lib文件夹拖入Books文件夹中,并将lib文件夹拷贝到/var/目录下。以上方法适用于已经越狱且出现Cydia数据库错误的iPhone手机。 ... [详细]
  • 篇首语:本文由编程笔记#小编为大家整理,主要介绍了软件测试知识点之数据库压力测试方法小结相关的知识,希望对你有一定的参考价值。 ... [详细]
  • 一次上线事故,30岁+的程序员踩坑经验之谈
    本文主要介绍了一位30岁+的程序员在一次上线事故中踩坑的经验之谈。文章提到了在双十一活动期间,作为一个在线医疗项目,他们进行了优惠折扣活动的升级改造。然而,在上线前的最后一天,由于大量数据请求,导致部分接口出现问题。作者通过部署两台opentsdb来解决问题,但读数据的opentsdb仍然经常假死。作者只能查询最近24小时的数据。这次事故给他带来了很多教训和经验。 ... [详细]
  • 本文介绍了解决Netty拆包粘包问题的一种方法——使用特殊结束符。在通讯过程中,客户端和服务器协商定义一个特殊的分隔符号,只要没有发送分隔符号,就代表一条数据没有结束。文章还提供了服务端的示例代码。 ... [详细]
  • Android中高级面试必知必会,积累总结
    本文介绍了Android中高级面试的必知必会内容,并总结了相关经验。文章指出,如今的Android市场对开发人员的要求更高,需要更专业的人才。同时,文章还给出了针对Android岗位的职责和要求,并提供了简历突出的建议。 ... [详细]
  • 本文介绍了C#中生成随机数的三种方法,并分析了其中存在的问题。首先介绍了使用Random类生成随机数的默认方法,但在高并发情况下可能会出现重复的情况。接着通过循环生成了一系列随机数,进一步突显了这个问题。文章指出,随机数生成在任何编程语言中都是必备的功能,但Random类生成的随机数并不可靠。最后,提出了需要寻找其他可靠的随机数生成方法的建议。 ... [详细]
  • 本文介绍了如何使用php限制数据库插入的条数并显示每次插入数据库之间的数据数目,以及避免重复提交的方法。同时还介绍了如何限制某一个数据库用户的并发连接数,以及设置数据库的连接数和连接超时时间的方法。最后提供了一些关于浏览器在线用户数和数据库连接数量比例的参考值。 ... [详细]
  • [译]技术公司十年经验的职场生涯回顾
    本文是一位在技术公司工作十年的职场人士对自己职业生涯的总结回顾。她的职业规划与众不同,令人深思又有趣。其中涉及到的内容有机器学习、创新创业以及引用了女性主义者在TED演讲中的部分讲义。文章表达了对职业生涯的愿望和希望,认为人类有能力不断改善自己。 ... [详细]
  • 如何用UE4制作2D游戏文档——计算篇
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了如何用UE4制作2D游戏文档——计算篇相关的知识,希望对你有一定的参考价值。 ... [详细]
  • 本文介绍了Python爬虫技术基础篇面向对象高级编程(中)中的多重继承概念。通过继承,子类可以扩展父类的功能。文章以动物类层次的设计为例,讨论了按照不同分类方式设计类层次的复杂性和多重继承的优势。最后给出了哺乳动物和鸟类的设计示例,以及能跑、能飞、宠物类和非宠物类的增加对类数量的影响。 ... [详细]
  • 基于Socket的多个客户端之间的聊天功能实现方法
    本文介绍了基于Socket的多个客户端之间实现聊天功能的方法,包括服务器端的实现和客户端的实现。服务器端通过每个用户的输出流向特定用户发送消息,而客户端通过输入流接收消息。同时,还介绍了相关的实体类和Socket的基本概念。 ... [详细]
  • 全面介绍Windows内存管理机制及C++内存分配实例(四):内存映射文件
    本文旨在全面介绍Windows内存管理机制及C++内存分配实例中的内存映射文件。通过对内存映射文件的使用场合和与虚拟内存的区别进行解析,帮助读者更好地理解操作系统的内存管理机制。同时,本文还提供了相关章节的链接,方便读者深入学习Windows内存管理及C++内存分配实例的其他内容。 ... [详细]
author-avatar
俊铭心怡雅琪
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有