MySQL · 源码分析 · MySQL replication partial transaction

本文涉及的产品
云数据库 RDS MySQL Serverless,0.5-2RCU 50GB
云数据库 RDS MySQL Serverless,价值2615元额度,1个月
简介:

replication 概述

目前MySQL支持的replication方式多种多样

  1. 普通的master-slave 异步replication
  2. 半同步的semi-sync replication
  3. 支持多通道的group replication和double binlog

如果按连接协议来区分,又可以分为

  1. 非GTID模式,通过binlog文件名和文件的偏移来决定replication位点信息
  2. GTID模式,通过GTID信息来决定replication位点信息

如果按apply binglog的方式来区分,又可以分为

  1. 串行,按binlog event顺序依次执行
  2. 并行,以db, table或transaction为粒度的并行复制,以及基于group commit的LOGICAL_CLOCK并行复制

不论哪种replication, 都离不开replication最基本的组件,

  1. IO thread,负责从master拉取binlog.
  2. SQL thread,负责apply relay log binlog.

replication 异常

复制过程中,由于网络或者master主机宕机,都会造成slave IO thread异常中断。 例如以下事务在复制过程中发生上述异常,

SET GTID_NEXT; # GTID设置为ON时 
BEGIN; INSERT row1; INSERT row2; COMMIT; 

那么备库接收的binlog可能不包含完整的事务,备库可能仅接收到BEGIN,也可能只接收到INSERT row1.

然而,当IO thread恢复后,SQL线程怎么正确处理这种异常呢?

异常恢复

IO thread 异常中断后,SQL线程是正常工作的,SQL执行了部分事务, 它会等待IO 线程发送新的binlog. IO thread 线程恢复后,SQL线程可以选择继续执行事务或者回滚事务重新执行事务,这是由replication协议决定的。

  1. GTID模式下,设置auto_position=1时,slave会根据GTID信息,从事务起点开始,重新将事务完整binlog发给备库。此时,备库需要回滚之前的部分事务。
  2. GTID模式下,设置auto_position=0或非GTID模式下,slave会根据位点信息从master续传之前的binlog。此时,备库可以继续完成之前的部分事务。

继续执行事务比较简单,但是回滚之前的部分事务就比较复杂.

分为两种情况来分析:

  • 串行复制

串行复制时,完整的事务会由SQL thread来执行,当执行到GTID_LOG_EVENT时,会发这个GTID已经分配过了,这时候就可以回滚事物。具体参考

Gtid_log_event::do_apply_event()

 if (thd->owned_gtid.sidno)
 {
 /*
 Slave will execute this code if a previous Gtid_log_event was applied
 but the GTID wasn't consumed yet (the transaction was not committed
 nor rolled back).
 On a client session we cannot do consecutive SET GTID_NEXT without
 a COMMIT or a ROLLBACK in the middle.
 Applying this event without rolling back the current transaction may
 lead to problems, as a "BEGIN" event following this GTID will
 implicitly commit the "partial transaction" and will consume the
 GTID. If this "partial transaction" was left in the relay log by the
 IO thread restarting in the middle of a transaction, you could have
 the partial transaction being logged with the GTID on the slave,
 causing data corruption on replication.
 */ if (thd->transaction.all.ha_list)
 {
 /* This is not an error (XA is safe), just an information */
 rli->report(INFORMATION_LEVEL, 0,
 "Rolling back unfinished transaction (no COMMIT " "or ROLLBACK in relay log). A probable cause is partial " "transaction left on relay log because of restarting IO " "thread with auto-positioning protocol.");
 const_cast<Relay_log_info*>(rli)->cleanup_context(thd, 1);
 }
 gtid_rollback(thd);
 }

  • 并行复制

并行复制有别于串行复制,binlog event由worker线程执行。按串行复制的方式来回滚事务是行不通的,因为重新发送的事务binlog并不一定会分配原来的worker来执行。因此,回滚操作需交给coordinate线程(即sql线程)来完成。 GTID模式下,设置auto_position=1时. IO thread重连时,都会发送 ROTATE_LOG_EVENT和FORMAT_DESCRIPTION_EVENT. 并且FORMAT_DESCRIPTION_EVENT的log_pos>0. 通过非auto_position方式重连的FORMAT_DESCRIPTION_EVENT的log_pos在send之前会被置为0. SQL线程通过执行FORMAT_DESCRIPTION_EVENT且其log_pos>0来判断是否应进入回滚逻辑。而回滚是通过构造Rollback event让work来执行的。
具体参考

