MySQL Backup and Recovery

Stone大约 34 分钟

MySQL Backup and Recovery

应该定期对生产数据库进行备份,以便在出现诸如系统崩溃,硬件故障或者用户误删数据时恢复数据库。

注意:

此文档对应的 MySQL 版本为 8.0.32 社区版。

Backup and Recovery Types

Physical Versus Logical Backups

物理备份:数据目录和文件的拷贝。适用于大数据量,快速备份恢复场景。官方工具为 MySQL Enterprise Backup,需要购买企业版许可;常用的免费第三方工具为 Percona XtraBackupopen in new window

逻辑备份:通过查询获取数据库结构和数据进行备份。备份速度比物理备份慢,备份输出比物理备份大。适用于小数据量场景。官方工具为 mysqldumpopen in new window

Online Versus Offline Backups

在线备份:也称为热备,在 MySQL Server 运行时进行备份。为保证备份完整性,需要进行适当的锁定。

离线备份:也称为冷备,在 MySQL Server 关闭时进行备份。一般在从库进行。

Full Versus Incremental Backups

全量备份:备份所有数据。

增量备份:备份增量数据,通过二进制日志(Binary Logopen in new window)实现。

Full Versus Point-in-Time (Incremental) Recovery

全量恢复:从全量备份中恢复所有数据到备份的时间点,还可以再从增量备份恢复到其时间点。

增量恢复:也就是基于时间点(Point-in-Time)的恢复,使用全量备份和二进制日志将数据恢复到指定的时间点。

Example Backup and Recovery Strategy

Establishing a Backup Policy

这里使用 mysqldumpopen in new window,在每周日下午 1 点负载较低时进行进行全量备份:

$> mysqldump --all-databases --source-data --single-transaction > backup_sunday_1_PM.sql

此备份操作在导出开始时获取所有表的全局读锁(使用 FLUSH TABLES WITH READ LOCK)。一旦获取了该锁,就会读取二进制日志位置并释放该锁。如果在发出 FLUSH 语句时正在运行长时间更新语句,则备份操作可能需要等待这些语句完成。

对于 InnoDB 表,选项 --single-transaction 使用一致性读保证 mysqldumpopen in new window 看到的数据不会发生变化(mysqldumpopen in new window 进程看不到其他客户端对 InnoDB 表所做的更改)。如果备份操作包括非事务性表,则一致性要求其在备份期间不能更改。

为提高备份效率,节约磁盘空间,对于大型数据库,一般在周末进行全量备份后,其余时间进行增量备份。在 MySQL 中,增量备份通过二进制日志(Binary Logopen in new window)实现,MySQL Server 将对数据的更改写入到数据目录下的二进制日志文件中,类似如下:

-rw-rw---- 1 guilhem  guilhem   1277324 Nov 10 23:59 gbichot2-bin.000001
-rw-rw---- 1 guilhem  guilhem         4 Nov 10 23:59 gbichot2-bin.000002
-rw-rw---- 1 guilhem  guilhem        79 Nov 11 11:06 gbichot2-bin.000003
-rw-rw---- 1 guilhem  guilhem       508 Nov 11 11:08 gbichot2-bin.000004
-rw-rw---- 1 guilhem  guilhem 220047446 Nov 12 16:47 gbichot2-bin.000005
-rw-rw---- 1 guilhem  guilhem    998412 Nov 14 10:08 gbichot2-bin.000006
-rw-rw---- 1 guilhem  guilhem       361 Nov 14 10:07 gbichot2-bin.index

每次重新启动时,MySQL Server 都会使用序列中的下一个数字创建一个新的二进制日志文件。在运行时,还可以使用 FLUSH LOGS 语句或 mysqladmin flush-logs 命令来关闭当前二进制日志文件并创建一个新的二进制日志文件。

修改前面的 mysqldumpopen in new window 命令,使用 --flush-logs 选项, 在全量备份时刷新 MySQL 二进制日志,并使导出文件包含新的当前二进制日志的名称:

$> mysqldump --single-transaction --flush-logs --source-data=2 \
         --all-databases > backup_sunday_1_PM.sql

执行此命令后,数据目录有新的二进制日志文件 gbichot2-bin.000007,使用 --source-data 选项将二进制日志信息写入到导出文件中:

-- Position to start replication or point-in-time recovery from
-- CHANGE MASTER TO MASTER_LOG_FILE='gbichot2-bin.000007',MASTER_LOG_POS=4;

表示:

  • 导出文件 backup_sunday_1_PM.sql 包含了在二进制日志文件 gbichot2-bin.000007 之前的所有数据。
  • 备份后所有数据更改会写入到 gbichot2-bin.000007 及之后的二进制日志文件中。

在周一下午 1 点,可以通过刷新日志创建新的二进制日志文件来进行增量备份。例如执行 mysqladmin flush-logs 命令创建 gbichot2-bin.000008。周日下午 1 点到周一下午 1 点之间的所有更改都在 gbichot2-bin.000007 中。

Using Backups for Recovery

假设在周三上午 8 点出现问题需要使用备份进行恢复,第一步是先恢复最近的全量备份,即上周日下午 1 点的全量备份:

$> mysql < backup_sunday_1_PM.sql

完成后,数据恢复到上周日下午 1 点,继续恢复增量备份,例如 gbichot2-bin.000007gbichot2-bin.000008 二进制日志文件:

$> mysqlbinlog gbichot2-bin.000007 gbichot2-bin.000008 | mysql

完成后,数据恢复到周二下午 1 点,此时需要从周二下午 1 点到周三上午 8 点之间的二进制日志文件,例如 gbichot2-bin.000009 等:

$> mysqlbinlog gbichot2-bin.000009 ... | mysql

Backup Strategy Summary

需要遵守的准则 :

  • 始终启用二进制日志(MySQL 8.0 默认启用)。
  • 定期执行全量备份。
  • 定期使用 FLUSH LOGS 语句或 mysqladmin flush-logs 命令刷新日志创建增量备份。

Using mysqldump for Backups

根据是否使用 --tab 选项,mysqldumpopen in new window 有以下两种输出类型:

不使用 --tab 选项,将 SQL 语句写入到标准输出,包括创建对象语句(CREATE)和插入数据语句(INSERT)。可以将输出保存到文件。

使用 --tab 选项,为每个导出的表生成两个输出文件。一个文件为默认以 TAB 分割的文本文件,文本文件中的一行对应表的一行,文件名为 tbl_name.txt。另一个文件存放表的 CREATE TABLE 语句,文件名为 tbl_name.sql

Dumping Data in SQL Format with mysqldump

mysqldumpopen in new window 默认将 SQL 语句写入到标准输出,可以将输出保存到文件:

$> mysqldump [arguments] > file_name

使用 --all-databases 选项导出所有数据库:

$> mysqldump --all-databases > dump.sql

使用 --databases 选项导出指定数据库:

$> mysqldump --databases db1 db2 db3 > dump.sql

使用 --all-databases 或者 --databases 选项,会将每个数据库的 CREATE DATABASEUSE 语句写到导出文件中,确保在加载导出文件时,如果不存在对应的数据库,可以使用这两个语句创建数据库并设置为默认数据库,以便将数据加载到相同的数据库中。还可以加上 --add-drop-database 选项将 DROP DATABASE 语句写在 CREATE DATABASE 语句之前,指定加载时先删除数据库。

导出单个数据库:

$> mysqldump --databases test > dump.sql

这种情况可以省略 --databases 选项:

$> mysqldump test > dump.sql

