GTID是什么?

GTID (Global Transaction ID) 是对于一个已提交事务的编号,并且是一个全局唯一的编号,每一个事务都会对应GTID,GTID是从MySQL-5.6.5开始支持的,MySQL-5.6.10后开始完善。GTID由两部分组成server_uuid:序列号。

gtid_format.jpg

GTIT set可以包含来自多个数据库实例的事务,用逗号分隔开,例如一从多主库的从库就有多个。

GTID作用

  • 更方便的方式搭建主从备份,旧版本是通过binlog+position号方式实现
  • 更简单的实现主从之间failover

GDIT工作原理

  1. master更新数据时,会在事务前产生GTID,一同记录到binlog日志中。
  2. slave端的i/o 线程将变更的binlog,写入到本地的relay log中。
  3. sql线程从relay log中获取GTID,然后对比slave端的binlog是否有记录。
  4. 如果有记录,说明该GTID的事务已经执行,slave会忽略。
  5. 如果没有记录,slave就会从relay log中执行该GTID的事务,并记录到binlog。
  6. 在解析过程中会判断是否有主键,如果没有就用二级索引,如果没有就用全部扫描。

GTID开启时导出导入库的注意事项

导出数据库

1
2
mysqldump -uroot -p db > test.sql
Warning: A partial dump from a server that has GTIDs will by default include the GTIDs of all transactions, even those that changed suppressed parts of the database. If you don't want to restore GTIDs, pass --set-gtid-purged=OFF. To make a complete dump, pass --all-databases --triggers --routines --events

会导出成功,但是会有一个warning提示,并且在导出的sql文件中的头部会有类似以下GTID相关信息:

1
2
3
4
5
6
7
8
9
SET @MYSQLDUMP_TEMP_LOG_BIN = @@SESSION.SQL_LOG_BIN;
SET @@SESSION.SQL_LOG_BIN= 0;

--
-- GTID state at the beginning of the backup
--

SET @@GLOBAL.GTID_PURGED='048b5fb0-ec3e-11e7-b805-6c92bf5f0bea:1-380,
5f2ddf18-5462-11e9-87a0-6c0b84d5e42c:1-12;

在开启有 GTID 功能的数据库实例中, 导出其中任何一个库, 如果没有显示地指定–set-gtid-purged参数, 都会提示这一行信息. 默认情况下, 导出的库中含有 GTID 信息, 如果不想导出包含有 GTID 信息的数据库, 需要显示地添加–set-gtid-purged=OFF参数,例如:

1
mysqldump -uroot -p  --set-gtid-purged=OFF db > test.sql

如果只是简单做个数据导出,添加–set-gtid-purged=OFF即可,不含GTID信息,导入数据时候更简单。

导入数据库

如果sql中不含GTID信息,直接导入即可。
如果是带有GTID信息,可能不会顺利导入。

1
2
mysql -uroot -p userdb < userdb.sql
ERROR 1840 (HY000) at line 24: @@GLOBAL.GTID_PURGED can only be set when @@GLOBAL.GTID_EXECUTED is empty.

在 mysql5.7版本中加入了多 channel 的特性, 一台数据库实例可以同时与多个主库同步, 实现多主一从架构, 但是假如现在数据库实例中开启了 GTID, 并以 GTID 的方式与 A 主库和 B 主库同步,那么现在的 slave 中就记录有两条 GTID 信息. 在导入带有新 GTID 信息的库时, 会报错, 要求你清除掉目标数据库实例中所有的 GTID 信息. 在这种情况下, 问题就比较严重了, 因为我的这台数据库已经和两台主库建立主从关系, 现在为了导入一个新库, 需要 reset 掉所有同步信息(GTID 信息)

这个时候你有两个选择:

  1. 重新使用–set-gtid-purged=OFF dump 不含GTID的数据库,再导入。
  2. 在目标数据库中执行reset slave all; reset master;清空所有 GTID 信息之后就可以导入了,通过查看gtid信息可以看到gtid_executed已清空。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
mysql> show global variables like '%gtid%';
+----------------------------------+--------------------------------------------+
| Variable_name | Value |
+----------------------------------+--------------------------------------------+
| binlog_gtid_simple_recovery | ON |
| enforce_gtid_consistency | ON |
| gtid_executed | |
| gtid_executed_compression_period | 1000 |
| gtid_mode | ON |
| gtid_owned | |
| gtid_purged | |
| session_track_gtids | OFF |
+----------------------------------+--------------------------------------------+
8 rows in set (0.00 sec)

通过mysqldump搭建从库(旧方法)

1、在备份的时候指定–master-data=2(导出的文件重会以注释方式保存binlog的文件号和position的命令,–master-data=1就不注释,1和2就是自动和手动设置binlog和position的区别)。

