![db2d5aeb7f2369617df9668787c8fedb.png](https://i-blog.csdnimg.cn/blog_migrate/6866a76b0f548c3512fd170df6e563f2.jpeg)
引 言
本文是由爱可生研发团队出品的「图解MySQL」系列文章,不定期更新,但篇篇精品。
爱可生开源社区持续运营维护的小目标:
- 每周至少推送一篇高质量技术文章
- 每月研发团队发布开源组件新版
- 每年1024开源一款企业级组件
- 2019年至少25场社区活动
欢迎大家持续关注~
本文分析的缺陷是MySQL bug#89370,其主要的现象是:配置半同步(复制)到多个从库,部分从库在一段时间内无法复制数据,但所有复制状态均正常。
缺陷的复现
MySQL版本:5.7.16,5.7.17,5.7.21
- 配置半同步一个master两个slave,设置master的
rpl_semi_sync_master_wait_for_slave_count=2,保持一定数据压力 - 检查master的
rpl_semi_sync_master_status状态为ON,确保半同步没有退化为异步 - 设置master的
rpl_semi_sync_master_wait_for_slave_count=1 - 重启一个slave “stop slave; start slave”
可以观察到步骤4中重启的那个slave长达数分钟不会有master的复制数据流入,但查看复制状态均正常。
缺陷的原理图解
图一:描述了半同步复制的大致流程
![24acd890814498fb223f601b5d1d9e93.png](https://i-blog.csdnimg.cn/blog_migrate/cd857428f2e0e0d13afc86b28931facf.jpeg)
- 上图中按序解析了MySQL半同步插件在binlog group commit中扮演的角色:
binlog group commit分为三个阶段:
- Flush Phase(图中序号2): 将一组事务写入binlog缓存区,向半同步插件注册事务(图中序号2.1),更新binlog文件位置信息(图中序号2.2)
- Sync Phase(图中序号4): 对binlog做fsync操作,将一组事务一起刷入磁盘
- Commit Phase(图中序号5): 等待半同步完成,在引擎层提交事务
半同步插件:
- 图中序号3:在binlog完成位置信息更新后,开始通过复制线程读取binlog文件,将其中的event发送给slave
- 图中序号5.1:将事务复制完成信息返回master,master根据该信息确定是否可以提交事务
- MySQL从5.5版本后引入了半同步插件,以解决传统异步复制在master节点宕机时可能出现的数据丢失。
- 开启半同步能够保证master接收到的事务,在得到至少一个slave接收确认之后再返回给客户端。
- MySQL 5.6版本之前存在一个著名的bug#13669,在开启binlog时为了保证引擎层与binlog的提交顺序一致,使得group commit机制失效。从5.6版本后才真正引入了binlog的group commit,在保证引擎层和binlog事务最终一致的情况下,大幅提高了高并发场景下的处理性能。
图二:描述了MySQL 5.6版本中的ACK接收机制
![d976128a1ed1b7d1f857b136a1af86f5.png](https://i-blog.csdnimg.cn/blog_migrate/c917a70c31c7402cde82df243062c0b6.jpeg)
- 在MySQL 5.6版本的实现里,master的复制线程同时负责发送事务和接收slave返回的ACK消息,当没有接收到上一个事务的ACK消息之前,无法发送下一个事务。如此串行化的机制成为了半同步的性能瓶颈。
图三:描述了MySQL 5.7版本中的ACK接收机制
![80567cd01ddc96d4710f733abf0a34ac.png](https://i-blog.csdnimg.cn/blog_migrate/5d6c0896d912febb38120d56523f6634.jpeg)
- 在MySQL 5.7版本的实现里,将接收ACK这部分任务从master的复制线程中拆分出来,由半同步插件的ACK接收线程单独处理,使得事务发送和接收ACK得以并行,极大提高了半同步性能。
图四:描述了本文缺陷的发生原因
![6e55c80091700a97da47dc96ad328484.png](https://i-blog.csdnimg.cn/blog_migrate/2289301ffbf189aa6ab0a99886209cb2.jpeg)
- 本文所要描述的缺陷就出现在ACK接收线程中,ACK线程(图中序号1)和复制线程(图中序号2)在抢占互斥锁时产生了竞争。
- master在监听slave的ACK消息时,无限的while循环使得ACK线程基本时刻占有互斥锁。当启动另一个slave时,master的新复制线程无法在短时间内抢占该互斥锁,导致复制线程无法启动成功,造成了slave的slave_io_thread 停滞,无法复制数据的现象。
扩展阅读
- https://bugs.mysql.com/bug.php?id=89370
- https://bugs.mysql.com/bug.php?id=13669
- https://kristiannielsen.livejournal.com/12254.html
精选系列
| MySQL分布式中间件使用指南 DBLE系列公开课第一课 DBLE概述 DBLE系列公开课第二课 DBLE的配置及使用 MyCat的坑如何在分布式中间件DBLE上改善(内含视频链接) | DBLE 快速入门 深度分析 | MyCat与DBLE的对比性能调优 开源分布式中间件 DBLE 快速入门指南 DBLE 自定义拆分算法 DBLE Server.xml 配置解析 DBLE Schema.xml 配置解析 DBLE rule.xml 配置解析 | MySQL深度分析 MGR相同GTID产生不同transaction故障分析 DBLE和Mycat跨分片查询结果不一致案例分析 基于Xtrabackup及可传输表空间实现多源数据恢复 [缺陷分析] Table cache 导致 MySQL 崩溃
![4ef0d90c8aa6a48a55a25a9b92f2080b.gif](https://i-blog.csdnimg.cn/blog_migrate/cb0de527e6e13aa3e1fcf6e14b8bf1d8.gif)
开源分布式中间件DBLE
社区官网: https:// opensource.actionsky.com /
GitHub主页: https:// github.com/actiontech/d ble
技术交流群:669663113
开源数据传输中间件DTLE
社区官网: https:// opensource.actionsky.com /
GitHub主页: https:// github.com/actiontech/d tle
技术交流群:852990221
![5e51e56af4a5e76f604fdc0a9a320058.png](https://i-blog.csdnimg.cn/blog_migrate/7451ad472a947c1d6b8db071ab13f9bd.jpeg)