解读 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 常用参数及含义
对性能提升帮助较大的参数:
--rows 和--chunk-filesize 可将表分成多块。在恢复时,利用多线程并发恢复数据,可以提高速度。
--trx-consistency-only 只导出已提交的事务数据。在导出大量数据的情况下,可以减少导出的数据量和时间。
--threads 并发线程数。增加线程数,可提升恢复性能。但需注意不要影响到正常业务。
myloader 常用参数
myloader 常用参数如表 2 所示:
表 2 myloader 常用参数及含义
性能对比
本章节使用 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)表级时间点恢复过程中负责数据导出导入过程。通过在导出阶段对表数据进行分块,并调整导入阶段线程数,使得恢复过程充分利用多线程优势,提升表级恢复性能,大幅改善用户体验。
评论