如何使用XtraBackup 8.0搭建从库并注意哪些关键事项?
- 内容介绍
- 文章标签
- 相关推荐
本文共计4854个文字,预计阅读时间需要20分钟。
构建数据库备份,本质上需要的只是一个一致性备份集及该备份集对应的点位信息。在此之前,介绍几个常用的备份工具(以MySQL为例),如何选择合适的备份策略和工具以满足需求。以下,我们重点探讨。
搭建从库,本质上需要的只是一个一致性备份集及这个备份集对应的位置点信息。之前介绍的几个备份工具(MySQL中如何选择合适的备份策略和备份工具)均可满足。
这里,我们重点看看如何基于 XtraBackup 搭建从库。
整个过程其实比较简单,无非是备份还原。唯一需要注意的是建立复制时位置点的选择,包括:
- 在基于位置点的复制中,CHANGE MASTER TO 语句中 MASTER_LOG_FILE 和 MASTER_LOG_POS 的选择。
- 在 GTID 复制中,在执行 CHANGE MASTER TO 命令之前,必须首先设置 GTID_PURGED。
尤其是在 MySQL 8.0 中,得益于 performance_schema.log_status 的引入( 注意,不是备份锁 ),XtraBackup 8.0 在备份的过程中不再加全局读锁。
而备份集对应的位置点信息,是 XtraBackup 8.0 在备份结束时查询 performance_schema.log_status 获取的,包括 GTID 和 Binlog 的位置点。
理论上,备份集里保存的 GTID 和 Binlog 位置点,指向的应该是同一个事务。
但在 XtraBackup 8.0 中,却并非如此。
由此带来的问题是,在 GTID 复制中,如果我们还是按照 MySQL 5.6,5.7( 对应 XtraBackup 2.4 )中的方法来搭建从库,大概率会导致主从数据不一致,甚至主从复制中断。
So,在 XtraBackup 8.0 中,我们又该如何搭建从库呢?
本文主要包括以下几部分:
- 使用 XtraBackup 搭建从库的一般步骤。
- 基于从库备份搭建从库时的注意事项。
- GTID 复制中,为什么需要设置 GTID_PURGED?
- 设置 GTID_PURGED 时的注意事项。
- 使用 XtraBackup 8.0 搭建从库时的注意事项。
- performance_schema.log_status 的作用。
- XtraBackup 8.0 中哪些场景会加全局读锁?
以下是测试环境信息。
下面我们看看具体的搭建步骤。
1. 主库上创建复制账号
mysql>createuser'repl'@'%'identifiedby'repl123';
QueryOK,0rowsaffected(0.01sec)
mysql>grantreplicationslaveon*.*TO'repl'@'%';
QueryOK,0rowsaffected(0.00sec)
2. 对主库进行备份
在 10.0.0.118 上执行备份命令。
#xtrabackup--user=backup_user--password=backup_pass--socket=/data/mysql/3306/data/mysql.sock--backup--parallel=10--slave-info--target-dir=/data/backup/full
3. 将备份文件传输到从库上
#scp-r/data/backup/full/*root@10.0.0.195:/data/backup/full
4. 从库上准备好 MySQL 安装包及参数文件
#tarxvfmysql-8.0.27-linux-glibc2.12-x86_64.tar.xz-C/usr/local/
#cd/usr/local/
#ln-smysql-8.0.27-linux-glibc2.12-x86_64mysql
5. 在从库上进行 Prepare 和恢复
#xtrabackup--prepare--target-dir=/data/backup/full
#xtrabackup--defaults-file=/etc/my.cnf--copy-back--parallel=10--target-dir=/data/backup/full
恢复命令中的 /etc/my.cnf 是从库的配置文件。
其中,第 2,3,5 步可以简化为下面这两条命令。
#xtrabackup\
--user=backup_user--password=backup_pass--socket=/data/mysql/3306/data/mysql.sock\
--backup--stream=xbstream--slave-info--parallel=10|lz4|\
sshmysql@10.0.0.195'cat-|lz4-d|xbstream-p10-x-C/data/mysql/3306/data/'
#xtrabackup--prepare--target-dir=/data/mysql/3306/data/
第一条命令是线上搭建从库时的一条常用命令,它将流式备份、管道结合在一起,具有以下优点:
- 边备份,边解压。相对于备份、传输、再解压,花费的时间更短。
- 备份集是直接解压到从库服务器,并不会保存到本地。这样,对于主库服务器,一可减少磁盘空间,二可减小磁盘 IO 压力。
- /data/mysql/3306/data/ 是从库的数据目录,在恢复时,无需 --copy-back,直接 Prepare 即可。
6. 启动实例
#chown-Rmysql.mysql/data/mysql/3306/data/
#/usr/local/mysql/bin/mysqld_safe--defaults-file=/etc/my.cnf&
很多人有个误区,认为搭建从库,需要提前创建个空白实例。对于逻辑备份确实如此,但对于物理备份,则无此必要,直接使用 mysqld_safe 启动还原后的备份文件即可。
7. 建立复制
这里需要区分两种场景:GTID 复制和基于位置点的复制。
首先查看备份集中的xtrabackup_binlog_info 文件的内容。
#catxtrabackup_binlog_info
mysql-bin.0000028828800682cbdc21a-db11-11ec-83bf-020017003dc4:1-223148
如果 xtrabackup_binlog_info 中存在 GTID 信息,则代表备份实例开启了 GTID,这个时候就需要建立 GTID 复制。
7.1 GTID 复制
对于 GTID 复制,在建立复制前,必须首先设置 GTID_PURGED。
设置 GTID_PURGED 时,注意备份实例的版本。
MySQL 5.7
在 MySQL 5.7 中,因为引入了 mysql.gtid_executed。
从库实例启动后,会基于该表的值来初始化 GTID_EXECUTED 和 GTID_PURGED。
mysql>select*frommysql.gtid_executed;
+--------------------------------------+----------------+--------------+
|source_uuid|interval_start|interval_end|
+--------------------------------------+----------------+--------------+
|2cbdc21a-db11-11ec-83bf-020017003dc4|1|2124|
+--------------------------------------+----------------+--------------+
1rowinset(0.00sec)
mysql>showglobalvariableswherevariable_namein('gtid_executed','gtid_purged');
+---------------+---------------------------------------------+
|Variable_name|Value|
+---------------+---------------------------------------------+
|gtid_executed|2cbdc21a-db11-11ec-83bf-020017003dc4:1-2124|
|gtid_purged|2cbdc21a-db11-11ec-83bf-020017003dc4:1-2124|
+---------------+---------------------------------------------+
2rowsinset(0.00sec)
但很明显,GTID_PURGED 与 xtrabackup_binlog_info 中的 GTID 信息相差甚远。
关于这一点,不难理解,因为主库的 mysql.gtid_executed,在 MySQL 8.0.17 之前,只有在日志切换和实例关闭时更新。
下面我们基于 xtrabackup_binlog_info 中的 GTID 信息重新设置 GTID_PURGED。
mysql>resetmaster;
QueryOK,0rowsaffected(0.00sec)
mysql>setglobalgtid_purged='2cbdc21a-db11-11ec-83bf-020017003dc4:1-223148';
QueryOK,0rowsaffected(0.01sec)
因为 GTID_EXECUTED 有值,所以在设置 GTID_PURGED 之前,必须首先通过 RESET MASTER 命令清空 GTID_EXECUTED。
MySQL 5.6
可直接基于 xtrabackup_binlog_info 中的 GTID 信息设置 GTID_PURGED。
mysql>setglobalgtid_purged='2cbdc21a-db11-11ec-83bf-020017003dc4:1-223148';
为什么在 MySQL 5.6 中无需执行 RESET MASTER 呢?
因为 MySQL 5.6 中还没有引入 mysql.gtid_executed,实例恢复后,GTID_EXECUTED 和 GTID_PURGED 均为空。
MySQL 8.0
在 MySQL 8.0 中,无需设置 GTID_PURGED。
至于为什么不用设置,后面会有详细介绍。这里,大家记住这个结论就可以了。
设置完 GTID_PURGED,接下来执行 CHANGE MASTER TO 命令。
CHANGEMASTERTO
MASTER_HOST='10.0.0.118',
MASTER_USER='repl',
MASTER_PASSWORD='repl123',
MASTER_PORT=3306,
MASTER_AUTO_POSITION=1;
对于 GTID 复制,需将 MASTER_AUTO_POSITION 设置为 1。
在 MySQL 8.0 中,CHANGE MASTER TO 语句中还需添加 GET_MASTER_PUBLIC_KEY = 1。
7.2 基于位置点的复制
如果 xtrabackup_binlog_info 没有 GTID 信息,则代表备份实例没有开启 GTID,这个时候就无需设置 GTID_PURGED,直接执行 CHANGE MASTER TO 命令即可。
CHANGEMASTERTO
MASTER_HOST='10.0.0.118',
MASTER_USER='repl',
MASTER_PASSWORD='repl123',
MASTER_PORT=3306,
MASTER_LOG_FILE='mysql-bin.000002',
MASTER_LOG_POS=882880068;
CHANGE MASTER TO 语句中的 MASTER_LOG_FILE 和 MASTER_LOG_POS 的值分别取自 xtrabackup_binlog_info 中的 filename 和 position。
8. 开启复制
mysql>startslave;
9. 检查主从复制是否正常
mysql>showslavestatus\G
Slave_IO_Running 和 Slave_SQL_Running 均为 Yes 代表复制正常。
以上就是使用 XtraBackup 搭建从库的基本步骤。
基于从库备份搭建从库时的注意事项不过在线上,我们很少会对主库进行备份,一般是备份从库。所以,基于从库的备份来搭建一个新的从库是一个更为常见的场景。
对于这种场景,上面的搭建步骤同样适用,不过有以下几点需要注意:
1. 对从库进行备份,需指定 --slave-info。这个时候备份集中会生成一个 xtrabackup_slave_info 文件,该文件记录了备份时备份实例对应主库的一致性位置点信息,如,
#catxtrabackup_slave_info
CHANGEMASTERTOMASTER_LOG_FILE='mysql-bin.000004',MASTER_LOG_POS=6263314;
如果从库开启了 GTID,则只会记录 GTID 信息,如,
SETGLOBALgtid_purged='2cbdc21a-db11-11ec-83bf-020017003dc4:1-2049780';
CHANGEMASTERTOMASTER_AUTO_POSITION=1;
其实,对主库备份,也可指定 --slave-info,只不过此时的 xtrabackup_slave_info 内容为空。
所以,上面搭建步骤中的备份命令都带上了 --slave-info。
2. 在基于位置点的复制中,CHANGE MASTER TO 语句中的 MASTER_LOG_FILE 和 MASTER_LOG_POS 必须取自 xtrabackup_slave_info,而不是 xtrabackup_binlog_info。
对于 GTID 复制,则没关系,因为 xtrabackup_slave_info 和 xtrabackup_binlog_info 中的 GTID 信息是一致的。
3. 只要是基于从库的备份来搭建从库,在执行 CHANGE MASTER TO 之前,都必须首先执行 RESET SLAVE ALL 清空 mysql.slave_master_info 和 mysql.slave_relay_log_info 表中的内容。
设置 GTID_PURGED 时的注意事项在 GTID 复制中,为什么需要设置 GTID_PURGED 呢?
实际上,设置 GTID_PURGED 只是手段,最终目的还是为了设置 GTID_EXECUTED。
GTID_EXECUTED
GTID_EXECUTED 代表了实例中已经执行过的 GTID 集。在建立复制后,从库会自动跳过 GTID_EXECUTED 相关的事务。如果这个值设置不准确,会导致事务丢失,或者已经重放过的操作重复执行。
但 GTID_EXECUTED 是个只读参数,不能直接修改。
mysql>setglobalgtid_executed='411693c9-d512-11ec-9e11-525400d51a16:1-10369';
ERROR1238(HY000):Variable'gtid_executed'isareadonlyvariable
如果我们要修改它,必须通过修改 GTID_PURGED 来间接修改它。
GTID_PURGED
GTID_PURGED 代表了实例中已经执行过,但 Binlog 中不存在的 GTID 集。所以GTID_PURGED 一定是GTID_EXECUTED 的子集。
在 MySQL 8.0 之前,如果要修改 GTID_PURGED,GTID_EXECUTED 必须为空。
mysql>setglobalgtid_purged='411693c9-d512-11ec-9e11-525400d51a16:1-10369';
ERROR1840(HY000):@@GLOBAL.GTID_PURGEDcanonlybesetwhen@@GLOBAL.GTID_EXECUTEDisempty.
而要 GTID_EXECUTED 为空,只能执行 RESET MASTER 操作。
mysql>resetmaster;
QueryOK,0rowsaffected(0.02sec)
mysql>showglobalvariableswherevariable_namein('gtid_executed','gtid_purged');
+---------------+-------+
|Variable_name|Value|
+---------------+-------+
|gtid_executed||
|gtid_purged||
+---------------+-------+
2rowsinset(0.00sec)
mysql>setglobalgtid_purged='411693c9-d512-11ec-9e11-525400d51a16:1-10369';
QueryOK,0rowsaffected(0.00sec)
mysql>showglobalvariableswherevariable_namein('gtid_executed','gtid_purged');
+---------------+----------------------------------------------+
|Variable_name|Value|
+---------------+----------------------------------------------+
|gtid_executed|411693c9-d512-11ec-9e11-525400d51a16:1-10369|
|gtid_purged|411693c9-d512-11ec-9e11-525400d51a16:1-10369|
+---------------+----------------------------------------------+
2rowsinset(0.00sec)
可以看到,调整完 GTID_PURGED 后,GTID_EXECUTED 也随之更改。
在 MySQL 8.0 中,则剔除了这一限制,即设置 GTID_PURGED 时,无需 GTID_EXECUTED 为空。但也不能随便设置,设置时需满足以下要求:
1. 设置的 GTID_PURGED 不能与 gtid_subtract(@@gtid_executed, @@gtid_purged) 存在交集。
看下面这个示例。
mysql>showglobalvariableswherevariable_namein('gtid_executed','gtid_purged');
+---------------+------------------------------------------+
|Variable_name|Value|
+---------------+------------------------------------------+
|gtid_executed|a028d418-ccce-11ec-bf07-525400d51a16:1-8|
|gtid_purged|a028d418-ccce-11ec-bf07-525400d51a16:1-4|
+---------------+------------------------------------------+
2rowsinset(0.00sec)
mysql>selectgtid_subtract(@@gtid_executed,@@gtid_purged);
+-----------------------------------------------+
|gtid_subtract(@@gtid_executed,@@gtid_purged)|
+-----------------------------------------------+
|a028d418-ccce-11ec-bf07-525400d51a16:5-8|
+-----------------------------------------------+
1rowinset(0.00sec)
mysql>setglobalgtid_purged='a028d418-ccce-11ec-bf07-525400d51a16:1-5';
ERROR3546(HY000):@@GLOBAL.GTID_PURGEDcannotbechanged:theaddedgtidsetmustnotoverlapwith@@GLOBAL.GTID_EXECUTED
2. 设置的 GTID_PURGED 必须是当前 GTID_PURGED 的超集。
mysql>showglobalvariableswherevariable_namein('gtid_executed','gtid_purged');
+---------------+------------------------------------------+
|Variable_name|Value|
+---------------+------------------------------------------+
|gtid_executed|a028d418-ccce-11ec-bf07-525400d51a16:1-8|
|gtid_purged|a028d418-ccce-11ec-bf07-525400d51a16:1-4|
+---------------+------------------------------------------+
2rowsinset(0.00sec)
mysql>setglobalgtid_purged='a028d418-ccce-11ec-bf07-525400d51a16:1-3';
ERROR3546(HY000):@@GLOBAL.GTID_PURGEDcannotbechanged:thenewvaluemustbeasupersetoftheoldvalue
mysql>setglobalgtid_purged='a028d418-ccce-11ec-bf07-525400d51a16:1-4,9b481834-de85-11ec-9045-020017003dc4:1-10';
QueryOK,0rowsaffected(0.01sec)
mysql>showglobalvariableswherevariable_namein('gtid_executed','gtid_purged')\G
***************************1.row***************************
Variable_name:gtid_executed
Value:9b481834-de85-11ec-9045-020017003dc4:1-10,
a028d418-ccce-11ec-bf07-525400d51a16:1-8
***************************2.row***************************
Variable_name:gtid_purged
Value:9b481834-de85-11ec-9045-020017003dc4:1-10,
a028d418-ccce-11ec-bf07-525400d51a16:1-4
2rowsinset(0.00sec)
可以看到,新添加的 GTID 集同样也添加到 GTID_EXECUTED 中了。
除了直接指定,在 MySQL 8.0 中还支持通过 + 号添加新的 GTID 集。如,
mysql>setglobalgtid_purged='+9b481834-de85-11ec-9045-020017003dc4:1-10';
使用 XtraBackup 8.0 搭建从库时的注意事项
QueryOK,0rowsaffected(0.01sec)
XtraBackup 8.0 中没有加全局读锁,备份结束时的位置点信息查询的是 performance_schema.log_status。
该表的内容如下,
mysql>select*fromperformance_schema.log_status\G
***************************1.row***************************
SERVER_UUID:d310871c-db0c-11ec-a557-020017003dc4
LOCAL:{"gtid_executed":"d310871c-db0c-11ec-a557-020017003dc4:1-352559","binary_log_file":"mysql-bin.000022","binary_log_position":9698237}
REPLICATION:{"channels":[]}
STORAGE_ENGINES:{"InnoDB":{"LSN":912297234,"LSN_checkpoint":912297234}}
1rowinset(0.00sec)
需要注意的是,LOCAL 中的 gtid_executed 和 binary_log_file + binary_log_position 对应的并不总是同一个事务。
这一点很容易模拟出来,对一张表持续进行插入操作即可。
下面我们看一个具体的案例。
备份过程中,持续对一张表进行插入操作。最后备份集中 xtrabackup_binlog_info 的内容如下。
#catxtrabackup_binlog_info
mysql-bin.000024507d310871c-db0c-11ec-a557-020017003dc4:1-388482
接下来我们基于 Binlog 的位置点信息 "mysql-bin.000024 507" 查找对应的事务。
#mysqlbinlog-v--base64-output=decode-rows--stop-position=507mysql-bin.000024
#Thepropertermispseudo_replica_mode,butweusethiscompatibilityalias
#tomakethestatementusableonserverversions8.0.24andolder.
/*!50530SET@@SESSION.PSEUDO_SLAVE_MODE=1*/;
/*!50003SET@OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/;
DELIMITER/*!*/;
#at4
#22052911:19:07serverid1end_log_pos126CRC320xdcc54ec7Start:binlogv4,serverv8.0.28created22052911:19:07
#at126
#22052911:19:07serverid1end_log_pos197CRC320x5d440f7cPrevious-GTIDs
#d310871c-db0c-11ec-a557-020017003dc4:1-388482
#at197
#22052911:19:07serverid1end_log_pos276CRC320x0dd893b5GTIDlast_committed=0sequence_number=1rbr_only=yesoriginal_committed_timestamp=1653823147539722immediate_commit_timestamp=1653823147539722transaction_length=310
/*!50718SETTRANSACTIONISOLATIONLEVELREADCOMMITTED*//*!*/;
#original_commit_timestamp=1653823147539722(2022-05-2911:19:07.539722GMT)
#immediate_commit_timestamp=1653823147539722(2022-05-2911:19:07.539722GMT)
/*!80001SET@@session.original_commit_timestamp=1653823147539722*//*!*/;
/*!80014SET@@session.original_server_version=80028*//*!*/;
/*!80014SET@@session.immediate_server_version=80028*//*!*/;
SET@@SESSION.GTID_NEXT='d310871c-db0c-11ec-a557-020017003dc4:388483'/*!*/;
#at276
#22052911:19:07serverid1end_log_pos365CRC320xa49dc290Querythread_id=262exec_time=0error_code=0
...
BEGIN
/*!*/;
#at365
#22052911:19:07serverid1end_log_pos425CRC320x824f6309Table_map:`slowtech`.`t1`mappedtonumber157
#at425
#22052911:19:07serverid1end_log_pos476CRC320x5a6fe6ecWrite_rows:tableid157flags:STMT_END_F
###INSERTINTO`slowtech`.`t1`
###SET
###@1=1483132
###@2='aaaaaaaaaa'
#at476
#22052911:19:07serverid1end_log_pos507CRC320x66a401f6Xid=4108904
COMMIT/*!*/;
SET@@SESSION.GTID_NEXT='AUTOMATIC'/*addedbymysqlbinlog*//*!*/;
DELIMITER;
#Endoflogfile
/*!50003SETCOMPLETION_TYPE=@OLD_COMPLETION_TYPE*/;
/*!50530SET@@SESSION.PSEUDO_SLAVE_MODE=0*/;
可以看到,该事务对应的 GTID 是 d310871c-db0c-11ec-a557-020017003dc4:388483,不是 xtrabackup_binlog_info 中的 388482。
如果我们像在 MySQL 5.6,5.7 中那样,基于 xtrabackup_binlog_info 中的 GTID 信息来设置 GTID_PURGED,在我们这个 case 中,会导致同一个 INSERT 操作执行两次,进而会出现主键冲突,主从复制中断。
如此来看,问题的根源还是出在 performance_schema.log_status 中的 gtid_executed 和 binary_log_file + binary_log_position 指向的不是同一个事务。
这是一个 Bug 吗?其实不然。
XtraBackup 8.0 在查询完 performance_schema.log_status 后,会基于查询到的 binary_log_file 和 binary_log_position 拷贝对应的 Binlog 。
下面是备份集中拷贝的 Binlog。
#ll/data/backup/full/
...
-rw-r-----.1rootroot507May2911:19mysql-bin.000024
-rw-r-----.1rootroot19May2911:19mysql-bin.index
...
Binlog 中记录了 "mysql-bin.000024 507" 这个位置点的事务所对应的 GTID 值。
实例启动时,会自动基于 Binlog 中的 GTID 信息来初始化 GTID_EXECUTED 和 GTID_PURGED。
mysql>showglobalvariableswherevariable_namein('gtid_executed','gtid_purged');
+---------------+-----------------------------------------------+
|Variable_name|Value|
+---------------+-----------------------------------------------+
|gtid_executed|d310871c-db0c-11ec-a557-020017003dc4:1-388483|
|gtid_purged|d310871c-db0c-11ec-a557-020017003dc4:1-388482|
+---------------+-----------------------------------------------+
2rowsinset(0.00sec)
所以,实例起来后,我们看到的 GTID_EXECUTED 就已经是正确值,就已经能正确反映备份结束时的一致性位置点信息了。
这个时候,直接执行 CHANGE MASTER TO 操作就可以了。
performance_schema.log_status 的作用关于 performance_schema.log_status 的作用,其实官方文档中也提到了,是提供位置点信息,供备份工具拷贝所需的 Binlog。查询的过程中也会阻塞日志和相关管理操作。不过阻塞的时间很短,填充完表中的数据就会释放资源。
Thelog_statustableprovidesinformationthatenablesanonlinebackuptooltocopytherequiredlogfileswithoutlockingthoseresourcesforthedurationofthecopyprocess.
XtraBackup 8.0 中哪些场景会加全局读锁
Whenthelog_statustableisqueried,theserverblocksloggingandrelatedadministrativechangesforjustlongenoughtopopulatethetable,thenreleasestheresources.
Thelog_statustableinformstheonlinebackupwhichpointitshouldcopyuptointhesource'sbinarylogandgtid_executedrecord,andtherelaylogforeachreplicationchannel.
Italsoprovidesrelevantinformationforindividualstorageengines,suchasthelastlogsequencenumber(LSN)andtheLSNofthelastcheckpointtakenfortheInnoDBstorageengine.
下面两种场景,XtraBackup 8.0 会加全局读锁:
-
备份实例中存在 MyISAM 表。
-
备份从库,且命令行中指定了 --slave-info,且从库 SHOW SLAVE STATUS 中的 Auto_Position 不为 1。
Auto_Position 不为 1 意味着从库没有开启 GTID 复制,或者开启了 GTID 复制,但未将 MASTER_AUTO_POSITION 设置为 1。
1. 备份锁引入的初衷是为了阻塞备份过程中的 DDL,不是为了替代全局读锁。在 XtraBackup 8.0 中,我们可以指定 --skip-lock-ddl 禁用备份锁,这并不影响 XtraBackup 的正常使用。
2. 基于物理备份搭建从库时,无需提前创建空白实例。
3. 在基于位置点的复制中,注意 CHANGE MASTER TO 语句中 MASTER_LOG_FILE 和 MASTER_LOG_POS 的选择。
以一个简单的主从复制拓扑为例:master -> slave1。
- 如果是基于 master 的备份添加一个 master 的从库,或者,基于 slave1 的备份添加一个 slave1 的从库。建立复制时,应使用 xtrabackup_binlog_info 的位置点信息。
- 如果是基于 slave1 的备份添加 master 的一个从库,应使用 xtrabackup_slave_info 的位置点信息。
4. 基于从库的备份搭建从库时,在执行 CHANGE MASTER TO 操作之前,必须首先执行 RESET SLAVE ALL。
5. 无论是对主库还是从库进行备份,都可指定 --slave-info,此时都会生成 xtrabackup_slave_info。只不过如果是对主库进行备份,该文件会为空。
6. 在 GTID 复制中,设置 GTID_PURGED 时,注意备份实例的版本。如果是 MySQL 5.6,5.7,可直接基于 xtrabackup_binlog_info 中的 GTID 信息设置 GTID_PURGED。如果是 MySQL 8.0,无需再设置 GTID_PURGED。
参考[1] LOCK INSTANCE FOR BACKUP and UNLOCK INSTANCE Statements
[2] The log_status Table
[3]log_status has wrong binary_log_position of gtid_executed
本文共计4854个文字,预计阅读时间需要20分钟。
构建数据库备份,本质上需要的只是一个一致性备份集及该备份集对应的点位信息。在此之前,介绍几个常用的备份工具(以MySQL为例),如何选择合适的备份策略和工具以满足需求。以下,我们重点探讨。
搭建从库,本质上需要的只是一个一致性备份集及这个备份集对应的位置点信息。之前介绍的几个备份工具(MySQL中如何选择合适的备份策略和备份工具)均可满足。
这里,我们重点看看如何基于 XtraBackup 搭建从库。
整个过程其实比较简单,无非是备份还原。唯一需要注意的是建立复制时位置点的选择,包括:
- 在基于位置点的复制中,CHANGE MASTER TO 语句中 MASTER_LOG_FILE 和 MASTER_LOG_POS 的选择。
- 在 GTID 复制中,在执行 CHANGE MASTER TO 命令之前,必须首先设置 GTID_PURGED。
尤其是在 MySQL 8.0 中,得益于 performance_schema.log_status 的引入( 注意,不是备份锁 ),XtraBackup 8.0 在备份的过程中不再加全局读锁。
而备份集对应的位置点信息,是 XtraBackup 8.0 在备份结束时查询 performance_schema.log_status 获取的,包括 GTID 和 Binlog 的位置点。
理论上,备份集里保存的 GTID 和 Binlog 位置点,指向的应该是同一个事务。
但在 XtraBackup 8.0 中,却并非如此。
由此带来的问题是,在 GTID 复制中,如果我们还是按照 MySQL 5.6,5.7( 对应 XtraBackup 2.4 )中的方法来搭建从库,大概率会导致主从数据不一致,甚至主从复制中断。
So,在 XtraBackup 8.0 中,我们又该如何搭建从库呢?
本文主要包括以下几部分:
- 使用 XtraBackup 搭建从库的一般步骤。
- 基于从库备份搭建从库时的注意事项。
- GTID 复制中,为什么需要设置 GTID_PURGED?
- 设置 GTID_PURGED 时的注意事项。
- 使用 XtraBackup 8.0 搭建从库时的注意事项。
- performance_schema.log_status 的作用。
- XtraBackup 8.0 中哪些场景会加全局读锁?
以下是测试环境信息。
下面我们看看具体的搭建步骤。
1. 主库上创建复制账号
mysql>createuser'repl'@'%'identifiedby'repl123';
QueryOK,0rowsaffected(0.01sec)
mysql>grantreplicationslaveon*.*TO'repl'@'%';
QueryOK,0rowsaffected(0.00sec)
2. 对主库进行备份
在 10.0.0.118 上执行备份命令。
#xtrabackup--user=backup_user--password=backup_pass--socket=/data/mysql/3306/data/mysql.sock--backup--parallel=10--slave-info--target-dir=/data/backup/full
3. 将备份文件传输到从库上
#scp-r/data/backup/full/*root@10.0.0.195:/data/backup/full
4. 从库上准备好 MySQL 安装包及参数文件
#tarxvfmysql-8.0.27-linux-glibc2.12-x86_64.tar.xz-C/usr/local/
#cd/usr/local/
#ln-smysql-8.0.27-linux-glibc2.12-x86_64mysql
5. 在从库上进行 Prepare 和恢复
#xtrabackup--prepare--target-dir=/data/backup/full
#xtrabackup--defaults-file=/etc/my.cnf--copy-back--parallel=10--target-dir=/data/backup/full
恢复命令中的 /etc/my.cnf 是从库的配置文件。
其中,第 2,3,5 步可以简化为下面这两条命令。
#xtrabackup\
--user=backup_user--password=backup_pass--socket=/data/mysql/3306/data/mysql.sock\
--backup--stream=xbstream--slave-info--parallel=10|lz4|\
sshmysql@10.0.0.195'cat-|lz4-d|xbstream-p10-x-C/data/mysql/3306/data/'
#xtrabackup--prepare--target-dir=/data/mysql/3306/data/
第一条命令是线上搭建从库时的一条常用命令,它将流式备份、管道结合在一起,具有以下优点:
- 边备份,边解压。相对于备份、传输、再解压,花费的时间更短。
- 备份集是直接解压到从库服务器,并不会保存到本地。这样,对于主库服务器,一可减少磁盘空间,二可减小磁盘 IO 压力。
- /data/mysql/3306/data/ 是从库的数据目录,在恢复时,无需 --copy-back,直接 Prepare 即可。
6. 启动实例
#chown-Rmysql.mysql/data/mysql/3306/data/
#/usr/local/mysql/bin/mysqld_safe--defaults-file=/etc/my.cnf&
很多人有个误区,认为搭建从库,需要提前创建个空白实例。对于逻辑备份确实如此,但对于物理备份,则无此必要,直接使用 mysqld_safe 启动还原后的备份文件即可。
7. 建立复制
这里需要区分两种场景:GTID 复制和基于位置点的复制。
首先查看备份集中的xtrabackup_binlog_info 文件的内容。
#catxtrabackup_binlog_info
mysql-bin.0000028828800682cbdc21a-db11-11ec-83bf-020017003dc4:1-223148
如果 xtrabackup_binlog_info 中存在 GTID 信息,则代表备份实例开启了 GTID,这个时候就需要建立 GTID 复制。
7.1 GTID 复制
对于 GTID 复制,在建立复制前,必须首先设置 GTID_PURGED。
设置 GTID_PURGED 时,注意备份实例的版本。
MySQL 5.7
在 MySQL 5.7 中,因为引入了 mysql.gtid_executed。
从库实例启动后,会基于该表的值来初始化 GTID_EXECUTED 和 GTID_PURGED。
mysql>select*frommysql.gtid_executed;
+--------------------------------------+----------------+--------------+
|source_uuid|interval_start|interval_end|
+--------------------------------------+----------------+--------------+
|2cbdc21a-db11-11ec-83bf-020017003dc4|1|2124|
+--------------------------------------+----------------+--------------+
1rowinset(0.00sec)
mysql>showglobalvariableswherevariable_namein('gtid_executed','gtid_purged');
+---------------+---------------------------------------------+
|Variable_name|Value|
+---------------+---------------------------------------------+
|gtid_executed|2cbdc21a-db11-11ec-83bf-020017003dc4:1-2124|
|gtid_purged|2cbdc21a-db11-11ec-83bf-020017003dc4:1-2124|
+---------------+---------------------------------------------+
2rowsinset(0.00sec)
但很明显,GTID_PURGED 与 xtrabackup_binlog_info 中的 GTID 信息相差甚远。
关于这一点,不难理解,因为主库的 mysql.gtid_executed,在 MySQL 8.0.17 之前,只有在日志切换和实例关闭时更新。
下面我们基于 xtrabackup_binlog_info 中的 GTID 信息重新设置 GTID_PURGED。
mysql>resetmaster;
QueryOK,0rowsaffected(0.00sec)
mysql>setglobalgtid_purged='2cbdc21a-db11-11ec-83bf-020017003dc4:1-223148';
QueryOK,0rowsaffected(0.01sec)
因为 GTID_EXECUTED 有值,所以在设置 GTID_PURGED 之前,必须首先通过 RESET MASTER 命令清空 GTID_EXECUTED。
MySQL 5.6
可直接基于 xtrabackup_binlog_info 中的 GTID 信息设置 GTID_PURGED。
mysql>setglobalgtid_purged='2cbdc21a-db11-11ec-83bf-020017003dc4:1-223148';
为什么在 MySQL 5.6 中无需执行 RESET MASTER 呢?
因为 MySQL 5.6 中还没有引入 mysql.gtid_executed,实例恢复后,GTID_EXECUTED 和 GTID_PURGED 均为空。
MySQL 8.0
在 MySQL 8.0 中,无需设置 GTID_PURGED。
至于为什么不用设置,后面会有详细介绍。这里,大家记住这个结论就可以了。
设置完 GTID_PURGED,接下来执行 CHANGE MASTER TO 命令。
CHANGEMASTERTO
MASTER_HOST='10.0.0.118',
MASTER_USER='repl',
MASTER_PASSWORD='repl123',
MASTER_PORT=3306,
MASTER_AUTO_POSITION=1;
对于 GTID 复制,需将 MASTER_AUTO_POSITION 设置为 1。
在 MySQL 8.0 中,CHANGE MASTER TO 语句中还需添加 GET_MASTER_PUBLIC_KEY = 1。
7.2 基于位置点的复制
如果 xtrabackup_binlog_info 没有 GTID 信息,则代表备份实例没有开启 GTID,这个时候就无需设置 GTID_PURGED,直接执行 CHANGE MASTER TO 命令即可。
CHANGEMASTERTO
MASTER_HOST='10.0.0.118',
MASTER_USER='repl',
MASTER_PASSWORD='repl123',
MASTER_PORT=3306,
MASTER_LOG_FILE='mysql-bin.000002',
MASTER_LOG_POS=882880068;
CHANGE MASTER TO 语句中的 MASTER_LOG_FILE 和 MASTER_LOG_POS 的值分别取自 xtrabackup_binlog_info 中的 filename 和 position。
8. 开启复制
mysql>startslave;
9. 检查主从复制是否正常
mysql>showslavestatus\G
Slave_IO_Running 和 Slave_SQL_Running 均为 Yes 代表复制正常。
以上就是使用 XtraBackup 搭建从库的基本步骤。
基于从库备份搭建从库时的注意事项不过在线上,我们很少会对主库进行备份,一般是备份从库。所以,基于从库的备份来搭建一个新的从库是一个更为常见的场景。
对于这种场景,上面的搭建步骤同样适用,不过有以下几点需要注意:
1. 对从库进行备份,需指定 --slave-info。这个时候备份集中会生成一个 xtrabackup_slave_info 文件,该文件记录了备份时备份实例对应主库的一致性位置点信息,如,
#catxtrabackup_slave_info
CHANGEMASTERTOMASTER_LOG_FILE='mysql-bin.000004',MASTER_LOG_POS=6263314;
如果从库开启了 GTID,则只会记录 GTID 信息,如,
SETGLOBALgtid_purged='2cbdc21a-db11-11ec-83bf-020017003dc4:1-2049780';
CHANGEMASTERTOMASTER_AUTO_POSITION=1;
其实,对主库备份,也可指定 --slave-info,只不过此时的 xtrabackup_slave_info 内容为空。
所以,上面搭建步骤中的备份命令都带上了 --slave-info。
2. 在基于位置点的复制中,CHANGE MASTER TO 语句中的 MASTER_LOG_FILE 和 MASTER_LOG_POS 必须取自 xtrabackup_slave_info,而不是 xtrabackup_binlog_info。
对于 GTID 复制,则没关系,因为 xtrabackup_slave_info 和 xtrabackup_binlog_info 中的 GTID 信息是一致的。
3. 只要是基于从库的备份来搭建从库,在执行 CHANGE MASTER TO 之前,都必须首先执行 RESET SLAVE ALL 清空 mysql.slave_master_info 和 mysql.slave_relay_log_info 表中的内容。
设置 GTID_PURGED 时的注意事项在 GTID 复制中,为什么需要设置 GTID_PURGED 呢?
实际上,设置 GTID_PURGED 只是手段,最终目的还是为了设置 GTID_EXECUTED。
GTID_EXECUTED
GTID_EXECUTED 代表了实例中已经执行过的 GTID 集。在建立复制后,从库会自动跳过 GTID_EXECUTED 相关的事务。如果这个值设置不准确,会导致事务丢失,或者已经重放过的操作重复执行。
但 GTID_EXECUTED 是个只读参数,不能直接修改。
mysql>setglobalgtid_executed='411693c9-d512-11ec-9e11-525400d51a16:1-10369';
ERROR1238(HY000):Variable'gtid_executed'isareadonlyvariable
如果我们要修改它,必须通过修改 GTID_PURGED 来间接修改它。
GTID_PURGED
GTID_PURGED 代表了实例中已经执行过,但 Binlog 中不存在的 GTID 集。所以GTID_PURGED 一定是GTID_EXECUTED 的子集。
在 MySQL 8.0 之前,如果要修改 GTID_PURGED,GTID_EXECUTED 必须为空。
mysql>setglobalgtid_purged='411693c9-d512-11ec-9e11-525400d51a16:1-10369';
ERROR1840(HY000):@@GLOBAL.GTID_PURGEDcanonlybesetwhen@@GLOBAL.GTID_EXECUTEDisempty.
而要 GTID_EXECUTED 为空,只能执行 RESET MASTER 操作。
mysql>resetmaster;
QueryOK,0rowsaffected(0.02sec)
mysql>showglobalvariableswherevariable_namein('gtid_executed','gtid_purged');
+---------------+-------+
|Variable_name|Value|
+---------------+-------+
|gtid_executed||
|gtid_purged||
+---------------+-------+
2rowsinset(0.00sec)
mysql>setglobalgtid_purged='411693c9-d512-11ec-9e11-525400d51a16:1-10369';
QueryOK,0rowsaffected(0.00sec)
mysql>showglobalvariableswherevariable_namein('gtid_executed','gtid_purged');
+---------------+----------------------------------------------+
|Variable_name|Value|
+---------------+----------------------------------------------+
|gtid_executed|411693c9-d512-11ec-9e11-525400d51a16:1-10369|
|gtid_purged|411693c9-d512-11ec-9e11-525400d51a16:1-10369|
+---------------+----------------------------------------------+
2rowsinset(0.00sec)
可以看到,调整完 GTID_PURGED 后,GTID_EXECUTED 也随之更改。
在 MySQL 8.0 中,则剔除了这一限制,即设置 GTID_PURGED 时,无需 GTID_EXECUTED 为空。但也不能随便设置,设置时需满足以下要求:
1. 设置的 GTID_PURGED 不能与 gtid_subtract(@@gtid_executed, @@gtid_purged) 存在交集。
看下面这个示例。
mysql>showglobalvariableswherevariable_namein('gtid_executed','gtid_purged');
+---------------+------------------------------------------+
|Variable_name|Value|
+---------------+------------------------------------------+
|gtid_executed|a028d418-ccce-11ec-bf07-525400d51a16:1-8|
|gtid_purged|a028d418-ccce-11ec-bf07-525400d51a16:1-4|
+---------------+------------------------------------------+
2rowsinset(0.00sec)
mysql>selectgtid_subtract(@@gtid_executed,@@gtid_purged);
+-----------------------------------------------+
|gtid_subtract(@@gtid_executed,@@gtid_purged)|
+-----------------------------------------------+
|a028d418-ccce-11ec-bf07-525400d51a16:5-8|
+-----------------------------------------------+
1rowinset(0.00sec)
mysql>setglobalgtid_purged='a028d418-ccce-11ec-bf07-525400d51a16:1-5';
ERROR3546(HY000):@@GLOBAL.GTID_PURGEDcannotbechanged:theaddedgtidsetmustnotoverlapwith@@GLOBAL.GTID_EXECUTED
2. 设置的 GTID_PURGED 必须是当前 GTID_PURGED 的超集。
mysql>showglobalvariableswherevariable_namein('gtid_executed','gtid_purged');
+---------------+------------------------------------------+
|Variable_name|Value|
+---------------+------------------------------------------+
|gtid_executed|a028d418-ccce-11ec-bf07-525400d51a16:1-8|
|gtid_purged|a028d418-ccce-11ec-bf07-525400d51a16:1-4|
+---------------+------------------------------------------+
2rowsinset(0.00sec)
mysql>setglobalgtid_purged='a028d418-ccce-11ec-bf07-525400d51a16:1-3';
ERROR3546(HY000):@@GLOBAL.GTID_PURGEDcannotbechanged:thenewvaluemustbeasupersetoftheoldvalue
mysql>setglobalgtid_purged='a028d418-ccce-11ec-bf07-525400d51a16:1-4,9b481834-de85-11ec-9045-020017003dc4:1-10';
QueryOK,0rowsaffected(0.01sec)
mysql>showglobalvariableswherevariable_namein('gtid_executed','gtid_purged')\G
***************************1.row***************************
Variable_name:gtid_executed
Value:9b481834-de85-11ec-9045-020017003dc4:1-10,
a028d418-ccce-11ec-bf07-525400d51a16:1-8
***************************2.row***************************
Variable_name:gtid_purged
Value:9b481834-de85-11ec-9045-020017003dc4:1-10,
a028d418-ccce-11ec-bf07-525400d51a16:1-4
2rowsinset(0.00sec)
可以看到,新添加的 GTID 集同样也添加到 GTID_EXECUTED 中了。
除了直接指定,在 MySQL 8.0 中还支持通过 + 号添加新的 GTID 集。如,
mysql>setglobalgtid_purged='+9b481834-de85-11ec-9045-020017003dc4:1-10';
使用 XtraBackup 8.0 搭建从库时的注意事项
QueryOK,0rowsaffected(0.01sec)
XtraBackup 8.0 中没有加全局读锁,备份结束时的位置点信息查询的是 performance_schema.log_status。
该表的内容如下,
mysql>select*fromperformance_schema.log_status\G
***************************1.row***************************
SERVER_UUID:d310871c-db0c-11ec-a557-020017003dc4
LOCAL:{"gtid_executed":"d310871c-db0c-11ec-a557-020017003dc4:1-352559","binary_log_file":"mysql-bin.000022","binary_log_position":9698237}
REPLICATION:{"channels":[]}
STORAGE_ENGINES:{"InnoDB":{"LSN":912297234,"LSN_checkpoint":912297234}}
1rowinset(0.00sec)
需要注意的是,LOCAL 中的 gtid_executed 和 binary_log_file + binary_log_position 对应的并不总是同一个事务。
这一点很容易模拟出来,对一张表持续进行插入操作即可。
下面我们看一个具体的案例。
备份过程中,持续对一张表进行插入操作。最后备份集中 xtrabackup_binlog_info 的内容如下。
#catxtrabackup_binlog_info
mysql-bin.000024507d310871c-db0c-11ec-a557-020017003dc4:1-388482
接下来我们基于 Binlog 的位置点信息 "mysql-bin.000024 507" 查找对应的事务。
#mysqlbinlog-v--base64-output=decode-rows--stop-position=507mysql-bin.000024
#Thepropertermispseudo_replica_mode,butweusethiscompatibilityalias
#tomakethestatementusableonserverversions8.0.24andolder.
/*!50530SET@@SESSION.PSEUDO_SLAVE_MODE=1*/;
/*!50003SET@OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/;
DELIMITER/*!*/;
#at4
#22052911:19:07serverid1end_log_pos126CRC320xdcc54ec7Start:binlogv4,serverv8.0.28created22052911:19:07
#at126
#22052911:19:07serverid1end_log_pos197CRC320x5d440f7cPrevious-GTIDs
#d310871c-db0c-11ec-a557-020017003dc4:1-388482
#at197
#22052911:19:07serverid1end_log_pos276CRC320x0dd893b5GTIDlast_committed=0sequence_number=1rbr_only=yesoriginal_committed_timestamp=1653823147539722immediate_commit_timestamp=1653823147539722transaction_length=310
/*!50718SETTRANSACTIONISOLATIONLEVELREADCOMMITTED*//*!*/;
#original_commit_timestamp=1653823147539722(2022-05-2911:19:07.539722GMT)
#immediate_commit_timestamp=1653823147539722(2022-05-2911:19:07.539722GMT)
/*!80001SET@@session.original_commit_timestamp=1653823147539722*//*!*/;
/*!80014SET@@session.original_server_version=80028*//*!*/;
/*!80014SET@@session.immediate_server_version=80028*//*!*/;
SET@@SESSION.GTID_NEXT='d310871c-db0c-11ec-a557-020017003dc4:388483'/*!*/;
#at276
#22052911:19:07serverid1end_log_pos365CRC320xa49dc290Querythread_id=262exec_time=0error_code=0
...
BEGIN
/*!*/;
#at365
#22052911:19:07serverid1end_log_pos425CRC320x824f6309Table_map:`slowtech`.`t1`mappedtonumber157
#at425
#22052911:19:07serverid1end_log_pos476CRC320x5a6fe6ecWrite_rows:tableid157flags:STMT_END_F
###INSERTINTO`slowtech`.`t1`
###SET
###@1=1483132
###@2='aaaaaaaaaa'
#at476
#22052911:19:07serverid1end_log_pos507CRC320x66a401f6Xid=4108904
COMMIT/*!*/;
SET@@SESSION.GTID_NEXT='AUTOMATIC'/*addedbymysqlbinlog*//*!*/;
DELIMITER;
#Endoflogfile
/*!50003SETCOMPLETION_TYPE=@OLD_COMPLETION_TYPE*/;
/*!50530SET@@SESSION.PSEUDO_SLAVE_MODE=0*/;
可以看到,该事务对应的 GTID 是 d310871c-db0c-11ec-a557-020017003dc4:388483,不是 xtrabackup_binlog_info 中的 388482。
如果我们像在 MySQL 5.6,5.7 中那样,基于 xtrabackup_binlog_info 中的 GTID 信息来设置 GTID_PURGED,在我们这个 case 中,会导致同一个 INSERT 操作执行两次,进而会出现主键冲突,主从复制中断。
如此来看,问题的根源还是出在 performance_schema.log_status 中的 gtid_executed 和 binary_log_file + binary_log_position 指向的不是同一个事务。
这是一个 Bug 吗?其实不然。
XtraBackup 8.0 在查询完 performance_schema.log_status 后,会基于查询到的 binary_log_file 和 binary_log_position 拷贝对应的 Binlog 。
下面是备份集中拷贝的 Binlog。
#ll/data/backup/full/
...
-rw-r-----.1rootroot507May2911:19mysql-bin.000024
-rw-r-----.1rootroot19May2911:19mysql-bin.index
...
Binlog 中记录了 "mysql-bin.000024 507" 这个位置点的事务所对应的 GTID 值。
实例启动时,会自动基于 Binlog 中的 GTID 信息来初始化 GTID_EXECUTED 和 GTID_PURGED。
mysql>showglobalvariableswherevariable_namein('gtid_executed','gtid_purged');
+---------------+-----------------------------------------------+
|Variable_name|Value|
+---------------+-----------------------------------------------+
|gtid_executed|d310871c-db0c-11ec-a557-020017003dc4:1-388483|
|gtid_purged|d310871c-db0c-11ec-a557-020017003dc4:1-388482|
+---------------+-----------------------------------------------+
2rowsinset(0.00sec)
所以,实例起来后,我们看到的 GTID_EXECUTED 就已经是正确值,就已经能正确反映备份结束时的一致性位置点信息了。
这个时候,直接执行 CHANGE MASTER TO 操作就可以了。
performance_schema.log_status 的作用关于 performance_schema.log_status 的作用,其实官方文档中也提到了,是提供位置点信息,供备份工具拷贝所需的 Binlog。查询的过程中也会阻塞日志和相关管理操作。不过阻塞的时间很短,填充完表中的数据就会释放资源。
Thelog_statustableprovidesinformationthatenablesanonlinebackuptooltocopytherequiredlogfileswithoutlockingthoseresourcesforthedurationofthecopyprocess.
XtraBackup 8.0 中哪些场景会加全局读锁
Whenthelog_statustableisqueried,theserverblocksloggingandrelatedadministrativechangesforjustlongenoughtopopulatethetable,thenreleasestheresources.
Thelog_statustableinformstheonlinebackupwhichpointitshouldcopyuptointhesource'sbinarylogandgtid_executedrecord,andtherelaylogforeachreplicationchannel.
Italsoprovidesrelevantinformationforindividualstorageengines,suchasthelastlogsequencenumber(LSN)andtheLSNofthelastcheckpointtakenfortheInnoDBstorageengine.
下面两种场景,XtraBackup 8.0 会加全局读锁:
-
备份实例中存在 MyISAM 表。
-
备份从库,且命令行中指定了 --slave-info,且从库 SHOW SLAVE STATUS 中的 Auto_Position 不为 1。
Auto_Position 不为 1 意味着从库没有开启 GTID 复制,或者开启了 GTID 复制,但未将 MASTER_AUTO_POSITION 设置为 1。
1. 备份锁引入的初衷是为了阻塞备份过程中的 DDL,不是为了替代全局读锁。在 XtraBackup 8.0 中,我们可以指定 --skip-lock-ddl 禁用备份锁,这并不影响 XtraBackup 的正常使用。
2. 基于物理备份搭建从库时,无需提前创建空白实例。
3. 在基于位置点的复制中,注意 CHANGE MASTER TO 语句中 MASTER_LOG_FILE 和 MASTER_LOG_POS 的选择。
以一个简单的主从复制拓扑为例:master -> slave1。
- 如果是基于 master 的备份添加一个 master 的从库,或者,基于 slave1 的备份添加一个 slave1 的从库。建立复制时,应使用 xtrabackup_binlog_info 的位置点信息。
- 如果是基于 slave1 的备份添加 master 的一个从库,应使用 xtrabackup_slave_info 的位置点信息。
4. 基于从库的备份搭建从库时,在执行 CHANGE MASTER TO 操作之前,必须首先执行 RESET SLAVE ALL。
5. 无论是对主库还是从库进行备份,都可指定 --slave-info,此时都会生成 xtrabackup_slave_info。只不过如果是对主库进行备份,该文件会为空。
6. 在 GTID 复制中,设置 GTID_PURGED 时,注意备份实例的版本。如果是 MySQL 5.6,5.7,可直接基于 xtrabackup_binlog_info 中的 GTID 信息设置 GTID_PURGED。如果是 MySQL 8.0,无需再设置 GTID_PURGED。
参考[1] LOCK INSTANCE FOR BACKUP and UNLOCK INSTANCE Statements
[2] The log_status Table
[3]log_status has wrong binary_log_position of gtid_executed

