现象描述

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#6314WL#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

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



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



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

MySQL案例-并行复制乱序提交引起的同步异常的更多相关文章

  1. MySQL的并行复制多线程复制MTS(Multi-Threaded Slaves)

    MySQL的并行复制多线程复制MTS(Multi-Threaded Slaves) http://www.tuicool.com/articles/m2Unmeq 姜承饶 简称MTS:基于binlog ...

  2. mysql 原理 ~ 并行复制

    一 概念1 MTS(Prepared transactions slave parallel applier)   主库在同一时间进入prepare状态的事务可以被从库并行回放2 传统与改进   ma ...

  3. mysql并行复制降低主从同步延时的思路与启示

    一.缘起 mysql主从复制,读写分离是互联网用的非常多的mysql架构,主从复制最令人诟病的地方就是,在数据量较大并发量较大的场景下,主从延时会比较严重. 为什么mysql主从延时这么大? 回答:从 ...

  4. MySQL 5.7 基于GTID主从复制+并行复制+半同步复制

    环境准备 IP HOSTNAME SERVICE SYSTEM 192.168.131.129 mysql-master1 mysql CentOS7.6 192.168.131.130 mysql- ...

  5. 谈谈MySQL的WriteSet并行复制

    [历史背景] 岁月更迭中我已经从事MySQL-DBA这个工作三个年头,见证MySQL从“基本可用”,“边缘系统可以用MySQL”,“哦操!你怎么不用MySQL”; 正所谓!“一个数据库的境遇既取决于历 ...

  6. 【58沈剑架构系列】mysql并行复制优化思路

    一.缘起 mysql主从复制,读写分离是互联网用的非常多的mysql架构,主从复制最令人诟病的地方就是,在数据量较大并发量较大的场景下,主从延时会比较严重. 为什么mysql主从延时这么大? 回答:从 ...

  7. mysql 案例 ~ 主从复制延迟之并行复制

    一 概念说明   1 模型 并行复制是典型的生产者.消费者模式,Coordinator作为生产者,worker线程作为消费者.   2 Waiting for preceding transactio ...

  8. 详解mysql复制机制--异步复制,半同步复制和并行复制

    图4 那么如何并行化,并行IO线程,还是并行SQL线程?其实两方面都可以并行,但是并行SQL线程的收益更大,因为SQL线程做的事情更多(解析,执行).并行IO线程,可以将从Master拉取和写Rela ...

  9. Mysql主从复制、半同步复制、并行复制

    MySQL之间数据复制的基础是二进制日志文件(binary log file).一台MySQL数据库一旦启用二进制日志后,其作为master,它的数据库中所有操作都会以"事件"的方 ...

  10. Centos7.5部署MySQL5.7基于GTID主从复制+并行复制+半同步复制+读写分离(ProxySQL) 环境- 运维笔记 (完整版)

    之前已经详细介绍了Mysql基于GTID主从复制的概念,原理和配置,下面整体记录下MySQL5.7基于GTID主从复制+并行复制+增强半同步复制+读写分离环境的实现过程,以便加深对mysql新特性GT ...

随机推荐

  1. [转帖]一文读懂 K8s 持久化存储流程

    https://zhuanlan.zhihu.com/p/128552232 作者 | 孙志恒(惠志) 阿里巴巴开发工程师 导读:众所周知,K8s 的持久化存储(Persistent Storage) ...

  2. [转帖]Ipmitool跟OS下的ipmi模块之间的关系

    https://www.jianshu.com/p/71614d3288e8 OS下默认加载了ipmi的相关模块 注:此时OS下可以正常使用ipmitool命令访问本机的ipmi 设备. [root@ ...

  3. [转帖]/etc/passwd文件 各个字段详解

    转载自:https://www.sohu.com/a/320177323_505901 /etc/passwd文件: 系统用户配置文件,存储了系统中所有用户的基本信息,并且所有用户都可以对此文件执行读 ...

  4. 简单定位占用最高CPU的java进程信息

    公司里面一个应用不小心点击就会导致系统性能下降很明显. 性能组的同事定位到了, 我这里以学习的态度重现一下这个过程. 1. 问题再现 产品一个非常大数据量的帮助, 点击之后就会占用非常多的cpu 因为 ...

  5. Mark 一下 Redisson 可能需要升级版本

    貌似有bug 我们高并发的情况下貌似遇到了 https://github.com/redisson/redisson/issues/2299

  6. expres实现登录与修改密码

    登录模块 如果登录的时候,昵称在数据库中查询的是不唯一值.需要提示用户登录失败. 即使用户密码输入正确. 然后将该消息通知相关人员,立即进行排查问题. var express = require('e ...

  7. Git如何拉取指定远程分支

    转载来自https://www.jianshu.com/p/856ce249ed78 目的 我们想要获取到代码仓库中分支"a" 中的文件到本地,我了解到有三种方法.   代码仓库 ...

  8. 多模态对比语言图像预训练CLIP:打破语言与视觉的界限

    多模态对比语言图像预训练CLIP:打破语言与视觉的界限 一种基于多模态(图像.文本)对比训练的神经网络.它可以在给定图像的情况下,使用自然语言来预测最相关的文本片段,而无需为特定任务进行优化.CLIP ...

  9. 【6】python生成数据曲线平滑处理——(Savitzky-Golay 滤波器、convolve滑动平均滤波)方法介绍,推荐玩强化学习的小伙伴收藏

    相关文章: Python xlwt数据保存到 Excel中以及xlrd读取excel文件画图  先上效果图: 由于高频某些点的波动导致高频曲线非常难看,为了降低噪声干扰,需要对曲线做平滑处理,让曲线过 ...

  10. PaddleHub--飞桨预训练模型应用工具{风格迁移模型、词法分析情感分析、Fine-tune API微调}【一】

    相关文章: 基础知识介绍: [一]ERNIE:飞桨开源开发套件,入门学习,看看行业顶尖持续学习语义理解框架,如何取得世界多个实战的SOTA效果?_汀.的博客-CSDN博客_ernie模型 百度飞桨:E ...