现象描述

Slave在开启并行复制后, 默认会乱序提交事务, 可能会引起同步中断;

Slave端表现为同步的SQL线程抛出异常, 为主键重复, 修改的数据行不存在等;

GTID信息类似于: 9a2a50aa-5504-11e7-9e59-246e965d93f4:1-1371939844:1371939846

其中1371939845为报错的事务, 直观上看, Slave端先提交了1371939846事务;

解决办法

MySQLversion>=5.7.5

slave_preserve_commit_order:OFF(default)->ON

注:binlog_order_commits=ON(default)

问题分析

参考官方的WL#6314和WL#7165, 这里对原文内容进行简单的归纳, 有兴趣的可以看看原文的High Level Architecture;

WL#6314 : https://dev.mysql.com/worklog/task/?id=6314

WL#7165 : https://dev.mysql.com/worklog/task/?id=7165

注: 英文原文中的commit-parent transaction, sequence number指的就是binlog中的last_commited和sequence_number; 即简单翻译中的”逻辑时间戳标记”

WL#6314 关于slave端的并行applier

当事务进入prepare阶段(组提交流程的某一个阶段)时, 这些事务都会获得一个逻辑时间戳的标记, 用来标记最新提交的事务是哪个;

在master端, 有关流程如下:

在prepare阶段, 从commit_clock中获取时间戳并存储下来, 用来标记最新提交的事务;

在commit阶段(事务已经写入binlog, 但是在引擎层提交前), 对commit_clock执行步进操作;

在Slave端, 有关流程如下:

coordinate线程会读取relaylog的event, 如果这些event都有相同的逻辑时间戳(last_commited), 那么这些event就可以由worker并行执行;

WL#7165 有关并行复制的并行度优化

参照WL#6314的描述, 虽然已经实现了并行复制, 但是并没有达到预期的程度;

举例: 下图代表各个事务的执行顺序与时间线, 其中P代表单个事务的prepare阶段, 在这个阶段会获取到commit_clock的时间戳, C代表这个事务的写binlog的阶段, 在这里会对commit_clock进行步进操作;

如上图所示, Trx1, Trx2, Trx3的P阶段获取到的都是同一个last_commited值(比如说是1), 因此这三个事务可以在Slave端并行执行; 同理, Trx4不能和< Trx1, Trx2, Trx3 > 一起并行回放, 因为Trx4的P阶段, 获取到的last_commited值是Trx1执行完步进以后的值(步进之后变成了2);

按照WL#6314的逻辑, Slave端可以发现这七个事务分成了四个事务组, 分别是< Trx1, Trx2, Trx3 >, < Trx4 >, < Trx5, Trx6 >, < Trx7 >;

但是需要注意的是, 对于不同的事务组, < Trx4 > 和 < Trx5, Trx6 > 是能并发执行的, 因为从时间线上看, < Trx4 > 和 < Trx5, Trx6 > 的prepare阶段在时间线上是有重叠的, 这也就意味着这两组事务并不存在锁的冲突, 那么就可以在Slave并行执行;

对于并行度的优化

改进后的并行复制使用锁来判断是否可以进行并发;

基本逻辑如下:

L代表锁阶段开始, C代表锁阶段结束;

A中的Trx1和Trx2由于锁阶段存在重合, 也没有发生冲突, 说明Trx1和Trx2是可以并行执行的, 但是B不行, 因为Trx1和Trx2的锁阶段没有重合, 所以无法确认是不是可以并行执行(不做额外的判断, 直接当做不可并行处理, 节约性能开销);

关于锁阶段的判断, WL中明确表示没有进行锁分析, 而是直接把事务提交的一些阶段作为加锁与释放锁的时间点(从事务提交的阶段来看, 也没什么问题);

假设在进行存储引擎层的提交之前, 所有的锁都已已经释放(锁阶段结束的时间点);

假设在prepare阶段开始的时候, 所有需要的锁已经全部获取到(锁阶段开始的时间点);