前面两个语句的不同之处在于,省略 --databases 选项的导出文件没有 CREATE DATABASEUSE 语句,则需要注意:

  • 当加载该导出文件时,必须指定默认数据库名称。
  • 如果数据库不存在,则需要先创建。
  • 由于导出文件没有 CREATE DATABASE 语句,则 --add-drop-database 选项无效,即使使用,也不会生成 DROP DATABASE 语句。

从数据库中导出指定表,将表名写在数据库名后面:

$> mysqldump test t1 t3 t7 > dump.sql

Reloading SQL-Format Backups

mysqldumpopen in new window 的 SQL 导出文件作为 mysqlopen in new window 客户端的输入,以加载导出文件数据到数据库中。如果导出时使用了 --all-databases 或者 --databases 选项,则导出文件中包含 CREATE DATABASEUSE 语句,这时就不需要指定加载数据的默认数据库:

$> mysql < dump.sql

也可以进入客户端,使用 source 命令:

mysql> source dump.sql

如果导出文件不包含 CREATE DATABASEUSE 语句,如有必要,则先创建数据库:

$> mysqladmin create db1

再在导入时指定数据库名称:

$> mysql db1 < dump.sql

也可以进入客户端,创建数据库,选择其作为默认数据库,再加载数据:

mysql> CREATE DATABASE IF NOT EXISTS db1;
mysql> USE db1;
mysql> source dump.sql

Dumping Data in Delimited-Text Format with mysqldump

如果加上 --tab=dir_name 选项,mysqldumpopen in new window 使用 dir_name 作为输出目录,为每个表生成两个文件。假设表名为 t1, 文件名分别为 t1.txtt1.sql,其中 SQL 文件包含创建表的 CREATE TABLE 语句,TXT 文件包含表数据。

例如以下命令导出 db1 数据库到 /tmp 目录:

$> mysqldump --tab=/tmp db1

最好在 MySQL Server 上使用 --tab 选项,如果在客户端使用该选项,则需要确保服务器端和客户端都必须有该选项指定的目录,此时会将 TXT 文件写到服务器端目录下,将 SQL 文件写到客户端目录下。

默认 TXT 文件中的一行对应表的一行,各字段值以 TAB 分割,与 SELECT ... INTO OUTFILE 的默认输出一致。可以使用以下选项调整输出格式:

  • --fields-terminated-by=str:指定字段值分隔符,默认为 TAB。
  • --fields-enclosed-by=char:指定字段值包围符,默认无包围符,如果字段值中存在 TAB,则需要设置该选项。
  • --fields-optionally-enclosed-by=char:指定非数字字段值的包围符,默认无包围符。
  • --fields-escaped-by=char:指定跳脱字符,默认无跳脱字符。
  • --lines-terminated-by=str:指定行分隔符,默认为 newline

例如使用双引号包围字段值:

--fields-enclosed-by='"'

或者使用双引号的 16 进制:

--fields-enclosed-by=0x22

例如以逗号分割字段值,以 \r\n 分割行进行导出:

$> mysqldump --tab=/tmp --fields-terminated-by=, --fields-enclosed-by='"' --lines-terminated-by=0x0d0a db1

加载时也需要使用对应的选项。

Reloading Delimited-Text Format Backups

加载使用 --tab 选项导出的文件,需要先切换到输出目录,然后使用 mysqlopen in new window 客户端处理 SQL 文件创建空表,再使用 mysqlimportopen in new window 处理 TXT 文件:

$> mysql db1 < t1.sql
$> mysqlimport db1 t1.txt

也可以进入 mysqlopen in new window 客户端,使用 LOAD DATA 语句加载数据:

mysql> USE db1;
mysql> LOAD DATA INFILE 't1.txt' INTO TABLE t1;

如果使用了上面的格式选项进行导出,则在加载时也需要使用对应的格式选项以便正确解析数据:

$> mysqlimport --fields-terminated-by=, --fields-enclosed-by='"' --lines-terminated-by=0x0d0a db1 t1.txt

或者:

mysql> USE db1;
mysql> LOAD DATA INFILE 't1.txt' INTO TABLE t1
       FIELDS TERMINATED BY ',' FIELDS ENCLOSED BY '"'
       LINES TERMINATED BY '\r\n';

mysqldump Tips

可以使用 mysqldumpopen in new window 解决以下问题。

Making a Copy of a Database

拷贝数据库。

$> mysqldump db1 > dump.sql
$> mysqladmin create db2
$> mysql db2 < dump.sql

此时不要使用 --databases 选项。

Copy a Database from one Server to Another

迁移数据库。

先在源环境导出:

$> mysqldump --databases db1 > dump.sql

然后拷贝导出文件到目标库。

再在目标环境加载:

$> mysql < dump.sql

可以忽略 --databases 选项,此时可能需要先再目标环境创建数据库,例如:

源环境导出:

$> mysqldump db1 > dump.sql

目标环境加载:

$> mysqladmin create db1
$> mysql db1 < dump.sql

此时也可以为目标环境指定其他数据库名称。

Dumping Stored Programs

导出存储程序。

使用以下选项处理存储程序(包括存储过程,函数,触发器和事件):

  • --events:导出事件,不加该选项为默认禁用。
  • --routines:导出存储过程和函数,不加该选项为默认禁用。
  • --triggers:导出表触发器,不加该选项为默认启用,可以使用 --skip-triggers 禁用。

Dumping Table Definitions and Content Separately

使用 --no-data 选项不导出表数据,只导出表的创建语句。使用 --no-create-info 语句只导出数据,不导出表的创建语句。

例如,分开导出 test 数据库的表创建语句和表数据:

$> mysqldump --no-data test > dump-defs.sql
$> mysqldump --no-create-info test > dump-data.sql

加上 --events--routines 选项导出存储过程和事件定义:

$> mysqldump --no-data --routines --events test > dump-defs.sql

Using mysqldump to Test for Upgrade Incompatibilities

在考虑升级 MySQL 时,一般是先将新版本与当前生产版本分开安装,然后从生产服务器导出数据库和数据库对象定义,并将其分别加载到升级服务器中,以验证其是否得到正确处理。

在生产服务器导出对象元数据:

$> mysqldump --all-databases --no-data --routines --events > dump-defs.sql

在升级服务器加载对象元数据:

$> mysql < dump-defs.sql

此时导入对象元数据,用于验证兼容性,完成后在生产服务器导出数据:

$> mysqldump --all-databases --no-create-info > dump-data.sql

在升级服务器加载数据:

$> mysql < dump-data.sql

现在检查表数据并运行测试查询语句。

Point-in-Time (Incremental) Recovery

基于时间点(Point-in-Time)的恢复是指使用全量备份和二进制日志将数据恢复到指定的时间点。

Point-in-Time Recovery Using Binary Log

注意:

如果二进制日志中包含 \0 (null) 字符,使用 mysqlopen in new window 客户端处理时需要加上 --binary-mode 选项。

基于时间点恢复的信息源是在完全备份操作之后生成的一组二进制日志文件。因此,要将服务器还原到指定时间点,必须在其上启用二进制日志,MySQL 8.0 默认启用,参考 Binary Logopen in new window

若要从二进制日志还原数据,必须知道当前二进制日志文件的名称和位置。默认情况下,在数据目录中创建二进制日志文件,可以使用 --log-bin 选项指定路径名,以将文件放置在其他位置。

使用以下语句查看所有二进制日志文件的列表:

mysql> SHOW BINARY LOGS;

使用以下语句查询当前二进制日志文件的名称:

