MyDumper原理简介

1. 简介

相对于 MySQL 官方提供的逻辑备份工具 mysqldump,mydumper 最突出的特性就是可采用多线程并行备份,极大提高了数据导出的速度。本文基于 mydumper在 github 上托管的最新源码,对其实现原理进行较详细的介绍。

2. 备份机制

与其他备份工具一样,mydumper 默认情况下是用 FTWRL (Flush Tables With Read Lock) 全局读锁来保证备份数据的一致性。FTWRL 锁对 MySQL 的杀伤力很大,特别是在读写负载比较高的场景,因而mydumper在加锁时会优先使用影响更小的备份锁,依次执行 LOCK TABLES FOR BACKUPLOCK TABLES FOR BINLOG,如果导出实例支持的话。

在进行数据备份时,mydumper 的主逻辑由一个主线程和多个备份子线程共同完成,默认情况下为四个子线程。其主线程的主要流程为:

  1. 连接数据库
  2. FLUSH TABLES WITH READ LOCK 将脏页刷新到磁盘并获得只读锁
  3. START TRANSACTION /!40108 WITH CONSISTENT SNAPSHOT /开启事务并获取一致性快照
  4. SHOW MASTER STATUS 获得binlog位点信息
  5. 创建子线程并连接数据库
  6. 为子线程分配任务并 push 到队列queue
  7. 在子线程处理完所有非 InnoDB 表之后,UNLOCK TABLES / FTWRL / 释放锁
  8. thread.join() 等待子线程结束

备份子线程的主要流程是:

  1. 连接数据库
  2. 将 session 的隔离级别设置为 Repeatable Read
  3. START TRANSACTION /!40108 WITH CONSISTENT SNAPSHOT /开启事务并获取一致性快照
  4. 从队列中 pop 任务并执行
  5. 在所有非 InnoDB 表执行完之后,将事件通知给主线程

值得注意的是,虽然 mydumper 支持表级别的并行操作,且在导出的时候会对大的表数据进行分块 chunk 导出,但是同一个表的 chunks 是在同一个线程中处理的,并非多线程并行的。

4. 备份的详细流程

mydumper执行备份的详细流程如下

mydumper flow

流程图中的步骤基本与源码中的函数名称对应,可以将源码与流程图对照来看。

5. 一致性与锁

如流程图中所示,主线程会在开始时获取 FTWRL 全局只读锁,来保证确保接下来没有变更产生。

之后开启一致性读事务,创建子线程并确认子线程 session 隔离级别为 Repeatable Read、开启一致性读事务。这样保证了即使主线程在所有导出任务结束之前释放锁,子线程在处理 InnoDB 表时能利用 MySQL MVCC 特性继续执行,得到事务开启时间点的一致性数据视图。

接下来主线程会在自己的 session 里面读取数据库表结构、拆分任务,主线程UNLOCK TABLES释放锁由非 InnoDB 表都处理完的事件来触发,确保所有的非事务表的数据一致性。

mydumper通过结合以上逻辑可以保证即使在多线程处理的情形下,备份数据仍是一致的。

--trx-consistency-only 选项

这个选项与 mysqldump 的--single-transaction功能类似,将备份流程当作一个大事务来处理,可以看到流程中在主线程等待子线程创建完之后,主线程就会提前UNLOCK TABLES释放锁了。

显然,这个时候无法保证非InnoDB表的数据一致性,这是因为MyISAM等非事务并不支持MVCC特性,无法实现一致性快照读。

--less-locking 模式

mydumper有一个比较有意思的--less-locking选项,主要目的就是尽量减少 mydumper 中FTWRL整体的锁定时间。

