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

发布时间 2023-04-20 15:36:12作者: whiteY

问题描述:

使用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
==================
  1. 主库使用innobackupex备份并在从库恢复

  2. 从库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中的值。