1
2
3
4
5
--
-- Position to start replication or point-in-time recovery from
--

CHANGE MASTER TO MASTER_LOG_FILE='mysql-bin.000090', MASTER_LOG_POS=107;

2、将备份还原到slave后,使用change master to命令挂载master端。
3、5.6.9后可以GTID同步的方式,上面提到带GTID信息的数据导入。

相关名词解析

name desc
enforce_gtid_consistency 开启gtid的一些安全限制
gtid_executed 全局和seeeion级别都可以用。用来保存已经执行过的GTIDs。
gtid_executed 全局和seeeion级别都可以用。用来保存已经执行过的GTIDs。show master status;输出结果中的Executed_Gtid_Set和gitd_executed一致。reset master时,此值会被清空。
gtid_owned 全局和session级别都可用,全局表示所有服务器拥有GTIDs,session级别表示当前client拥有所有GTIDs。(此功能用的少)
gtid_mode 是否开启GTID功能。
gtid_purged 全局参数,设置在binlog中,已经purged的GTIDs,并且purged掉的GTIDs会包含到gtid_executed中。从而导致slave不会再去master请求这些GTIDs,并且Executed_Gtid_Set为空时,才可以设置此值。
gtid_next 这个时session级别的参数。查看命令:show session variables like ‘%gtid_next%’;

相关命令

主库

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
mysql> show master status;
+-------------------+-----------+--------------+------------------+--------------------------------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+-------------------+-----------+--------------+------------------+--------------------------------------------+
| master-bin.000002 | 149375983 | | | 834449ff-4487-11e8-8b27-000c294b06ca:1-254 |
+-------------------+-----------+--------------+------------------+--------------------------------------------+
1 row in set (0.00 sec)

mysql> show slave hosts;
+-----------+------+------+-----------+--------------------------------------+
| Server_id | Host | Port | Master_id | Slave_UUID |
+-----------+------+------+-----------+--------------------------------------+
| 32 | | 3306 | 31 | 68303133-4489-11e8-84e9-000c293eaee6 |
+-----------+------+------+-----------+--------------------------------------+
1 row in set (0.00 sec)

mysql> show global variables like '%gtid%';
+----------------------------------+--------------------------------------------+
| Variable_name | Value |
+----------------------------------+--------------------------------------------+
| binlog_gtid_simple_recovery | ON |
| enforce_gtid_consistency | ON |
| gtid_executed | 834449ff-4487-11e8-8b27-000c294b06ca:1-255 |已经在该实例上执行过的事务
| gtid_executed_compression_period | 1000 |
| gtid_mode | ON |
| gtid_owned | |正在执行的事务的gtid以及对应的线程ID
| gtid_purged | |本机已经执行,且被PURGE BINARY LOG TO删除
| session_track_gtids | OFF |
+----------------------------------+--------------------------------------------+
8 rows in set (0.00 sec)

mysql> SHOW SESSION VARIABLES LIKE 'gtid_next';
+---------------+-----------+
| Variable_name | Value |
+---------------+-----------+
| gtid_next | AUTOMATIC | session级别变量,表示下一个将被使用的gtid
+---------------+-----------+
1 row in set (0.02 sec)

从库

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
mysql> SHOW SLAVE STATUS\G
*************************** 1. row ***************************
Slave_IO_State: Waiting for master to send event
Master_Host: 192.168.0.123
Master_User: mysync
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: mysqld-bin.000005
Read_Master_Log_Pos: 879
Relay_Log_File: mysqld-relay-bin.000009 # 备库中的relaylog文件
Relay_Log_Pos: 736 # 备库执行的偏移量
Relay_Master_Log_File: mysqld-bin.000005
Slave_IO_Running: Yes
Slave_SQL_Running: No
... ...
Skip_Counter: 0
Exec_Master_Log_Pos: 634
Relay_Log_Space: 1155
... ...
Last_IO_Errno: 0
Last_IO_Error:
Last_SQL_Errno: 1062
Last_SQL_Error: Error 'Duplicate entry '1' for key 'PRIMARY'' on query.
Default database: ''. Query: 'insert into wb.t1 set i=1'
Replicate_Ignore_Server_Ids:
Master_Server_Id: 3
Master_UUID: 46fdb7ad-5852-11e6-92c9-0800274fb806
... ...
Retrieved_Gtid_Set: 46fdb7ad-5852-11e6-92c9-0800274fb806:1-4, #已从主库获取的事务
4fbe2d57-5843-11e6-9268-0800274fb806:1-3
Executed_Gtid_Set: 46fdb7ad-5852-11e6-92c9-0800274fb806:1-3, #已执行的事务
4fbe2d57-5843-11e6-9268-0800274fb806:1-3,
81a567a8-5852-11e6-92cb-0800274fb806:1
Auto_Position: 1
1 row in set (0.00 sec)