这种模式的实现比较巧妙,在这种模式下,线程数量是用户指定线程数n的两倍,默认情况下也即是八个线程,新增的线程为专门处理非 InnoDB 表的一组线程less_locking_threads。主要的流程为:

  1. 主线程 FLUSH TABLES WITH READ LOCK 获取全局只读锁
  2. 主线程 START TRANSACTION /!40108 WITH CONSISTENT SNAPSHOT / 开启事务并获取一致性快照
  3. 主线程 SHOW MASTER STATUS获得binlog位点信息
  4. 主线程创建两组子线程并连接数据库,其中原来的一组线程threads会条件等待less_locking_threads结束才开始工作,less_locking_threads中结束一个就通知threads中的一个线程开始工作
  5. 主线程将非InnoDB表按照表中数据量均分为与n份push到queue_less_locking,其他表的导出任务还是按照原来的流程处理push到队列queue`中
  6. less_locking_threads中每个线程会拿到一个非InnoDB表任务执行,直到执行完通知threads中的一个线程开始执行queue中的任务
  7. 当所有less_locking_threads执行完时,主线程UNLOCK TABLES / FTWRL / 释放锁
  8. 主线程 thread.join() 等待子线程结束

可以看到在--less-locking模式下,mydumper 会首先集中能力处理完所有非 InnoDB 表的任务,尽快满足主线程释放锁的条件。由于每个less_locking_threads处理的任务量相当,这基本是最快的处理方式了。

参考

一致性问题

原创声明,本文系作者授权云+社区发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

编辑于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏老安的博客

批量更新zabbix中的主机名

1843
来自专栏FreeBuf

如何使用基于整数的手动SQL注入技术

今天,我将教大家如何使用基于整型的手动SQL注入技术来对MySQL数据库进行渗透测试。提醒一下,这是一篇写给newbee的文章。话不多说,我们直奔主题!

1576
来自专栏数据和云

SQL Server for Linux 下一版本的公共预览

当微软宣布即将发布SQL Server for Linux版本的时候,有些人觉得很兴奋,有些人觉得然并卵,但是既然Gartner在2016年的数据库管理系统魔...

3319
来自专栏逸鹏说道

30分钟全面解析-SQL事务+隔离级别+阻塞+死锁

阅读目录 概述: 一、事务 二、锁 三、阻塞 三、隔离级别 四.死锁 以前总是追求新东西,发现基础才是最重要的,今年主要的目标是精通SQL查询和SQL性能...

2875
来自专栏cloudskyme

提高数据库查询速度的几个思路

1、缓存,在持久层或持久层之上做缓存。 2、数据库表的大字段剥离,保证单条记录的数据量很小。 3、恰当地使用索引。 4、必要时建立多级索引。 5、分析O...

3968
来自专栏MYSQL轻松学

你真的熟悉MySQL权限吗?

(以下操作都是以root身份登陆进行grant授权,以root@localhost身份登陆执行各种命令。) MySQL包含哪些权限,共29个。 权限说明举例us...

4273
来自专栏运维技术迷

从Mysql备份中恢复单个表

因为云平台的备份是把库中所有的表都打包成一个 .sql文件,然而这一个.sql文件大约有20G,现阶段的方法是把.sql文件source到数据库数据处理机器上,...

40411
来自专栏运维前线

CentOS7 安装并使用SQL Server

CentOS7 安装并使用SQL Server Linux 上的 SQL Server 安装指南 参考:https://docs.microsoft.com/z...

4746
来自专栏云计算

如何在Debian 9上设置MariaDB

MariaDB是MySQL的直接替代品。它致力于成为寻求强大,可扩展且可靠的SQL Server的数据库专业人员的合理选择。本指南将帮助初学者在Debian 9...

1.2K3
来自专栏Albert陈凯

2018-11-23 当我们输入一条 SQL 查询语句时,发生了什么?

我们经常说,看一个事儿千万不要直接陷入细节里,你应该先鸟瞰其全貌,这样能够帮助你从高维度理解问题。同样,对于 MySQL 的学习也是这样。平时我们使用数据库,看...

1655

扫码关注云+社区

领取腾讯云代金券