mysql> SHOW MASTER STATUS;

使用 mysqlbinlogopen in new window 将二进制日志文件中的事件从二进制格式转换为文本,以便查看或应用。

使用 mysqlopen in new window 客户端处理 mysqlbinlogopen in new window 的输出以应用二进制日志中的事件:

$> mysqlbinlog binlog_files | mysql -u root -p

查看二进制日志内容:

$> mysqlbinlog binlog_files | more

也可以将二进制日志文件输出到文本文件进行编辑:

$> mysqlbinlog binlog_files > tmpfile
$> ... edit tmpfile ...

编辑后,应用到数据库中:

$> mysql -u root -p < tmpfile

如果需要应用多个二进制日志文件:

$> mysqlbinlog binlog.000001 binlog.000002 | mysql -u root -p

也可以将多个二进制日志文件输出到一个文本文件中,再应用:

$> mysqlbinlog binlog.000001 >  /tmp/statements.sql
$> mysqlbinlog binlog.000002 >> /tmp/statements.sql
$> mysql -u root -p -e "source /tmp/statements.sql"

Point-in-Time Recovery Using Event Positions

上一节介绍了使用二进制日志执行基于时间点恢复的一般思路。本节通过示例详细介绍该操作。

假设在 2020 年 3 月 11 日 20:06:00 左右,执行了删除表的 SQL 语句。可以执行基于时间点恢复,还原到删除表之前的状态。步骤如下:

  1. 还原距离问题时间点(2020 年 3 月 11 日 20:06:00)最近的全量备份,完成后记下还原到的二进制日志位置,然后重新启动 MySQL Server。
  2. 查找与问题时间点对应的二进制日志事件位置。可以通过使用 mysqlbinlogopen in new window 检查该时间点周围的日志内容来定位。使用 --start-datetime--stop-datetime 选项指定时间段,然后在输出中查找事件。例如:
$> mysqlbinlog --start-datetime="2020-03-11 20:05:00" \
                   --stop-datetime="2020-03-11 20:08:00" --verbose \
         /var/lib/mysql/bin.123456 | grep -C 15 "DROP TABLE"
 
/*!80014 SET @@session.original_server_version=80019*//*!*/;
/*!80014 SET @@session.immediate_server_version=80019*//*!*/;
SET @@SESSION.GTID_NEXT= 'ANONYMOUS'/*!*/;
# at 232
#200311 20:06:20 server id 1  end_log_pos 355 CRC32 0x2fc1e5ea 	Query	thread_id=16	exec_time=0	error_code=0
SET TIMESTAMP=1583971580/*!*/;
SET @@session.pseudo_thread_id=16/*!*/;
SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=0, @@session.unique_checks=1, @@session.autocommit=1/*!*/;
SET @@session.sql_mode=1168113696/*!*/;
SET @@session.auto_increment_increment=1, @@session.auto_increment_offset=1/*!*/;
/*!\C utf8mb4 *//*!*/;
SET @@session.character_set_client=255,@@session.collation_connection=255,@@session.collation_server=255/*!*/;
SET @@session.lc_time_names=0/*!*/;
SET @@session.collation_database=DEFAULT/*!*/;
/*!80011 SET @@session.default_collation_for_utf8mb4=255*//*!*/;
DROP TABLE `pets`.`cats` /* generated by server */
/*!*/;
# at 355
#200311 20:07:48 server id 1  end_log_pos 434 CRC32 0x123d65df 	Anonymous_GTID	last_committed=1	sequence_number=2	rbr_only=no	original_committed_timestamp=1583971668462467	immediate_commit_timestamp=1583971668462467	transaction_length=473
# original_commit_timestamp=1583971668462467 (2020-03-11 20:07:48.462467 EDT)
# immediate_commit_timestamp=1583971668462467 (2020-03-11 20:07:48.462467 EDT)
/*!80001 SET @@session.original_commit_timestamp=1583971668462467*//*!*/;
/*!80014 SET @@session.original_server_version=80019*//*!*/;
/*!80014 SET @@session.immediate_server_version=80019*//*!*/;
SET @@SESSION.GTID_NEXT= 'ANONYMOUS'/*!*/;
# at 434
#200311 20:07:48 server id 1  end_log_pos 828 CRC32 0x57fac9ac 	Query	thread_id=16	exec_time=0	error_code=0	Xid = 217
use `pets`/*!*/;
SET TIMESTAMP=1583971668/*!*/;
/*!80013 SET @@session.sql_require_primary_key=0*//*!*/;
CREATE TABLE dogs

可以看到删除表语句

DROP TABLE `pets`.`cats`

在二进制日志 # at 232# at 355 之间,意味着日志位置 232 发生在删除语句之前,日志位置 355 发生在删除语句之后。

  1. 应用二进制日志文件,起始位置为步骤 1 中找到的位置(假设为 155),结束位置为步骤 2 中找到的删除语句前的位置(为 232):
$> mysqlbinlog --start-position=155 --stop-position=232 /var/lib/mysql/bin.123456 \
         | mysql -u root -p

该命令恢复从起始位置到结束位置的所有事务,也就是恢复到误删除表之前。

  1. 在完成基于时间点恢复后,如果想重新执行删除语句后的语句,使用 --start-position 选项指定起始位置为 355:
$> mysqlbinlog --start-position=355 /var/lib/mysql/bin.123456 \
         | mysql -u root -p

这样就可以恢复到当前位置,跳过误删除语句。

Percona XtraBackup

注意:

此文档对应的 Percona XtraBackup 版本为 8.0.32-26。

Percona XtraBackup 是用于 MySQL 的开源热备工具。

Introduction

About Percona XtraBackup

Percona XtraBackup 支持 InnoDB 数据库非阻塞热备。

Percona XtraBackup 2.4 支持 MySQL 5.6 and 5.7。Percona XtraBackup 8.0.x 支持 MySQL 8.0.x。

Percona XtraBackup 还支持 XtraDB 及 MyRocks 存储引擎的非阻塞备份。

Percona XtraBackup 通过在备份结束时短暂暂停写入来备份 MyISAM 和 Merge 存储引擎,包括分区表、触发器和数据库选项。

How Percona XtraBackup works

Percona XtraBackup 基于 InnoDB 的崩溃恢复功能来实现热备。在某个时间点,复制 InnoDB 数据文件,这些数据文件可能包含未提交的事务和缺失已提交的事务,再对数据文件执行崩溃恢复后使其成为一致、可用的数据库。

这是因为 InnoDB 维护一组重做(REDO)日志,也称为事务日志,包含对 InnoDB 数据的每次更改记录。当 InnoDB 启动时,检查数据文件和重做日志,并执行以下两个步骤:

  • 将提交的重做日志条目应用于数据文件。
  • 对修改了数据但未提交的任何事务执行撤消(UNDO)操作。

Percona XtraBackup 8.0.30-23 版本增加了 --register-redo-log-consumer 参数,默认禁用。启用此参数后,Percona XtraBackup 可以在备份开始时注册为重做日志消费者。MySQL Server 不会删除 Percona XtraBackup(消费者)尚未复制的重做日志。消费者读取重做日志并手动推进日志序列号(Log Sequence Number LSN),在此过程中阻止写入。根据重做日志的消费情况来确定何时可以清除日志。

Percona XtraBackup 的工作原理就是在其启动时记住 LSN,然后拷贝数据文件。同时 Percona XtraBackup 运行一个后台进程监视重做日志文件,并从中复制更改。

