摘要:本文将详细介绍mydumper与myloader在GaussDB(for MySQL)中的应用,通过分析其原理,结合具体的测试结果,深入探讨线程数及分块分行策略对数据恢复性能的影响。同时,通过调整相应的策略,提升表级恢复性能。

本文分享自华为云社区《【华为云MySQL技术专栏】GaussDB(for MySQL)表级恢复中mydumper、myloader的应用与性能优化》,作者:GaussDB 数据库。

背景介绍

表级时间点恢复技术为“误删表”场景提供了一种快速且精确的恢复方案。通过将指定时间点的数据恢复到临时实例,再把用户所需的表导出至本地,后重新导入至原集群,从而实现对误删表的快速恢复,保证业务运行的连续性。图1是表级恢复的整体流程。

图1 表级时间点恢复恢复整体流程

与MySQL官方提供的单线程mysqldump工具相比,mydumper和myloader支持多线程导入导出,不仅避免了字符集转换,还大幅提升恢复速度,同时也减少了备份过程中对数据库并发访问性能的影响。

本文将详细介绍mydumper与myloader在GaussDB(for MySQL)中的应用,通过分析其原理,结合具体的测试结果,深入探讨线程数及分块分行策略对数据恢复性能的影响。同时,通过调整相应的策略,提升表级恢复性能。

原理介绍

mydumper机制

mydumper导出数据时,由一个主线程和多个子线程完成。线程的关系如图2所示。

图2 mydumper执行流程及各线程关系

  • 主线程的流程为:

1) 连接数据库;

2) FLUSH TABLES WITH READ LOCK 将脏页刷到磁盘并获得只读锁;

3) START TRANSACTION /!40108 WITH CONSISTENT SNAPSHOT / 开启事务并获取一致性快照;

4)SHOW MASTER STATUS 获得binlog信息;

5)创建子线程并连接数据库;

6)为子线程分配任务并push到队列中;

7)在子线程处理完所有非InnoDB表之后,UNLOCK TABLES;

  • 子线程主要流程:

1)连接数据库;

2)SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ,设置隔离级别为RR;

3)START TRANSACTION /!40108 WITH CONSISTENT SNAPSHOT / 开启事务并获取一致性快照;

4)从队列中pop任务并执行。每个线程执行一个任务,包括导出表、schema、触发器等;

5)导出数据时,如果当前数据文件大小超过--chunk-filesize指定的大小,则写入新的数据文件;

6)在所有非InnoDB表的任务执行完之后,通知主线程;

myloader机制

myloader的执行过程与mydumper类似,主线程负责主逻辑,默认四个子线程执行具体任务(threads参数可指定子线程个数),线程的关系如图3所示。

图3 myloader执行流程及各线程关系

主线程负责导入库表结构,创建异步导入任务及结束任务,并放到阻塞队列。等待子线程执行完所有任务并退出后,接着导入其他对象。

对象的导入顺序与mydumper的导出顺序正好相反,先导入库表结构,然后是每个库表的具体数据,最后是存储过程、函数、事件、视图、触发器等。

mydumper按照分块导出的数据文件,在导入阶段便可以充分利用myloader的多线程优势,提升导入速度。每个线程处理一个分块文件,导入完后继续处理其他分块文件。每个线程执行时间接近,避免出现单个线程工作,其他线程空闲等待的现象,提高并发度。

一致性

对于备份恢复,数据的一致性至关重要。mydumper通过一致性快照实现了备份数据的一致性。主要包括以下几步:

1. 先通过SHOW PROCESSLIST,得到长查询,并逐一Kill。如果Kill失败,则终止dump,退出程序。

2. 主线程通过 "FLUSH TABLES WITH READ LOCK" 将脏页刷到磁盘,并获取一个全局只读锁,从而保证在锁释放前,子线程通过"SHOW MASTER STATUS",获取binlog位点信息时,能够得到一致性位点,从而保证备份数据的一致性。

3. 工作线程执行"START TRANSACTION WITH CONSISTENT SNAPSHOT" 开启事务并获取一致性快照。

4. 等所有非InnoDB表的工作线程任务执行完成,主线程会"UNLOCK TABLES",释放"FLUSH TABLES WITH READ LOCK",然后继续执行job queue中的作业。

通过InnoDB的MVCC功能,可以实现快照读,因此,只有在任务创建阶段才需要加锁,就可实现快照一致性。而非InnoDB表则需要在表导出任务完成前,一致对这些表加锁。

mydumper常用参数

mydumper常用参数如表1所示:

表1 mydumper常用参数及含义

mydumper常用参数含义
-B, --database要备份的数据库,不指定则备份所有库(information_schema和performance_schema系统库除外)
-T, --tables-list需要备份的表,名字用逗号隔开,可以用正则表达式
-x, --regex使用正则表达式匹配备份/不备份的对象
-o, --outputdir备份文件输出的目录,不指定默认为当前目录
-r, --rows将表按行分块时,指定多少行数据作为一个块,指定这个选项会关闭 --chunk-filesize
-F, --chunk-filesize将表按指定大小分块,单位是MB
-k, --no-locks不使用临时共享只读锁,这会造成备份数据不一致
--less-locking最小化对InnoDB表的加锁时间
-L, --logfile使用的日志文件名(mydumper所产生的日志), 默认使用标准输出
--use-savepoints使用savepoints来减少采集metadata所造成的锁时间,需要 SUPER 权限
--trx-consistency-onlyTransactional consistency only
-h, --host连接的主机名
-u, --user备份所使用的用户
-p, --password密码
-P, --port端口
-S, --socket使用socket通信时的socket文件
-t, --threads开启的备份线程数,默认是4
-C, --compress-protocol压缩与mysql通信的数据
-v, --verbose输出信息模式, 0 = silent, 1 = errors, 2 = warnings, 3 = info, 默认为 2

