[缺陷分析]半同步下多从库复制异常

本文涉及的产品
云数据库 RDS MySQL Serverless,0.5-2RCU 50GB
简介: 本文分析的缺陷是MySQL bug#89370,其主要的现象是:配置半同步(复制)到多个从库,部分从库在一段时间内无法复制数据,但所有复制状态均正常。

作者:黄炎、王悦、周海鸣

本文分析的缺陷是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的复制数据流入,但查看复制状态均正常。

缺陷的原理图解

图一:描述了半同步复制的大致流程

1

上图中按序解析了MySQL半同步插件在binlog group commit中扮演的角色:

binlog group commit分为三个阶段:

  • Flush Phase(图中序号2): 将一组事务写入binlog缓存区,向半同步插件注册事务(图中序号2.1),更新binlog文件位置信息(图中序号2.2)
  • Sync Phase(图中序号4): 对binlog做fsync操作,将一组事务一起刷入磁盘
  • Commit Phase(图中序号5): 等待半同步完成,在引擎层提交事务

半同步插件:

1.图中序号3:在binlog完成位置信息更新后,开始通过复制线程读取binlog文件,将其中的event发送给slave
2.图中序号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接收机制

2

在MySQL 5.6版本的实现里,master的复制线程同时负责发送事务和接收slave返回的ACK消息,当没有接收到上一个事务的ACK消息之前,无法发送下一个事务。如此串行化的机制成为了半同步的性能瓶颈。

图三:描述了MySQL 5.7版本中的ACK接收机制

3

在MySQL 5.7版本的实现里,将接收ACK这部分任务从master的复制线程中拆分出来,由半同步插件的ACK接收线程单独处理,使得事务发送和接收ACK得以并行,极大提高了半同步性能。

图四:描述了本文缺陷的发生原因

4

本文所要描述的缺陷就出现在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
[1]https://kristiannielsen.livejournal.com/12254.html

相关实践学习
容器服务Serverless版ACK Serverless 快速入门:在线魔方应用部署和监控
通过本实验,您将了解到容器服务Serverless版ACK Serverless 的基本产品能力,即可以实现快速部署一个在线魔方应用,并借助阿里云容器服务成熟的产品生态,实现在线应用的企业级监控,提升应用稳定性。
云原生实践公开课
课程大纲 开篇:如何学习并实践云原生技术 基础篇: 5 步上手 Kubernetes 进阶篇:生产环境下的 K8s 实践 相关的阿里云产品:容器服务 ACK 容器服务 Kubernetes 版(简称 ACK)提供高性能可伸缩的容器应用管理能力,支持企业级容器化应用的全生命周期管理。整合阿里云虚拟化、存储、网络和安全能力,打造云端最佳容器化应用运行环境。 了解产品详情: https://www.aliyun.com/product/kubernetes
相关文章
|
存储 Java
2021年了,生产环境的问题你怎么解决呢?快学习下线程Dump分析(上)
2021年了,生产环境的问题你怎么解决呢?快学习下线程Dump分析
321 0
2021年了,生产环境的问题你怎么解决呢?快学习下线程Dump分析(上)
|
14天前
|
SQL 关系型数据库 MySQL
mysql主从同步出错解决办法
mysql主从同步出错解决办法
10 0
|
5月前
|
SQL 关系型数据库 数据库
记一次程序 Bug 导致数据删除的恢复过程
使用RDS、DMS进行数据恢复实践
949 0
|
安全 关系型数据库 MySQL
为什么延迟复制适用于备库数据的紧急恢复?底层原理是什么?
为什么延迟复制适用于备库数据的紧急恢复?底层原理是什么?
|
canal 存储 SQL
Canal 初次启动时如何定位同步位点(文末附流程图)
Canal 初次启动时如何定位同步位点(文末附流程图)
Canal 初次启动时如何定位同步位点(文末附流程图)
|
存储 安全 IDE
2021年了,生产环境的问题你怎么解决呢?快学习下线程Dump分析(下)
2021年了,生产环境的问题你怎么解决呢?快学习下线程Dump分析
254 0
2021年了,生产环境的问题你怎么解决呢?快学习下线程Dump分析(下)
|
SQL NoSQL 关系型数据库
二十五:从库的关闭和恢复流程(笔记)
一、stop slave流程 用户线程: stop_slave -> terminate_slave_threads ->带入参数rpl_stop_slave_timeout设置,作为等待SQL线程退出的超时时间。
795 0
|
开发工具 git
pull错代码起冲突,恢复到pull之前,切换历史版本 ---本地代码回退
pull错代码起冲突,恢复到pull之前,切换历史版本 ---本地代码回退
316 0
|
程序员
当你无法发现问题所在时,不要简单地把代码或者数据还原
这几天有一位同事需要做与我一样的功能,而这个功能是我已经开发好了的,他只需直接把我的代码拿去修改就可以。结果,我的代码可以正常运行,他的代码在开启服务之后,控制台就不断有日志输出,开发环境进入了死机状态。
1625 0
|
SQL 数据库 虚拟化
备份链中断导致差异备份报错案例
原文:备份链中断导致差异备份报错案例   最近一台SQL Server服务器部署SQL Server Backup后,发现每晚的差异备份老是失败,报如下错误:   Msg 3035, Level 16, State 1, Line 1 无法执行数据库"xxxx" 的差异备份,因为不存在当前数据库备份。
1373 0