Percona XtraBackup 在可用情况下使用轻量级的备份锁(Backup locksopen in new window)而不是 FLUSH TABLES WITH READ LOCK。MySQL 8.0 允许通过 LOCK INSTANCE FOR BACKUP 语句获取实例级备份锁。

只有在 Percona XtraBackup 备份完所有 InnoDB/XtraDB 数据和日志后,才会对 MyISAM 和其他非 InnoDB 表加锁。Percona XtraBackup 会自动使用其来复制非 InnoDB 数据,以避免阻塞修改 InnoDB 表的 DML 操作。

当实例仅包含 InnoDB 表时,Percona XtraBackup 试图避免备份锁和 FLUSH TABLES WITH READ LOCK。在这种情况下,Percona XtraBackup 从 performance_schema.log_status 获取二进制日志坐标。当在 MySQL 8.0 中使用 --slave-info 选项启动Percona XtraBackup 时,仍然需要 FLUSH TABLES WITH READ LOCK

在准备阶段,Percona XtraBackup 使用复制的重做日志文件对复制的数据文件执行崩溃恢复。完成此操作后,备份文件就可以用于还原和使用了。

Percona XtraBackup 使用 --copy-back--move-back 选项还原备份。首先从参数文件 my.cnf 中获取参数 datadirinnodb_data_home_dirinnodb_data_file_pathinnodb_log_group_home_dir,检查参数指定的目录是否存在。然后依次拷贝 InnoDB 表及索引, 非 InnoDB 表及索引,最后是日志文件。拷贝完成后需要确保文件的属组与 MySQL Server 的属组一致。

注意:

由于 --move-back 选项会删除备份文件,谨慎使用。

Installation

Use RPM downloaded packages to install Percona XtraBackup

官方网站open in new window下载页面选择版本和操作系统平台,下载对应的 RPM 包:percona-xtrabackup-80-8.0.32-26.1.el7.x86_64.rpm。

安装:

[root@mysql ~]# yum localinstall percona-xtrabackup-80-8.0.32-26.1.el7.x86_64.rpm

How Percona XtraBackup works

Implementation details

  • 需要有数据文件的读写权限。
  • 使用 posix_fadvise() 跳过操作系统缓存。
  • 以 1MB 为单位读写数据文件,以 512 字节为单位读写日志文件。

Connection and privileges needed

通过指定 --user--password 选项连接到 MySQL Server:

[root@mysql ~]# mkdir /data/bkps
[root@mysql ~]# chown mysql:mysql /data/bkps/
[root@mysql ~]# xtrabackup --user=backup --password='Qe7g!sJq#z' --backup --target-dir=/data/bkps/

创建备份用户并授予权限如下:

mysql> CREATE USER 'backup'@'localhost' IDENTIFIED BY 'Qe7g!sJq#z';
mysql> GRANT BACKUP_ADMIN, PROCESS, RELOAD, LOCK TABLES, REPLICATION CLIENT ON *.* TO 'backup'@'localhost';
mysql> GRANT SELECT ON performance_schema.log_status TO 'backup'@'localhost';
mysql> GRANT SELECT ON performance_schema.keyring_component_status TO 'backup'@'localhost';
mysql> GRANT SELECT ON performance_schema.replication_group_members TO 'backup'@'localhost';
mysql> FLUSH PRIVILEGES;

Configure xtrabackup

可以在命令行或者 MySQL 参数文件 /etc/my.cnf 中指定 Percona XtraBackup 选项,依次读取 [mysqld][xtrabackup] 部分的配置。

[xtrabackup]
user=backup
password='Qe7g!sJq#z'
target_dir=/data/bkps/

System configuration and NFS volumes

当备份到 NFS 上时,NFS 需要使用 sync 挂载选项。

Backup scenarios

The backup cycle - full backups

Create a backup

使用 --backup 选项运行 xtrabackup 命令,同时使用 --target-dir 选项(或者在参数文件中)指定备份目录。如果目录不存在,则会创建。目标不为空,报错 OS errno 17 - File exists, 备份失败。

启动备份进程,将数据备份到 /data/bkps/ 目标目录下 :

[root@mysql ~]# xtrabackup --backup --target-dir=/data/bkps/

备份输出的部分日志:

2023-05-02T14:05:21.423312+08:00 0 [Note] [MY-011825] [Xtrabackup] Finished backing up non-InnoDB tables and files
2023-05-02T14:05:21.423372+08:00 0 [Note] [MY-011825] [Xtrabackup] Executing FLUSH NO_WRITE_TO_BINLOG BINARY LOGS
2023-05-02T14:05:21.429642+08:00 0 [Note] [MY-011825] [Xtrabackup] Selecting LSN and binary log position from p_s.log_status
2023-05-02T14:05:21.434861+08:00 0 [Note] [MY-011825] [Xtrabackup] Copying /data/mysql/binlog.000060 to /data/bkps/binlog.000060 up to position 197
2023-05-02T14:05:21.435208+08:00 0 [Note] [MY-011825] [Xtrabackup] Done: Copying /data/mysql/binlog.000060 to /data/bkps/binlog.000060
2023-05-02T14:05:21.436242+08:00 0 [Note] [MY-011825] [Xtrabackup] Writing /data/bkps/binlog.index
2023-05-02T14:05:21.436551+08:00 0 [Note] [MY-011825] [Xtrabackup] Done: Writing file /data/bkps/binlog.index
2023-05-02T14:05:21.441626+08:00 0 [Note] [MY-011825] [Xtrabackup] Writing /data/bkps/xtrabackup_binlog_info
2023-05-02T14:05:21.441966+08:00 0 [Note] [MY-011825] [Xtrabackup] Done: Writing file /data/bkps/xtrabackup_binlog_info
2023-05-02T14:05:21.443567+08:00 0 [Note] [MY-011825] [Xtrabackup] Executing FLUSH NO_WRITE_TO_BINLOG ENGINE LOGS...
2023-05-02T14:05:21.446330+08:00 0 [Note] [MY-011825] [Xtrabackup] The latest check point (for incremental): '24168777'
2023-05-02T14:05:21.446399+08:00 0 [Note] [MY-011825] [Xtrabackup] Stopping log copying thread at LSN 24168777
2023-05-02T14:05:21.446536+08:00 1 [Note] [MY-011825] [Xtrabackup] Starting to parse redo log at lsn = 24168476
2023-05-02T14:05:21.449310+08:00 0 [Note] [MY-011825] [Xtrabackup] Executing UNLOCK INSTANCE
2023-05-02T14:05:21.449903+08:00 0 [Note] [MY-011825] [Xtrabackup] All tables unlocked
2023-05-02T14:05:21.450197+08:00 0 [Note] [MY-011825] [Xtrabackup] Copying ib_buffer_pool to /data/bkps/ib_buffer_pool
2023-05-02T14:05:21.451124+08:00 0 [Note] [MY-011825] [Xtrabackup] Done: Copying ib_buffer_pool to /data/bkps/ib_buffer_pool
2023-05-02T14:05:21.451966+08:00 0 [Note] [MY-011825] [Xtrabackup] Backup created in directory '/data/bkps/'
2023-05-02T14:05:21.452013+08:00 0 [Note] [MY-011825] [Xtrabackup] MySQL binlog position: filename 'binlog.000060', position '197', GTID of the last change 'bccc696b-a6a9-11ed-ae58-000c29fa5be5:1-147'
2023-05-02T14:05:21.452129+08:00 0 [Note] [MY-011825] [Xtrabackup] Writing /data/bkps/backup-my.cnf
2023-05-02T14:05:21.452451+08:00 0 [Note] [MY-011825] [Xtrabackup] Done: Writing file /data/bkps/backup-my.cnf
2023-05-02T14:05:21.454548+08:00 0 [Note] [MY-011825] [Xtrabackup] Writing /data/bkps/xtrabackup_info
2023-05-02T14:05:21.455037+08:00 0 [Note] [MY-011825] [Xtrabackup] Done: Writing file /data/bkps/xtrabackup_info
2023-05-02T14:05:22.460868+08:00 0 [Note] [MY-011825] [Xtrabackup] Transaction log of lsn (24168777) to (24168777) was copied.
2023-05-02T14:05:22.712512+08:00 0 [Note] [MY-011825] [Xtrabackup] completed OK!