对性能提升帮助较大的参数:

--rows和--chunk-filesize 可将表分成多块。在恢复时,利用多线程并发恢复数据,可以提高速度。

--trx-consistency-only 只导出已提交的事务数据。在导出大量数据的情况下,可以减少导出的数据量和时间。

--threads 并发线程数。增加线程数,可提升恢复性能。但需注意不要影响到正常业务。

myloader常用参数

myloader常用参数如表2所示:

表2 myloader常用参数及含义

myloader常用参数含义
-d, --directory备份文件的文件夹
-B, --database需要还原到哪个数据库(目标数据库)
-h, --host主机
-u, --user还原的用户
-p, --password密码
-P, --port端口
-s, --source-db需要还原哪个数据库(源数据库)
-S, --socketsocket文件
-t, --threads还原所使用的线程数,默认是4
-v, --verbose输出模式, 0 = silent, 1 = errors, 2 = warnings, 3 = info, 默认为2

性能对比

本章节使用 GaussDB(for MySQL) 8U64G规格的实例,对于不同数据模型的表,使用不同的参数,对比导入导出性能。

首先,对比窄表的导入导出性能。表的规格为4列,4000万行,数据量大小8G。图4为窄表4线程、8线程mydumper、myloader不同参数的性能对比结果。

图4:窄表4线程、8线程mydumper、myloader性能对比

分析图表数据,我们可以得出以下结论:

(1)通过增加线程数,无论是导出还是导入,性能均有提升。

(2)导出阶段:分块导出的速度与不分块/不分行相比,并没有显著差异;而分行导出的速度大约是分块导出速度的两倍。

(3)导入阶段:使用分块和分行的方法相比不分块/不分行,导入速度提升了3到5倍。在处理常见的大表误删除场景时,如果不采用分块或分行,导入过程将仅限于单线程恢复。通过分块或分行,可以将单一大表分割成多个小文件,利用多线程导入,显著加快恢复速度。

(4)对比导入阶段分块与分行两种策略,分行导入的速度大约是分块导入速度的90%。

就整个数据恢复流程而言,导出阶段耗时远低于导入阶段。例如,对于一个10GB的表,导出阶段大约需要20至30秒,而导入阶段则需要近10分钟。尽管分行导出的性能是分块导出的两倍,但分行导入的性能却只有分块导入的90%。因此,从整体恢复效率来看,分块的性能要优于分行。

接下来对比宽表的导入导出性能,表结构为17列,30万行,数据量大小9.45G。图5为宽表4线程、8线程mydumper、myloader的性能对比结果。

图5:宽表4线程、8线程mydumper、myloader性能对比

从图中可以看到,增加线程数后,导出导入速度也均有上升。

对比分块分行策略:

(1)导出阶段,分块与分行的导出速度基本持平。

(2)导入阶段,分块导入速度显著高于分行。这是因为分块策略将宽表分割成了更多的文件块,从而在导入时能够实现更高的并行度。

因此对于宽表来说,分块的恢复性能也要高于分行。

综上,选用--chunk-filesize参数将表按块分割为多个文件,并提高导入导出所用线程数,可以显著提高恢复速度。

性能优化

根据上文的性能对比结果,GaussDB(for MySQL) 表级时间点恢复在导入导出阶段,分别做了如下性能优化:

在临时实例上使用mydumper将数据导出到本地时,由于临时实例并无业务,因此可以充分利用多线程提高性能。默认使用CPU * 2个线程数,加快数据导出速度,减少原实例加锁时间,减轻对业务影响。同时导出阶段使用--chunk-filesize=100M,将表数据进行分块,从而使得无论是宽表还是窄表,都能在导入阶段充分利用多线程进行恢复。

此外,还可避免在恢复单张大表时,出现仅能有一个工作线程执行导入,其他线程空闲,导致恢复慢的问题。

通过myloader将数据导入回原实例时,会对原实例的业务存在一定程度的影响,因此要慎重选择所用线程。GaussDB(for MySQL) 默认使用4线程进行导入操作,同时也给客户提供一个选择,可以使用更多的线程来进行紧急恢复。客户选择紧急恢复时,可选使用CPU*2个线程执行导入操作,此时恢复速度明显加快,但会提高原实例的CPU利用率,且内存使用率也有轻微上涨。这种情况需由客户根据紧急程度自行选择。

经过上述优化,GaussDB(for MySQL) 4U8G实例,恢复一张10T大小的数据表时,恢复时间缩短为原来的1/4,恢复速度大幅提升。

总结

mydumper、myloader在GaussDB(for MySQL)表级时间点恢复过程中负责数据导出导入过程。通过在导出阶段对表数据进行分块,并调整导入阶段线程数,使得恢复过程充分利用多线程优势,提升表级恢复性能,大幅改善用户体验。

点击关注,第一时间了解华为云新鲜技术~

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