在MySQL的binlog中, L所指的标记就是last_commited, C所指的标记就是sequence_number;

关于last_commited和sequence_number, WL#7165有做如下描述

在事务进入flush阶段前, 会步进transaction.sequence_number的值 –> 显示为sequence_number

在事务进入引擎层提交之前, 会修改 global.max_committed_transaction的值

= max(global.max_committed_timestamp, transaction.sequence_number)

= transaction.sequence_number (如果binlog_order_commits使用默认值ON)

因此, Slave端在决定SQL是否可以并发执行时, 参考如下原则:

-----------------------------------------------------------------------------------------------------------

Slave can execute a transactionifthe smallest sequence_number

among all executing transactions is greater than transaction.last_committed.

-----------------------------------------------------------------------------------------------------------

伪代码会更直观一些:

-----------------------------------------------------------------------------------------------------------

Slave logic:

-before scheduler pushes the transaction for execution : wait until         transaction_sequence[0].sequence_number>transaction.last_committed

-----------------------------------------------------------------------------------------------------------

所以使用基于锁的并行度优化后, 确实可以让WL#6314的< Trx4 > 和 < Trx5, Trx6 > 并发执行;

故障场景还原

Slave上报错的事务为1371939845, binlog内容如下, 事务缺少1371939845;

Master上的事务序列如下:

参考WL#6314的格式, 根据Master的事务序列绘制事务序列图, GTID, last_commited, sequence_number均使用最后两位数作为标记;

由于Slave是乱序提交的, 所以这些事务在Slave的binlog中并非严格按照GTID递增的顺序出现

根据WL#7165的描述, 可以得出: 在Slave上, 当Trx41执行完毕之后, Slave认为, Trx46与Trx47已经可以由coordinate进行调度, 与< Trx42, Trx43, Trx44, Trx45 > 并行执行了, 但是Trx45与Trx46, Trx47 存在业务上的先后顺序(且确实存在锁冲突), 所以先执行的Trx46删除了Trx45需要的数据, 导致同步中断;

PS: 既然Trx45和Trx46有锁冲突, 为什么Trx46会拿到84作为last_commited, 而不是88?

参考WL#7165的伪代码,

-----------------------------------------------------------------------------------------------------------

When@@global.binlog_order_commitsistrue,inprinciple we could reduce the max

to an assignment:

global.max_committed_transaction=transaction.sequence_number

-----------------------------------------------------------------------------------------------------------

MySQL-5.7.21的源代码:

MYSQL_BIN_LOG::ordered_commit-->

process_commit_stage_queue-->

update_max_committed

-----------------------------------------------------------------------------------------------------------因此推测主库当时候是如下场景:作为一个事务组,进入到了存储引擎的commit阶段前,会递增sequence_number,而不是一次到位的全部加上;

所以Trx46进入prepare阶段时,刚好是Trx41完成了commit阶段,所以拿到的是84,而不是88;虽然官方描述中,认为会达到最终一致的状态,但是同步过程中会存在短暂的不一致现象,这种现象被描述为"GAP";