备份完成后,目标目录文件如下:

[root@mysql ~]# ll -rth /data/bkps/
total 69M
-rw-r----- 1 root root  12M May  2 14:05 ibdata1
drwxr-x--- 2 root root   28 May  2 14:05 sys
drwxr-x--- 2 root root  196 May  2 14:05 menagerie
-rw-r----- 1 root root  24M May  2 14:05 mysql.ibd
-rw-r----- 1 root root  16M May  2 14:05 undo_002
-rw-r----- 1 root root  16M May  2 14:05 undo_001
drwxr-x--- 2 root root  143 May  2 14:05 mysql
drwxr-x--- 2 root root 8.0K May  2 14:05 performance_schema
-rw-r----- 1 root root  197 May  2 14:05 binlog.000060
-rw-r----- 1 root root   16 May  2 14:05 binlog.index
-rw-r----- 1 root root   61 May  2 14:05 xtrabackup_binlog_info
-rw-r----- 1 root root 2.5K May  2 14:05 xtrabackup_logfile
-rw-r----- 1 root root  134 May  2 14:05 xtrabackup_checkpoints
-rw-r----- 1 root root 4.1K May  2 14:05 ib_buffer_pool
-rw-r----- 1 root root  450 May  2 14:05 backup-my.cnf
-rw-r----- 1 root root  495 May  2 14:05 xtrabackup_info
-rw-r----- 1 root root   39 May  2 14:05 xtrabackup_tablespaces
Prepare a backup

使用 --backup 选项创建备份后,需要使用 --prepare 选项对备份进行 Prepare 以便还原。因为在备份过程中,不同文件拷贝的时间不同,在此期间,数据可能发生变化,备份完成后为保证数据一致性,需要在 Prepare 阶段进行崩溃恢复。例如:

