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 条评论
登录 后参与评论

相关文章

来自专栏Golang语言社区

Go语言读写数据库

我用的驱动是:https://github.com/Go-SQL-Driver/MySQL 理由跟 https://github.com/astaxie/bui...

3236
来自专栏后端技术探索

mysql问题排查实例

最近遇到应用频繁的响应缓慢,无法正常访问。帮忙一起定位原因,最后定位到的问题说起来真的是很小的细节问题,但是就是这些小细节导致了服务不稳定,真是细节决定成败。这...

592
来自专栏待你如初见

Day16

1203
来自专栏Jackson0714

【SQL进阶】03.执行计划之旅1 - 初探

3317
来自专栏电光石火

数据库中的左连接(left join)和右连接(right join)区别

Left Join / Right Join /inner join相关

1846
来自专栏逸鹏说道

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

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

2715
来自专栏https://www.cnblogs.com/L

mysql中多个left join子查询写法以及别名用法

            od.reportSendOrderLogisticId,

763
来自专栏用户画像

sql sever 索引

微软的SQL SERVER提供了两种索引:聚集索引(clustered index,也称聚类索引、簇集索引)和非聚集索引(nonclustered index,...

584
来自专栏JavaQ

MySQL架构学习笔记

MySQL逻辑架构 了解MySQL的架构有助于深入理解MySQL服务器,下图是MySQL的三层逻辑架构图(图片来自于网络)。 ? 第一层用于对客户端的连接处理...

3319
来自专栏AILearning

Apache Spark 2.2.0 中文文档 - Spark SQL, DataFrames and Datasets Guide | ApacheCN

Spark SQL, DataFrames and Datasets Guide Overview SQL Datasets and DataFram...

1K8

扫码关注云+社区