设为首页 收藏本站
查看: 406|回复: 0

[经验分享] 淘宝物流MySQL slave复制数据丢失问题的个人整理

[复制链接]

尚未签到

发表于 2016-10-23 06:20:57 | 显示全部楼层 |阅读模式
  对于这几天微博上较火的关于淘宝物流MySQL slave复制数据丢失问题,我自己也比较关注,然后根据沃趣科技的一篇分析文章算是大概明白了其中的明细,现在再来根据我自己的理解理一下思路,顺便加深自己的理解。
  简单的说这个问题的来由是这样的:主库的一些DML语句在从库上没执行。那么遇到这样问题,我们一般都是从这几个方面找问题,
  

  • show slave status查看复制状态,SQL_THREAD,IO_THREAD是否正常/延迟多少
  • 上面没有问题,再看事件在主库是否记录了binlog,是否传到了从库(从relay log中查看)
  • 上面都没问题,那是否从库在这个事件的数据丢失之前就已经是M/S数据不一致了,导致DML没有有效的记录进行操作
    淘宝的这个案例就比较有意思了,上面的情况都不符合。后来他们定位到问题是由于binlog(RBR)里的table_map_event事件中的table_id在内部执行过程中传递值溢出导致的。这个table_map_event和table_id是怎么回事呢?先简单看个RBL的binlog event:


#121031 16:25:45 server id 1 end_log_pos 3466 Table_map: `test`.`tf` mapped to number 40
#121031 16:25:45 server id 1 end_log_pos 3504 Write_rows: table id 40 flags: STMT_END_F


BINLOG '
ieCQUBMBAAAAKgAAAIoNAAAAACgAAAAAAAEABHRlc3QAAnRmAAIDAwAD
ieCQUBcBAAAAJgAAALANAAAAACgAAAAAAAEAAv/8bwAAAN0AAAA=
'/*!*/;
### INSERT INTO test.tf
### SET
###  @1=111
###  @2=221
# at 3650
#121031 16:25:45 server id 1 end_log_pos 3531 Xid = 71
COMMIT/*!*/;


    红色标记部分显示了table_map_event和table_id,那么RBL为什么要这么做呢?在沃趣科技里面解释了这点(应该比较合理):一个DML可能影响很多行,而RBL是对每行进行记录,那么就用一个table_map来记录这个表的相关信息比较合理,而不是每行都记录。那table_id的作用是用来干什么的呢,简单的说它最主要的作用是用来将某个表的信息hash到cache中做hash key的,将表信息hash到cache中有是用来干什么呢?因为RBL的一个更新可能影响很多行,每行在真正应用到slave上之前必然要经过一些检查,而这些检查必然是与它将要操作的表的信息做对比验证,如果我们不将这个表的信息放到内存中,并且快速的定位到它,那么当影响的行很多时效率估计就会下降比较厉害。其实这一步本身想法没什么问题,只是MySQL当初实现时用到了这样一个table_id。
    接下来说引起这个案例的本质原因,binlog中table_id它是一个ulong类型(无符号长整形),在slave进行重做binlog events之前,它会先将这个ulong的table_id传给一个它内部维护的一个数据结构RPL_TABLE_LIST,这个里面有一个变量table_id用来存储binlog中的m_table_id(为了避免混淆,用m_table_id),好了问题出现:数据结构的变量table_id是一个uint(无符号整形),如果m_table_id超过uint的范围会发生截断。而MySQL内部在构造hash,从hash表中取值是这样的做法:set_table(table_id),get_table(m_table_id),在两个阶段用到的key因为发生了数据截断所以必然也就不能取到预期的值,因为也就发生了slave端relaylog的DML语句没有被执行这种情况。
    那怎么可以避免这个问题呢?第一,不让m_table_id太大,实际上我相信对于绝大部分公司也不会太大,淘宝这个案例的背景是这个实例有4000+的表;第二,适当的增大table_open_cache这个参数,因为m_table_id并不是与每个表的元数据信息id(类似表空间的tablespace id),它是这个表被打开时内部分配的id,当表被关闭后再次打开,那么分配给他的这个id就会递增,table_open_cache正好是控制能最多cache被打开的表。所以适当增加这个参数可行。第三,将RPL_TABLE_LIST这个内部数据结构里面的table_id类型改为ulong(已经上报bug)。
    最后一个小问题,这里为什么要用这个递增的m_table_id,而不用与表元数据的id(类似表空间的tablespace id)。因为完全可能出现这种情况,master上先DML一些数据-->然后执行了alter table-->然后继续DML,此时如果使用的与表相关的固定id, 那么第一次DML在slave上执行时就会将与之相关的表信息hash到cache中,然后alter table之后,这些cache中的数据并没有更新,当接在在DML的时候因为是用相同的id去get_table,得到不是最新的表数据信息,那么接下来真正对每行进行更新时就可能出问题了。而用了递增的m_table_id后,只要m_table_id发生了变化,那么是一定取不到之前非最新的表信息。
    些许感悟,有时候只是表面上的安全,尤其使用开源产品;多谢淘宝这样的大公司,有这样的业务才能出这样的案例;做MySQL还真得懂点源码(一个团队有人懂差不多就行了,遇到这种问题不懂源码怎么解决问题?)


参考文章:

  • http://hickey.in/?p=146物理MySQL slave复制数据部分丢失问题
  • http://vdisk.weibo.com/s/guZ8J沃趣科技对此问题的详细分析
  • http://blog.iyunv.com/uid-26896862-id-3329896.htmlCUer对binlog中table_id的源码分析

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.iyunv.com/thread-289928-1-1.html 上篇帖子: 基于tomcat+mysql的c/s模式下的系统自动更新 下篇帖子: <转>mysql对于大表(千万级),要怎么优化呢?
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表