[root@mysql ~]# xtrabackup --prepare --target-dir=/data/bkps/
2023-05-02T16:26:23.256065+08:00 0 [Note] [MY-011825] [Xtrabackup] recognized server arguments: --innodb_checksum_algorithm=crc32 --innodb_log_checksums=1 --innodb_data_file_path=ibdata1:12M:autoextend --innodb_log_file_size=50331648 --innodb_page_size=16384 --innodb_undo_directory=./ --innodb_undo_tablespaces=2 --server-id=8141 --innodb_log_checksums=ON --innodb_redo_log_encrypt=0 --innodb_undo_log_encrypt=0 
2023-05-02T16:26:23.256353+08:00 0 [Note] [MY-011825] [Xtrabackup] recognized client arguments: --prepare=1 --target-dir=/data/bkps/ 
xtrabackup version 8.0.32-26 based on MySQL server 8.0.32 Linux (x86_64) (revision id: 34cf2908)
2023-05-02T16:26:23.256398+08:00 0 [Note] [MY-011825] [Xtrabackup] cd to /data/bkps/
2023-05-02T16:26:23.256544+08:00 0 [Note] [MY-011825] [Xtrabackup] This target seems to be not prepared yet.
2023-05-02T16:26:23.277666+08:00 0 [Note] [MY-011825] [Xtrabackup] xtrabackup_logfile detected: size=8388608, start_lsn=(24168787)
2023-05-02T16:26:23.279565+08:00 0 [Note] [MY-011825] [Xtrabackup] using the following InnoDB configuration for recovery:
2023-05-02T16:26:23.279617+08:00 0 [Note] [MY-011825] [Xtrabackup] innodb_data_home_dir = .
2023-05-02T16:26:23.279637+08:00 0 [Note] [MY-011825] [Xtrabackup] innodb_data_file_path = ibdata1:12M:autoextend
2023-05-02T16:26:23.279875+08:00 0 [Note] [MY-011825] [Xtrabackup] innodb_log_group_home_dir = .
2023-05-02T16:26:23.279911+08:00 0 [Note] [MY-011825] [Xtrabackup] innodb_log_files_in_group = 1
2023-05-02T16:26:23.279941+08:00 0 [Note] [MY-011825] [Xtrabackup] innodb_log_file_size = 8388608
2023-05-02T16:26:23.280945+08:00 0 [Note] [MY-011825] [Xtrabackup] inititialize_service_handles suceeded
2023-05-02T16:26:23.282199+08:00 0 [Note] [MY-011825] [Xtrabackup] using the following InnoDB configuration for recovery:
2023-05-02T16:26:23.282241+08:00 0 [Note] [MY-011825] [Xtrabackup] innodb_data_home_dir = .
2023-05-02T16:26:23.282255+08:00 0 [Note] [MY-011825] [Xtrabackup] innodb_data_file_path = ibdata1:12M:autoextend
2023-05-02T16:26:23.282281+08:00 0 [Note] [MY-011825] [Xtrabackup] innodb_log_group_home_dir = .
2023-05-02T16:26:23.282294+08:00 0 [Note] [MY-011825] [Xtrabackup] innodb_log_files_in_group = 1
2023-05-02T16:26:23.282306+08:00 0 [Note] [MY-011825] [Xtrabackup] innodb_log_file_size = 8388608
2023-05-02T16:26:23.282323+08:00 0 [Note] [MY-011825] [Xtrabackup] Starting InnoDB instance for recovery.
2023-05-02T16:26:23.282337+08:00 0 [Note] [MY-011825] [Xtrabackup] Using 104857600 bytes for buffer pool (set by --use-memory parameter)
2023-05-02T16:26:23.282703+08:00 0 [Note] [MY-012932] [InnoDB] PUNCH HOLE support available
2023-05-02T16:26:23.282746+08:00 0 [Note] [MY-012944] [InnoDB] Uses event mutexes
2023-05-02T16:26:23.282760+08:00 0 [Note] [MY-012945] [InnoDB] GCC builtin __atomic_thread_fence() is used for memory barrier
2023-05-02T16:26:23.282844+08:00 0 [Note] [MY-012948] [InnoDB] Compressed tables use zlib 1.2.13
2023-05-02T16:26:23.283569+08:00 0 [Note] [MY-012951] [InnoDB] Using hardware accelerated crc32 and polynomial multiplication.
2023-05-02T16:26:23.284240+08:00 0 [Note] [MY-012203] [InnoDB] Directories to scan './'
2023-05-02T16:26:23.284328+08:00 0 [Note] [MY-012204] [InnoDB] Scanning './'
2023-05-02T16:26:23.299917+08:00 0 [Note] [MY-012208] [InnoDB] Completed space ID check of 16 files.
2023-05-02T16:26:23.301103+08:00 0 [Note] [MY-012955] [InnoDB] Initializing buffer pool, total size = 128.000000M, instances = 1, chunk size =128.000000M 
2023-05-02T16:26:23.315118+08:00 0 [Note] [MY-012957] [InnoDB] Completed initialization of buffer pool
2023-05-02T16:26:23.328936+08:00 0 [Note] [MY-011951] [InnoDB] page_cleaner coordinator priority: -20
2023-05-02T16:26:23.329572+08:00 0 [Note] [MY-011954] [InnoDB] page_cleaner worker priority: -20
2023-05-02T16:26:23.330749+08:00 0 [Note] [MY-011954] [InnoDB] page_cleaner worker priority: -20
2023-05-02T16:26:23.331008+08:00 0 [Note] [MY-011954] [InnoDB] page_cleaner worker priority: -20
2023-05-02T16:26:23.454856+08:00 0 [Note] [MY-013883] [InnoDB] The latest found checkpoint is at lsn = 24168787 in redo log file ./#innodb_redo/#ib_redo0.
2023-05-02T16:26:23.454986+08:00 0 [Note] [MY-012560] [InnoDB] The log sequence number 24107962 in the system tablespace does not match the log sequence number 24168787 in the redo log files!
2023-05-02T16:26:23.455029+08:00 0 [Note] [MY-012551] [InnoDB] Database was not shutdown normally!
2023-05-02T16:26:23.455052+08:00 0 [Note] [MY-012552] [InnoDB] Starting crash recovery.
2023-05-02T16:26:23.455226+08:00 0 [Note] [MY-013086] [InnoDB] Starting to parse redo log at lsn = 24168476, whereas checkpoint_lsn = 24168787 and start_lsn = 24168448
2023-05-02T16:26:23.455256+08:00 0 [Note] [MY-012550] [InnoDB] Doing recovery: scanned up to log sequence number 24168787
2023-05-02T16:26:23.507290+08:00 0 [Note] [MY-013083] [InnoDB] Log background threads are being started...
2023-05-02T16:26:23.562432+08:00 0 [Note] [MY-012532] [InnoDB] Applying a batch of 0 redo log records ...
2023-05-02T16:26:23.562478+08:00 0 [Note] [MY-012535] [InnoDB] Apply batch completed!
2023-05-02T16:26:23.664071+08:00 0 [Note] [MY-013084] [InnoDB] Log background threads are being closed...
2023-05-02T16:26:23.671748+08:00 0 [Note] [MY-013041] [InnoDB] Resizing redo log from 8M to 1024M (LSN=24168787) synchronously. If this takes too long, consider starting the server with large --innodb_redo_log_capacity, and resizing the redo log online using SET.
2023-05-02T16:26:23.672883+08:00 0 [Note] [MY-012968] [InnoDB] Starting to delete and rewrite redo log files.
2023-05-02T16:26:23.673027+08:00 0 [Note] [MY-011825] [InnoDB] Removing redo log file: ./#innodb_redo/#ib_redo0
2023-05-02T16:26:23.770435+08:00 0 [Note] [MY-011825] [InnoDB] Creating redo log file at ./#innodb_redo/#ib_redo0_tmp with file_id 0 with size 33554432 bytes
2023-05-02T16:26:23.772784+08:00 0 [Note] [MY-011825] [InnoDB] Renaming redo log file from ./#innodb_redo/#ib_redo0_tmp to ./#innodb_redo/#ib_redo0
2023-05-02T16:26:23.773889+08:00 0 [Note] [MY-012893] [InnoDB] New redo log files created, LSN=24168972
2023-05-02T16:26:23.773975+08:00 0 [Note] [MY-013083] [InnoDB] Log background threads are being started...
2023-05-02T16:26:23.781963+08:00 0 [Note] [MY-013252] [InnoDB] Using undo tablespace './undo_001'.
2023-05-02T16:26:23.783390+08:00 0 [Note] [MY-013252] [InnoDB] Using undo tablespace './undo_002'.
2023-05-02T16:26:23.786200+08:00 0 [Note] [MY-012910] [InnoDB] Opened 2 existing undo tablespaces.
2023-05-02T16:26:23.786398+08:00 0 [Note] [MY-011980] [InnoDB] GTID recovery trx_no: 39204
2023-05-02T16:26:23.847068+08:00 0 [Note] [MY-013776] [InnoDB] Parallel initialization of rseg complete
2023-05-02T16:26:23.847118+08:00 0 [Note] [MY-013777] [InnoDB] Time taken to initialize rseg using 2 thread: 60782 ms.
2023-05-02T16:26:23.847404+08:00 0 [Note] [MY-012923] [InnoDB] Creating shared tablespace for temporary tables
2023-05-02T16:26:23.847474+08:00 0 [Note] [MY-012265] [InnoDB] Setting file './ibtmp1' size to 12 MB. Physically writing the file full; Please wait ...
2023-05-02T16:26:23.914321+08:00 0 [Note] [MY-012266] [InnoDB] File './ibtmp1' size is now 12 MB.
2023-05-02T16:26:23.914727+08:00 0 [Note] [MY-013627] [InnoDB] Scanning temp tablespace dir:'./#innodb_temp/'
2023-05-02T16:26:23.934242+08:00 0 [Note] [MY-013018] [InnoDB] Created 128 and tracked 128 new rollback segment(s) in the temporary tablespace. 128 are now active.
2023-05-02T16:26:23.936302+08:00 0 [Note] [MY-012976] [InnoDB] 8.0.32 started; log sequence number 24168982
2023-05-02T16:26:23.937379+08:00 0 [Warning] [MY-012091] [InnoDB] Allocated tablespace ID 1 for sys/sys_config, old maximum was 0
2023-05-02T16:26:24.001642+08:00 0 [Note] [MY-011825] [Xtrabackup] starting shutdown with innodb_fast_shutdown = 1
2023-05-02T16:26:24.002060+08:00 0 [Note] [MY-012330] [InnoDB] FTS optimize thread exiting.
2023-05-02T16:26:25.001362+08:00 0 [Note] [MY-013072] [InnoDB] Starting shutdown...
2023-05-02T16:26:25.031375+08:00 0 [Note] [MY-013084] [InnoDB] Log background threads are being closed...
2023-05-02T16:26:25.068812+08:00 0 [Note] [MY-012980] [InnoDB] Shutdown completed; log sequence number 24168982
2023-05-02T16:26:25.072440+08:00 0 [Note] [MY-011825] [Xtrabackup] completed OK!

已经 Prepare 的备份,再次 Prepare 不会发生改变,输出如下:

2023-05-02T16:31:45.681728+08:00 0 [Note] [MY-011825] [Xtrabackup] This target seems to be already prepared.
2023-05-02T16:31:45.682750+08:00 0 [Note] [MY-011825] [Xtrabackup] xtrabackup_logfile was already used to '--prepare'.

在 Prepare 备份时不要中断 xtrabackup 进程,否则可能导致数据文件损坏,备份不可用。

Restore a backup

警告:

备份进行还原(Restore)前需要先 Prepare。

使用 --copy-back 选项拷贝备份到数据目录。拷贝之前需要关闭 MySQL Server,确保数据目录为空。拷贝之后根据需要调整目录属组。

[root@mysql ~]# systemctl stop mysqld.service 
[root@mysql ~]# rm -fr /data/mysql/*
[root@mysql ~]# xtrabackup --copy-back --target-dir=/data/bkps/
[root@mysql ~]# chown -R mysql:mysql /data/mysql/
[root@mysql ~]# systemctl start mysqld.service 

Incremental backup

Percona XtraBackup 支持增量备份。对于大型数据库,备份策略一般为周日进行全量备份,周一到周六进行增量备份。