exec_relay_log_event()
/*
 GTID protocol will put a FORMAT_DESCRIPTION_EVENT from the master with
 log_pos != 0 after each (re)connection if auto positioning is enabled.
 This means that the SQL thread might have already started to apply the
 current group but, as the IO thread had to reconnect, it left this
 group incomplete and will start it again from the beginning.
 So, before applying this FORMAT_DESCRIPTION_EVENT, we must let the
 worker roll back the current group and gracefully finish its work,
 before starting to apply the new (complete) copy of the group.
 */ if (ev->get_type_code() == FORMAT_DESCRIPTION_EVENT &&
 ev->server_id != ::server_id && ev->log_pos != 0 &&
 rli->is_parallel_exec() && rli->curr_group_seen_gtid)
 {
 if (coord_handle_partial_binlogged_transaction(rli, ev))
 /*
 In the case of an error, coord_handle_partial_binlogged_transaction
 will not try to get the rli->data_lock again.
 */
 DBUG_RETURN(1);
 }

MySQL官方针对此问题有过多次改进,详见以下commit

666aec4a9e976bef4ddd90246c4a31dd456cbca3
3f6ed37fa218ef6a39f28adc896ac0d2f0077ddb
9e2140fc8764feeddd70c58983a8b50f52a12f18

异常case处理

当slave SQL线程处于部分事务异常时,按上节的逻辑,IO thread恢复后,复制是可以正常进行的。但如果IO thread如果长时间不能恢复,那么SQL apply线程会一直等待新的binlog, 并且会一直持有事务中的锁。当slave切换为master后,新master会接受用户连接处理事务,这样SQL apply线程持有的事务锁,可能阻塞用户线程的事务。这是我们不希望看到的。

此时可以通过stop slave来停止SQL apply线程,让事务回滚释放锁。

另一种更好的方案是让SQL apply 线程自动识别这种情况,并加以处理。比如,增加等待超时机制,超时后自动kill sql 线程或回滚SQL线程的部分事务。

相关实践学习
基于CentOS快速搭建LAMP环境
本教程介绍如何搭建LAMP环境,其中LAMP分别代表Linux、Apache、MySQL和PHP。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
8月前
|
网络协议 算法 关系型数据库
解读 MySQL Client/Server Protocol: Connection & Replication(上)
解读 MySQL Client/Server Protocol: Connection & Replication
59 0
|
3月前
|
监控 负载均衡 关系型数据库
MySQL技能完整学习列表13、MySQL高级特性——1、分区表(Partitioning)——2、复制(Replication)——3、集群(Clustering)
MySQL技能完整学习列表13、MySQL高级特性——1、分区表(Partitioning)——2、复制(Replication)——3、集群(Clustering)
53 0
|
8月前
|
SQL 存储 关系型数据库
解读 MySQL Client/Server Protocol: Connection & Replication(下)
解读 MySQL Client/Server Protocol: Connection & Replication
74 1
|
10月前
|
存储 NoSQL 关系型数据库
An Overview of PostgreSQL & MySQL Cross Replication
An Overview of PostgreSQL & MySQL Cross Replication
66 0
|
12月前
|
关系型数据库 MySQL 数据库
MySQL部分权限回收功能(Partial Revokes)的使用---发表在爱可生开源社区
MySQL数据库对于对象的操作级别分为:全局、数据库、表、字段等。粒度从粗到细。如果粗的粒度的权限满足了,将不再检验细粒度的级别,这种验证方式有的时候不方便,例如需要把100个数据库中除了某一个数据库外的访问权限赋予某个用户
|
存储 SQL 缓存
PolarDB-MySQL 新特性 - Partial Result Cache
背景查询缓存(Query Cache)是数据库执行层的一个加速查询的特性,用来缓存一条查询语句的结果集,如果后续再有相同的查询,直接从结果集缓存中读取结果,而不用再重新执行而极大提升查询性能。但Query Cache在实际业务使用中存在较多的局限性,首先能够命中Query Cache的规则非常严格,必须是完全相同的SQL语句,并且被查询的表的数据不能有任何的修改,有任意规则不符合要求都会造成cac
165 0
PolarDB-MySQL 新特性 - Partial Result Cache
|
SQL Oracle 关系型数据库
MySQL · 源码分析 · Derived table代码分析
在具体介绍MySQL的derived table之前,先介绍一下子查询的概念。在MySQL中,包含2种类型的子查询:From字句中的子查询,例如select * from (select * from t1) tt;tt是一个抽象的表概念,内部就是一个子查询,在PG的概念中叫做sublink,MySQL则叫做derived table、view其他位置的子查询,如投影列中、条件中、having中,
318 0
MySQL · 源码分析 · Derived table代码分析
|
关系型数据库 MySQL
《从理论到实践,深度解析MySQL Group Replication》电子版地址
从理论到实践,深度解析MySQL Group Replication
77 0
《从理论到实践,深度解析MySQL Group Replication》电子版地址
|
Prometheus 监控 Cloud Native
mysql exporter源码分析
通过对MySQL Exporter整体进行分析,实现一个自定义的demo收集,并进行采集的整合
487 0
|
关系型数据库 MySQL
MySQL Group Replication
MySQL Group Replication
70 0