华为云带你探秘 Xtrabackup 备份原理和常见问题分析
本文来自华为云 MySQL 研发团队,主要分享了 MySQL 备份工具 Xtrabackup 的备份过程、华为云数据库团队对其做的优化改进,以及在使用中可能遇到的问题与解决方法。文章讨论的内容主要是针对华为云 RDS for MySQL, 以及用户自建的社区版 MySQL 数据库,希望有助于大家理解和使用 Xtrabackup,以后面对 Xtrabackup 问题也更加从容。
一、Xtrabackup 简介
Xtrabackup 是 Percona 团队开发的用于 MySQL 数据库物理热备份的开源备份工具,具有备份速度快、支持备份数据压缩、自动校验备份数据、支持流式输出、备份过程中几乎不影响业务等特点,是目前各个云厂商普遍使用的 MySQL 备份工具。
当前 Xtrabackup 存在两个版本:Xtrabackup 2.4.x 与 8.0.x,分别用于备份 MySQL 5.x 与 MySQL 8.0.x 版本。下面我们分别介绍 Xtrabackup 如何备份 MySQL 社区版以及华为云上的 Xtrabackup 的备份原理。
二、社区版 MySQL 的 Xtrabackup 备份
Xtrabackup 是为 Percona MySQL 设计的,同时也支持对官方社区版本 MySQL 进行备份,过程如下图所示:
兼容性检查:Xtrabackup 社区版本只支持 MyISAM , InnoDB , CSV , MRG_MYISAM 四种存储引擎的表,其他存储引擎的表不会备份;在这一步中,通过查询 tables,若发现存在表的存储引擎不是上述四种引擎之一,会打印 warning, 表明 Xtrabackup 不会备份该表。
启动 redo 后台备份线程:启动 redo 后台备份线程,从备份实例的最近一次 checkpoint LSN 的位置开始备份所有增量的 redo log,一直持续到备份任务结束。
加载所有的 innodb 表空间:打开并扫描所有 innodb 表的数据文件,检查所有表空间的第一个页面,初始化所有表的内存结构。
备份 innodb 表:遍历步骤 3 所构建的表的内存结构,备份每一个 innodb 表的数据文件,备份的过程中会检查每个页面的数据是否正确。
加备份锁 FLUSH TABLES WITH READ LOCK (FTWRL):FTWRL 锁是 MySQL 实例级的读锁,加锁过程复杂,且加锁之后,所有表的所有更新操作以及 DDL 都会堵塞。
备份非 innodb 表:因为在步骤 5 我们已经对实例加了读锁,因此,此时备份非 innodb 表是安全的,此时一定没有写业务。
记录 binlog 当前的 GTID 信息:请注意,此时我们仍持有全局读锁。这一步主要是方便我们使用该备份集快速地创建出备机。
停止 redo 备份线程。
释放锁资源,备份结束。
需要注意的是,Xtrabackup 2.4.x 与 8.0.x 在第 7、8 这两个步骤存在差异,这个差异有 MySQL 8.0.x 的原因,详情我们在下文介绍。
三、华为云 RDS for MySQL 备份
在备份社区版 MySQL 实例时,Xtrabackup 会对实例加全局读锁(FTWRL),该锁对数据库的业务影响很大,严重时甚至会导致数据库“挂起”,这对客户来说是不可接受的。因此华为云 MySQL 团队对这个过程进行了优化,主要有两点:
对 MySQL 5.x 以及 0.x 增加了备份锁:LOCK TABLES FOR BACKUP
对 MySQL 5.x 新增了 binlog 锁:LOCK BINLOG FOR BACKUP
优化之后,华为云 Xtrabackup 对 MySQL 的备份过程如下:
与 FTWRL 锁相比,备份锁 LOCK TABLES FOR BACKUP 对客户实例影响很小,其加锁过程简单,加锁期间 innodb 表的 DML 操作不受影响,但是非 innodb 表的所有的更新操作以及 DDL 操作仍然是不允许的。
备份完所有的表文件后,Xtrabackup 需要获取 binlog GTID 信息。
对于 MySQL 5.x 版本,Xtrabackup 2.4.x 会执行 LOCK BINLOG FOR BACKUP 操作,对 binlog 加锁,然后获取 GTID 信息。
对于 MySQL 8.0.x 版本,华为云 Xtrabackup 8.0.x 沿用官方的一致性备份点查询方法。Xtrabackup 查询 log_status 时,MySQL 服务器会分别对 redo log, binlog 等加轻量级锁,获取一致性备份点,这个过程是非常短暂的,对实例的运行几乎没有影响。MySQL 8.0.x 的备份一致性点,会告诉我们一致性的 redo log LSN 以及 binlog 的 GTID;查询完备份一致点后,Xtrabackup 会备份最后一个 binlog 文件,用于恢复时仲裁事务是否需要回滚;最后,redo log 备份线程任务会在其读取到的 redo log 的 LSN 大于查询到的备份一致性点的 redo log LSN 处停止。
由于 Xtrabackup 2.4.x 与 8.0.x 在处理 binlog 时存在差异,恢复过程也存在差异,我们会在后续文章中详细阐述。
四、常见问题与解决方法
华为云已经使用 Xtrabackup 为公司几乎所有的 MySQL 实例提供备份服务,在使用过程中,我们积极与社区保持联系,向 Percona 社区报告使用过程中的一些问题,帮助 Xtrabackup 向更好的方向演进。此外,对于发现的一些致命问题,若社区未能及时修复,华为云数据库团队会进行及时修复以保证备份数据的正确性。
下面是我们总结在使用 Xtrabackup 备份过程各个阶段可能遇到的问题,分析其原因以及对应的解决方法,
1. 兼容性检查阶段
问题现象:Xtrabackup 启动后,立即长时间“挂起”,查看日志发现 redo log 备份线程也没有启动。
原因:Xtrabackup 兼容性检查时无法获取 MDL 锁。Xtrabackup 兼容性检查是通过查询 imformation_schema.tables 这个插件表实现:
“SELECT CONCAT(table_schema, '/', table_name), engine FROM information_schema.tables WHERE engine NOT IN ('MyISAM', 'InnoDB', 'CSV', 'MRG_MYISAM') AND table_schema NOT IN ('performance_schema', 'information_schema', 'mysql')”
在查询每张表时,需要获取对应表的 MDL 锁,如果此时 MySQL 实例中存在长时间的 DML 或者 DDL 语句,或者更严重者出现了 MDL 死锁,上面的查询会一直堵塞在等待 MDL 锁阶段,此时 Xtrabackup 会长时间“挂起”。
解决办法:若等待锁的原因只是因为其他 SQL 语句的堵塞,等待其他 SQL 执行完成即可;若是发生了死锁,此时需要分析出死锁原因,将死锁解除;华为云 RDS for MySQL 提供了 MDL 锁视图功能,可以很好地帮助用户分析业务的 MDL 死锁。
2.redo log 备份阶段
问题现象 1:redo log 回卷,备份失败,Xtrabackup 报如下错误信息:
“xtrabackup: error:it looks like InnoDB log has wrapped around before xtrabackup could process all records due to either log copying being too slow, or log files being too small.\n");”
原因:在备份的过程中,如果主机业务负载很高,导致 redo log 写入的速度很快,会发生 Xtrabackup 的 redo log 备份线程的备份速度小于 redo log 的写入速度,因为 MySQL redo log 文件写入使用了 round-robin 的方式,使得新写入的日志覆盖了之前写入却还未备份的日志,因此备份失败。
解决办法:推荐在业务低峰期进行备份,或者增大 redo log 的文件大小。
问题现象 2:备份因 DDL 操作失败,错误信息如下:
“An optimized (without redo logging) DDLoperation has been performed. All modified pages may not have been flushed to the disk yet.
PXB will not be able take a consistent backup. Retry the backup operation”
原因: 备份过程中 MySQL 实例发生了创建索引的 DDL 操作,因为创建索引不会写 redo,若继续备份会引起数据不一致问题,所以 Xtrabackup 在这种场景中备份失败是预期行为。
解决办法:不要在备份过程中创建索引,如果确实需要,建议在建表语句中直接带上索引,或者使用 lock-ddl 参数进行备份(阻塞实例上新的 DDL 操作)。
问题现象 3:undo truncate 导致备份失败,Xtrabackup 错误信息如下:
“An undo ddl truncation (could be automatic) operation has been performed.”
原因:在 Xtrabackup 备份期间,如果 MySQL 实例发生 undo truncate 时,有可能会出现写入新 undo 文件(space id 不同)的 undo 日志丢失导致恢复出来的数据存在问题。官方在 Xtrabackup 8.0.14 版本(基于 MySQL 8.0.21)对该问题进行了修复,修复方法是 redo 备份线程,解析 redo log 时若发现该操作是 undo log 的 truncate 操作,则会备份失败。遗憾的是,该修复并没有完全解决问题,在以下两种场景中,社区版本的 Xtrabackup 仍可能会发生恢复出来的数据存在不一致的现象:
MySQL 版本低于 MySQL 8.0.21;
用户在备份过程中,自己创建了新的 undo tablespace。
解决办法:在备份期间关闭 undo tablespace 的 truncate 操作,并禁止用户创建 undo tablespace, 能够有效地防止备份数据恢复出来不一致的问题;另外华为云 Xtrabackup 对这个问题进行了进一步的修复,可以有效地防止此类现象发生。
3.加载表空间阶段
问题现象 1:Xtrabackup 报错:Too many open files
原因:操作系统允许同时打开的文件数量是有限的,Xtrabackup 在 load tablespace 阶段会同时打开所有的表文件,如果 Xtrabackup 打开的表的个数超过了该限制,则会备份失败。
解决办法:调大操作系统,允许同时打开最大文件数的配置,或者使用 lock-ddl 参数(阻塞实例上新的 DDL 操作)。
问题现象 2:rename table 导致备份失败,错误信息如下:
“Trying to add tablespace 'xxxx' with id xxx to the tablespace memory cache, but tablespace xxxx already exists in the cache!;”
原因:在 Xtrabackup 打开表空间的全过程是没有加锁的,如果发生了 rename table 有概率会发生重复加载相同的表空间,此时 Xtrabackup 会检测到重复的 tablespace id,因此备份失败。
解决办法:一般来说,加载表空间是一个很快的操作,rename table 并不是一个很频繁的操作,这种情况重试即可(Percona Xtrabackup 2.4.x 仅支持单线程加载表空间,华为云 Xtrabackup 支持多线程加载表空间)。
4.备份 innodb 表阶段
问题现象:innodb 表数据文件损坏,备份失败,错误信息如下:
“xtrabackup: Database page corruption detected at page xxxx, retrying.”
原因:Xtrabackup 在备份 innodb 表数据文件时,会检查每个页面的 checksum,如果发现 checksum 不对,则备份失败,这时说明 MySQL 实例的数据已经发生了损坏(例如磁盘静默错误)。
解决办法:需要通过恢复前一次的备份数据或者其他的办法将数据进行修复之后,备份才能成功,在后续的文章中,我们也会详细介绍数据修复办法。
五、结语
本文主要对比介绍了 Xtrabackup 备份原理,备份社区版 MySQL 以及华为云对其的改进,并分享了 Xtrabackup 常见问题的排查与解决,后续我们也会为大家带来更深入的分析,更实用的使用技巧,希望对大家理解和使用 Xtrabackup 有帮助。我们也将持续为客户提供更好的数据库服务,并时刻守护客户的数据安全。
最后,告诉大家一个好消息,云数据库 MySQL 包年 19.9 元起,助力企业无忧上云,欢迎大家前来体验>>https://activity.huaweicloud.com/dbs_Promotion/index.html
版权声明: 本文为 InfoQ 作者【华为云数据库小助手】的原创文章。
原文链接:【http://xie.infoq.cn/article/8649f9f49cf19ced4c4f79f40】。文章转载请联系作者。
评论