增量备份基于 InnoDB 页中的 LSN(Log Sequence Number),为整个数据库的系统版本号。增量备份复制比上一个备份(增量或全量)的 LSN 新的页。

Create an incremental backup

增量备份基于全量备份。Percona XtraBackup 会在备份目录中创建 xtrabackup_checkpoints 文件,文件中的 to_lsn 表示备份结束时数据库的 LSN。

先创建全量备份:

[root@mysql ~]# mkdir /data/bkps/{base,inc1,inc2}
[root@mysql ~]# chown mysql:mysql /data/bkps/*
[root@mysql ~]# ll /data/bkps/
total 0
drwxr-xr-x 2 mysql mysql 6 May  2 18:11 base
drwxr-xr-x 2 mysql mysql 6 May  2 18:11 inc1
drwxr-xr-x 2 mysql mysql 6 May  2 18:11 inc2
[root@mysql ~]# xtrabackup --backup --target-dir=/data/bkps/base
[root@mysql ~]# cat /data/bkps/base/xtrabackup_checkpoints 
backup_type = full-backuped
from_lsn = 0
to_lsn = 24218346
last_lsn = 24218346
flushed_lsn = 24218346
redo_memory = 0
redo_frames = 0

基于上面的全量备份创建增量备份:

[root@mysql ~]# xtrabackup --backup --target-dir=/data/bkps/inc1 --incremental-basedir=/data/bkps/base
[root@mysql ~]# du -sh /data/bkps/*
72M     /data/bkps/base
3.1M    /data/bkps/inc1
0       /data/bkps/inc2
[root@mysql ~]# cat /data/bkps/inc1/xtrabackup_checkpoints 
backup_type = incremental
from_lsn = 24218346
to_lsn = 24237231
last_lsn = 24237231
flushed_lsn = 24237231
redo_memory = 0
redo_frames = 0

基于上面的增量备份创建增量备份:

[root@mysql ~]# xtrabackup --backup --target-dir=/data/bkps/inc2 --incremental-basedir=/data/bkps/inc1
[root@mysql ~]# du -sh /data/bkps/*
72M     /data/bkps/base
3.1M    /data/bkps/inc1
2.3M    /data/bkps/inc2
[root@mysql ~]# cat /data/bkps/inc2/xtrabackup_checkpoints 
backup_type = incremental
from_lsn = 24237231
to_lsn = 24238735
last_lsn = 24238735
flushed_lsn = 24238735
redo_memory = 0
redo_frames = 0

注意:

to_lsnlast_lsn 不一致表示在备份过程中,数据发生了改变。

Prepare the incremental backups

与全量备份进行 Prepare 不同,增量备份(非最后一个)在使用 --prepare 选项进行 Prepare 时,需要使用 --apply-log-only 选项阻止回滚阶段。因为在当前增量备份中未提交的事务,有可能在下一个增量备份中提交。

对于全量备份进行 Prepare:

[root@mysql ~]# xtrabackup --prepare --apply-log-only --target-dir=/data/bkps/base

将第一个增量备份应用到全量备份:

[root@mysql ~]# xtrabackup --prepare --apply-log-only --target-dir=/data/bkps/base --incremental-dir=/data/bkps/inc1
[root@mysql ~]# cat /data/bkps/base/xtrabackup_checkpoints 
backup_type = log-applied
from_lsn = 0
to_lsn = 24237231
last_lsn = 24237231
flushed_lsn = 24237231
redo_memory = 0
redo_frames = 0

将增量文件应用于 /data/bkps/base 中的文件,前滚到增量备份的时间,然后应用重做日志。

警告:

只能对某个增量备份使用一次 --prepare

将第二个增量备份应用到全量备份:

[root@mysql ~]# xtrabackup --prepare --target-dir=/data/bkps/base --incremental-dir=/data/bkps/inc2
[root@mysql ~]# cat /data/bkps/base/xtrabackup_checkpoints 
backup_type = full-prepared
from_lsn = 0
to_lsn = 24238735
last_lsn = 24238735
flushed_lsn = 24238735
redo_memory = 0
redo_frames = 0

此时为最后一个增量备份,故无需使用 --apply-log-only 选项,完成后全量备份就可以用于还原了。

Compressed backup

Percona XtraBackup 支持压缩备份。

Create compressed backups

可以使用 --compress 选项创建压缩备份,可选算法有 quicklzlz4zstd,其中 quicklz 为默认,但是从 Percona XtraBackup 8.0.31-24 版本被废弃,建议选择 lz4 或者 zstd

使用 lz4 压缩算法创建压缩备份:

$ xtrabackup --backup --compress=lz4 --target-dir=/data/backup

使用 ZSTD 压缩算法创建压缩备份:

$ xtrabackup --backup --compress=zstd --target-dir=/data/backup

