MySQL: 为什么使用 innobackupex 备份恢复搭建主从时,必须人为设置 gtid_purged 变量

在MySQL主从复制中,由于未正确设置GTID导致从库数据不一致。主库在备份时有未提交的事务,gtid_executed未更新,从库恢复后基于不完整的GTID执行了重复事务。解决方法是在startslave前,根据xtrabackup_binlog_info的GTID设置gtid_purged,确保主从GTID一致。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

问题描述:
使用innobackupex 搭建主从的步骤如下:

  1. 主库使用 innobackupex 备份并 apply-log
  2. 将备份文件拷贝至从库,从库清空datadir目录,并使用 innobackupex 进行 copy-back
  3. 从库根据备份目录中的 xtrabackup_binlog_info 的GTID信息来设置 gtid_purged 变量。
  4. 从库 change master 并 start slave.

在下面的场景中,确少了第3步,导致主从数据发生了不一致:

1. 主库上创建表 t1007 并插入一条记录:

mysql> create table t1007(id int);
Query OK, 0 rows affected (0.02 sec)

mysql> flush binary logs;
Query OK, 0 rows affected (0.02 sec)

mysql> insert into t1007 values(1);
Query OK, 1 row affected (0.00 sec)

mysql> show global variables like '%gtid%';
+----------------------------------+---------------------------------------------+
| Variable_name                    | Value                                       |
+----------------------------------+---------------------------------------------+
| binlog_gtid_simple_recovery      | ON                                          |
| enforce_gtid_consistency         | ON                                          |
| gtid_executed                    | b0dd0ee8-ffd9-11e9-8d1c-005056aa8c82:1-7338 |
| gtid_executed_compression_period | 1000                                        |
| gtid_mode                        | ON                                          |
| gtid_owned                       |                                             |
| gtid_purged                      | b0dd0ee8-ffd9-11e9-8d1c-005056aa8c82:1-16   |
| session_track_gtids              | OFF                                         |
+----------------------------------+---------------------------------------------+
8 rows in set (0.00 sec)


=======
# cat xtrabackup_binlog_info 
mysql-bin.000010        456     b0dd0ee8-ffd9-11e9-8d1c-005056aa8c82:1-7338
==================

2. 主库使用innobackupex备份并在从库恢复

3. 从库change master 并 start slave

mysql>  show global variables like '%gtid%';
+----------------------------------+---------------------------------------------+
| Variable_name                    | Value                                       |
+----------------------------------+---------------------------------------------+
| binlog_gtid_simple_recovery      | ON                                          |
| enforce_gtid_consistency         | ON                                          |
| gtid_executed                    | b0dd0ee8-ffd9-11e9-8d1c-005056aa8c82:1-7337 |
| gtid_executed_compression_period | 1000                                        |
| gtid_mode                        | ON                                          |
| gtid_owned                       |                                             |
| gtid_purged                      | b0dd0ee8-ffd9-11e9-8d1c-005056aa8c82:1-7337 |
| session_track_gtids              | OFF                                         |
+----------------------------------+---------------------------------------------+
8 rows in set (0.00 sec)


mysql> change master to master_user='mysqlsync',
    -> master_password='xxxxxxxx',
    -> master_port=3306,
    -> master_host='197.0.xx.xxx',
    -> MASTER_AUTO_POSITION=1;
Query OK, 0 rows affected, 2 warnings (0.02 sec)

mysql> show warnings;
+-------+------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Level | Code | Message                                                                                                                                                                                                                                                                              |
+-------+------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Note  | 1759 | Sending passwords in plain text without SSL/TLS is extremely insecure.                                                                                                                                                                                                               |
| Note  | 1760 | Storing MySQL user name or password information in the master info repository is not secure and is therefore not recommended. Please consider using the USER and PASSWORD connection options for START SLAVE; see the 'START SLAVE Syntax' in the MySQL Manual for more information. |
+-------+------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
2 rows in set (0.00 sec)

mysql> start slave;
Query OK, 0 rows affected (0.06 sec)

mysql> show slave status \G
*************************** 1. row ***************************
               Slave_IO_State: Waiting for master to send event
...
             Slave_IO_Running: Yes
            Slave_SQL_Running: Yes
..
          SQL_Remaining_Delay: NULL
      Slave_SQL_Running_State: Slave has read all relay log; waiting for more updates
           Master_Retry_Count: 86400
..
           Retrieved_Gtid_Set: b0dd0ee8-ffd9-11e9-8d1c-005056aa8c82:7338
            Executed_Gtid_Set: b0dd0ee8-ffd9-11e9-8d1c-005056aa8c82:1-7338
                Auto_Position: 1
...
1 row in set (0.00 sec)

mysql> select * from xiaoyan.t1007;
+------+
| id   |
+------+
|    1 |
|    1 |
+------+
2 rows in set (0.00 sec)

可以看到从库查到到 t1007 有两条记录,至此主从数据已经不一致了,但是没有任何报错。

原因如下:
主库上的 insert 语句的事务编号是 7338,从库恢复之后可以看到从库的 gtid_executed 为 1-7337 ,因此建立主从关系之后从库会再做一次 7338号事务,因此相当于又做了一次插入,加上表本身的一条记录,结果是两条记录。

为那么从库的 gtid_executed 不是 1-7338 呢?因为它是从主库备份恢复过来的,主库备份的时候实际上是备份的 表 mysql.gtid_executed 的数据,在上一篇文章 中说过,这个表记录并不准确,它和实际执行过的 GTID 不一样,它不包含活动的 BINLOG 中的 GTID 。 主库上 7338 号事务完成后并没有 flush binary logs,因此 mysql.gtid_executed 中只有 1-7337.

因此,如果主库上有事务在进行,大多数情况下,备份出来的 gtid_executed 都不准确。
在搭建从库时,需要查看 xtrabackup_binlog_info 文件,该文件中的 gtid_executed 才准确,需要在start slave之前 先 reset maset ,并 set global gtid_purged 为 xtrabackup_binlog_info中的值。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值