list存入mysql乱序_MySQL案例-并行复制乱序提交引起的同步异常相关推荐

  1. mysql复制多行_mysql中的复制方式总结(半同步复制,并行复制,多源复制)

    一.MySQL主从复制(异步复制,默认) Mysql主从复制原理 Mysql的复制原理大致如下: 1.主库记录binlog日志 在每次准备提交事务完成数据更新前,主库将数据更新的事件记录到二进制日志b ...

  2. MySQL 5.6, 5.7并行复制测试(二)(r12笔记第10天)

    昨天花了点时间整理了下并行复制在5.6,5.7中的一些差别和测试,当然只是一个开始,因为里面还有不少需要完善的部分,总体的感觉来看MySQL 5.7里的并行复制改进很大,能够极大提高效率,充分利用资源 ...

  3. mysql多线程复制crash_MySQL 并行复制(MTS) 从库发生异常crash分析

    背景 半同步复制从库在晚上凌晨2点半发生异常crash,另一个异步复制从库在第二天凌晨3点也发生了异常crash. 版本 mysql 5.7.16 redhat 6.8 mysql> show ...

  4. mysql mts_MySQL进一步完善可用并行复制-MTS并行增量的应用-爱可生

    原标题: MySQL进一步完善可用并行复制-MTS并行增量的应用-爱可生 MTS 并行增量应用 MySQL 的复制延迟在早期版本一直存在,MySQL 5.6.3 版本后开始支持并行复制,并在 5.7 ...

  5. mysql 降序_MySQL 8 新特性之降序索引底层实现

    什么是降序索引 大家可能对索引比较熟悉,而对降序索引比较陌生,事实上降序索引是索引的子集. 我们通常使用下面的语句来创建一个索引: create index idx_t1_bcd on t1(b,c, ...

  6. mysql virt虚拟内存_mysql 案例 ~ mysql内存性能分析

    一 简介: mysql基于linux的内存分析 二 关键指标定义 1 底层分配和释放内存 1 使用C标准库的malloc()或者mmap(),就可以在堆和文件映射段分配内存了,通过free()或者um ...

  7. mysql 三主_MySQL主主复制3

    一.创建并授权用户 在每一台(主)服务器上创建一个用户,并为之授权,使它们可以互相访问彼此的数据库 在Server-1上: 创建一个充许Server-2来访问的用户server2,密码为:server ...

  8. mysql 备份表_MySQL中表的复制以及大型数据表的备份教程

    表复制mysql拷贝表操作我们会常常用到,下面就为您详细介绍几种mysql拷贝表的方式,希望对您学习mysql拷贝表方面能够有所帮助. 假如我们有以下这样一个表: id username passwo ...

  9. mysql 重装之后_mysql重装之后 复制data

    (哇,编程小白的第一篇博客丫,激动) Q one:mysql需要重装,数据该怎么办. 方法一:数据表最好是导出成.sql文件,这样才比较安全. 方法二:直接copy了data文件:在mysql安装盘下 ...

最新文章

  1. OpenCV 【七】————边缘提取算子(图像边缘提取)——canny算法的原理及实现
  2. Angular - - ngHref、ngSrc、ngCopy/ngCut/ngPaste
  3. 关于开始申请2010年4月份微软MVP的通知!
  4. WPF and Silverlight 学习笔记(九):WPF布局管理之Canvas、InkCanvas
  5. Azure 内容审查器之文本审查
  6. 提供写入的数据少于指定的数据_指定范围数据的汇总
  7. React Native实例
  8. Docker容器的重启策略
  9. leetcode - 62. 不同路径
  10. 计算1970距今的秒数
  11. RadGrid Columns HeaderText
  12. 7月第3周社交网站综合排行Top10:新浪微博居首
  13. android 投屏技术原理,什么是无线投屏技术,无线投屏技术原理解析
  14. RS-485通信协议(ModBus版)
  15. echarts实现山东地图可放大缩小可下钻
  16. 名师李涛老师主讲 Photoshop CS2 (全教程下载)
  17. 二叉树的python实现
  18. Win11小键盘无法使用怎么办?
  19. Ubuntu16.04 桌面 launcher 丢失
  20. 使用CenterNet训练自己的数据集

热门文章

  1. 强势分享5款超级实用的办公软件,建议收藏!
  2. 高性能存储之--快速理解redis(简版)
  3. 【硅谷牛仔】优步CEO,最倒霉的成功创业者 -- 特拉维斯·卡兰尼克
  4. solidworks入门
  5. ROS kinetic安装、Kinect2驱动安装和配置
  6. python 运行部分代码_改改Python代码,运行速度还能提升6万倍
  7. java 日志_跟着Tomcat学编码:Java 原生日志框架分析
  8. 深度学习算法实践(基于Theano和TensorFlow)
  9. 史上最全DSO学习资料
  10. VS项目工程管理技巧