使用 --compress-zstd-level(=#) 指定压缩级别:

$ xtrabackup --backup --compress-zstd-level=1 --target-dir=/data/backup

使用 --compress-threads 指定并行度:

[root@mysql ~]# xtrabackup --backup --compress=zstd --compress-threads=4 --target-dir=/data/backup/
[root@mysql ~]# du -sh /data/backup/
2.1M    /data/backup/
[root@mysql ~]# cat /data/backup/xtrabackup_checkpoints 
backup_type = full-backuped
from_lsn = 0
to_lsn = 24288239
last_lsn = 24288239
flushed_lsn = 24288239
redo_memory = 0
redo_frames = 0
Prepare the backup

在对压缩备份进行 Prepare 前,需要先使用 --decompress 选项解压备份:

[root@mysql ~]# yum isntall zstd
[root@mysql ~]# xtrabackup --decompress --target-dir=/data/backup/
[root@mysql ~]# du -sh /data/backup/
74M     /data/backup/
[root@mysql ~]# cat /data/backup/xtrabackup_checkpoints
backup_type = full-backuped
from_lsn = 0
to_lsn = 24288239
last_lsn = 24288239
flushed_lsn = 24288239
redo_memory = 0
redo_frames = 0

注意:

--parallel 可以和 --decompress 一起使用同时解压多个文件。

解压后使用 --prepare 选项:

[root@mysql ~]# xtrabackup --prepare --target-dir=/data/backup/
[root@mysql ~]# cat /data/backup/xtrabackup_checkpoints
backup_type = full-prepared
from_lsn = 0
to_lsn = 24288239
last_lsn = 24288239
flushed_lsn = 24288239
redo_memory = 0
redo_frames = 0

完成后就可以用于还原了。

Partial backups

当启用参数 innodb_file_per_table (默认启用)时,Percona XtraBackup 支持部分备份。

有三种方式创建部分备份:

  • 使用正则表达式匹配表名。
  • 在文件中提供表名清单。
  • 指定多个数据库名。

警告:

不要对 Prepare 的部分备份使用 –copy-back 选项,应该使用导入表的方式进行还原。也不要对部分备份进行增量备份。

Create partial backups

使用以下参数指定部分备份对象:

  • --tables :使用正则表达式列出表名。
  • --tables-file :在文件中提供表名清单。
  • --databases :指定多个数据库名。
  • --databases-file :在文件中提供数据库名清单。
  1. 使用 –-tables 选项,格式为 databasename.tablename

备份 menagerie 数据库的所有表:

[root@mysql ~]# xtrabackup --backup --target-dir=/data/backup/ --tables="^menagerie[.].*"
[root@mysql ~]# cat /data/backup/xtrabackup_checkpoints 
backup_type = full-backuped
from_lsn = 0
to_lsn = 24336000
last_lsn = 24336000
flushed_lsn = 24336000
redo_memory = 0
redo_frames = 0

备份 menagerie 数据库的 pet 表:

[root@mysql ~]# xtrabackup --backup --target-dir=/data/backup/ --tables="^menagerie[.]pet"
[root@mysql ~]# cat /data/backup/xtrabackup_checkpoints 
backup_type = full-backuped
from_lsn = 0
to_lsn = 24336020
last_lsn = 24336020
flushed_lsn = 24336020
redo_memory = 0
redo_frames = 0
  1. 使用 -–tables-file 选项,指定包含表名清单的文件,格式为 databasename.tablename

创建表名清单文件 /tmp/tables.txt 并备份:

[root@mysql ~]# echo "menagerie.pet" > /tmp/tables.txt
[root@mysql ~]# xtrabackup --backup --target-dir=/data/backup/ --tables-file=/tmp/tables.txt
[root@mysql ~]# cat /data/backup/xtrabackup_checkpoints 
backup_type = full-backuped
from_lsn = 0
to_lsn = 24336030
last_lsn = 24336030
flushed_lsn = 24336030
redo_memory = 0
redo_frames = 0
  1. 使用 --databases 选项,格式为 databasename[.tablename],需要指定 mysqlsysperformance_schema 数据库。

备份 menagerie 数据库。

[root@mysql ~]# xtrabackup --backup --target-dir=/data/backup/ --databases='mysql sys performance_schema menagerie'
[root@mysql ~]# cat /data/backup/xtrabackup_checkpoints 
backup_type = full-backuped
from_lsn = 0
to_lsn = 24336050
last_lsn = 24336050
flushed_lsn = 24336050
redo_memory = 0
redo_frames = 0
  1. 使用 --databases-file 选项,指定包含数据库名及表名的文件,格式为 databasename[.tablename]
Prepare partial backups

使用 --prepare--export 选项 Prepare:

[root@mysql ~]# xtrabackup --prepare --export --target-dir=/data/backup/
[root@mysql ~]# cat /data/backup/xtrabackup_checkpoints 
backup_type = full-prepared
from_lsn = 0
to_lsn = 24336050
last_lsn = 24336050
flushed_lsn = 24336050
redo_memory = 0
redo_frames = 0
Restore partial backups

将备份目录下的表还原到目标环境的步骤如下:

  1. 在目标环境,创建与原环境相同的表,可以使用 SHOW CREATE TABLE 语句获取表定义。
mysql> USE menagerie;
mysql> CREATE TABLE t1 (c1 INT, x INT) ENGINE=INNODB;
  1. 在目标环境,丢弃刚刚为表创建的表空间。
mysql> ALTER TABLE t1 DISCARD TABLESPACE;
  1. 在源环境,将备份目录下的 .ibd 文件和 .cfg 元数据文件复制到目标环境,权限需要保持一致。如果目标环境是主从架构,则需要将文件复制到主库和从库。
$> scp /data/backup/menagerie/t1.{ibd,cfg} destination-server:/path/to/datadir/menagerie
  1. 在目标环境,导入表空间。
mysql> USE menagerie;
mysql> ALTER TABLE t1 IMPORT TABLESPACE;

Advanced features

Point-in-time recovery

Percona XtraBackup 支持使用备份和二进制日志文件进行基于时间点恢复。

先进行备份和 Prepare:

[root@mysql ~]# xtrabackup --backup --target-dir=/data/backup/
[root@mysql ~]# xtrabackup --prepare --target-dir=/data/backup/
[root@mysql ~]# cat /data/backup/xtrabackup_checkpoints 
backup_type = full-prepared
from_lsn = 0
to_lsn = 24351012
last_lsn = 24351012
flushed_lsn = 24351012
redo_memory = 0
redo_frames = 0

查看二进制日志文件:

[(none)]> SHOW BINARY LOGS;
+---------------+-----------+-----------+
| Log_name      | File_size | Encrypted |
+---------------+-----------+-----------+
| binlog.000065 |       237 | No        |
| binlog.000066 |       281 | No        |
| binlog.000067 |       281 | No        |
| binlog.000068 |       260 | No        |
| binlog.000069 |       281 | No        |
| binlog.000070 |       281 | No        |
| binlog.000071 |       281 | No        |
| binlog.000072 |       281 | No        |
| binlog.000073 |       281 | No        |
| binlog.000074 |       281 | No        |
| binlog.000075 |       762 | No        |
| binlog.000076 |       887 | No        |
| binlog.000077 |       277 | No        |
+---------------+-----------+-----------+
13 rows in set (0.00 sec)

查看当前使用的二进制日志文件及位置:

[(none)]> SHOW MASTER STATUS\G
*************************** 1. row ***************************
             File: binlog.000077
         Position: 277
     Binlog_Do_DB: 
 Binlog_Ignore_DB: 
Executed_Gtid_Set: 04839312-e8dc-11ed-89a9-000c29fa5be5:1-4,
b7df3820-e8cd-11ed-ab4d-000c29fa5be5:1-4,
bccc696b-a6a9-11ed-ae58-000c29fa5be5:1-147
1 row in set (0.00 sec)

获取完成备份时对应的二进制日志文件及位置作为基于时间点恢复的起点:

[root@mysql ~]# cat /data/backup/xtrabackup_binlog_info 
binlog.000076   277     04839312-e8dc-11ed-89a9-000c29fa5be5:1-2,b7df3820-e8cd-11ed-ab4d-000c29fa5be5:1-4,bccc696b-a6a9-11ed-ae58-000c29fa5be5:1-147

可以看到完成备份时对应的二进制日志文件为 binlog.000076,位置为 277。而当前的二进制日志文件为 binlog.000077,位置为 277。需要先将备份到当前之间的二进制日志文件拷贝到临时目录:

[root@mysql ~]# cp /data/mysql/binlog.000076 /data/mysql/binlog.000077 /tmp/

再使用备份进行还原:

[root@mysql ~]# systemctl stop mysqld.service 
[root@mysql ~]# rm -fr /data/mysql/*
[root@mysql ~]# xtrabackup --copy-back --target-dir=/data/backup/
[root@mysql ~]# chown -R mysql:mysql /data/mysql/
[root@mysql ~]# systemctl start mysqld.service 

使用 mysqlbinlogopen in new window 解析二进制日志文件定位恢复点:

[root@mysql ~]# mysqlbinlog --verbose /tmp/binlog.000076 /tmp/binlog.000077 --start-position=277 | grep -C 15 "INSERT INTO"

使用恢复点进行恢复:

[root@mysql ~]# mysqlbinlog /tmp/binlog.000076 /tmp/binlog.000077 --start-position=277 --stop-datetime="23-05-03 13:56:29" | mysql

Smart memory estimation

对于繁忙的数据库,可能需要在 Prepare 阶段使用大量重做日志对数据文件进行崩溃恢复,如果使用默认的 128MB 缓冲池大小,则会花费很长时间。Percona XtraBackup 8.0.30-23 引入了智能内存估计(Smart Memory Estimation)功能提高 Prepare 阶段性能。

建议在备份阶段使用选项 --estimate-memory=ON 启用内存估计:

$ xtrabackup --backup --estimate-memory=ON --target-dir=/data/backup/

在 Prepare 阶段使用选项 --use-free-memory-pct=50 表示使用空闲内存的 50%:

$ xtrabackup --prepare --use-free-memory-pct=50 --target-dir=/data/backup/

优化后性能提升 10 倍,具体如下:

Time to run --prepare

上次编辑于:
贡献者: stonebox