一、GTID
1.1 gtid的基本概念
gtid的全称为全局事务标识符(global transaction identifiner),是MySQL 5.6引入的一个特性。gtid保证了MySQL的每一个事务都有一个全局唯一的标识,该标识在本实例甚至主从复制环境都保证全局唯一。
GTID = server_uuid:sequence_id
server_uuid是一个32字节+1字节(/0)的字符串,MySQL第一次启动时生成,并将该信息写入datadir目录下的auto.cnf文件。如果该文件丢失,MySQL会重新生成一个新的server_uuid。相同的server_uuid下的事务对应的sequence_id在binlog文件中是递增且连续有序的,他们以集合的方式呈现。
1.2 gtid带来的便利性
1)通过gtid定位该事务来自哪个实例
2)搭建主从复制不再需要指定binlog文件以及具体的位点信息,而是通过全局唯一的gtid来做复制,MySQL通过gtid来验证冲突并确保每个事务只会被执行一次。
3)方便DBA的运维管理,快速改变主从复制关系
1.3 GTID在主从复制中如何工作?
1)master执行的每一个变更操作都生成一个gtid值,并且会把该值记录在binlog中用来主从复制,后续择机更新gtid_executed表记录
2)主从复制模式下,start slave后,从库会将自身执行过的gtid集合信息发送给主库,主库将从库未执行过的binlog信息发送给从库
3)从库读取relaylog中把该值设置为当前的gtid_next值,对具体的事务进行应用,择机更新gtid_executed表记录。期间主库不断的将新产生的binlog event发送至从库
从库应用主库的事务时不会生成新的gtid值,而是将读取的gtid_next的值记录在自己的binlog文件中
1.4 gtid的维护
1、gtid_executed表
1)MySQL 5.7.5之前
- 该版本下从库必须开始binlog并且设置log_slave_updates=on来保证从库执行过的gtid信息全部记录在binlog中
2)MySQL 5.7.5之后
- MySQL 5.7.5之后新增的mysql.gtid_executed表
- 若不开启binlog,每个事务的gtid信息都会记录到gtid_executed表中
- 若开启binlog且开启log_slave_updates,每个事务的gtid信息不仅会记录到gtid_executed表中,也会在记录在binlog日志中的GTID_LOG_EVENT中
3)概览
- gtid持久化介质
- gtid_executed表会随着数据库的不断更新而存储较多的gtid信息
- MySQL对定期对gtid_executed表进行压缩,通过参数gtid_executed_compression_period进行控制,默认该表记录1000条记录后就进行一次压缩
- MySQL binlog日志切换也会模式对该表进行一次压缩
2、gtid_executed变量
- 该变量为一个gtid set的形式,存储在内存中,表示当前实例执行了哪些gtid事务
- “show slave status\G”、"show master status"中记录的Executed_Gtid_Set都来自该参数的值
3、gtid_purged变量
- 该变量为gtid set的形式,存储在内存中,表示当前实例已经丢失了(执行过)哪些gtid事务
- 通过purge命令或者expire_logs_days参数自动删除历史binlog文件后,会导致历史gtid信息丢失
- 在搭建从库时,我们可以手动指定gtid_purge值来表示当前从库已经执行过了哪些gtid,从该gtid之后重新开始复制
4、gtid_mode
gtid_mode值 | 含义 |
---|---|
ON | 使用gtid模式,新生产的事务为gtid事务,且只能复制gtid事务 |
ON_PERMISSIVE | 新生成的事务为gtid事务,同时可以复制gtid事务或者匿名事务 |
OFF_PERMISSIVE | 新生成的事务为匿名事务,同时可以复制gtid事务或者匿名事务 |
OFF | 关闭gtid模式,新生成的事务为匿名事务,且只能复制匿名事务 |
5、enforce_gtid_consistency
enforce_gtid_consistency值 | 含义 |
---|---|
ON | 不允许任何交易违反GTID一致性 |
WARN | 允许所有事务违反GTID一致性,但是在这种情况下会生成警告,MySQL 5.7.6新增 |
OFF | 允许所有事务违反GTID一致性 |
6、在主/从库中gtid_executed表、gtid_executed变量、gtid_purged变量更新时机
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Bzvv6DUI-1593157274284)(http://note.youdao.com/yws/res/56812/FD085068A28544C9A48478E0440293BC)]
7、GTID模块初始化以及binlog_gtid_simple_recovery参数的理解
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kUzYKNIB-1593157274289)(http://note.youdao.com/yws/res/56820/33267B0128BE4C9C82E3A5BBCE732C9C)]
二、gtid的应用
2.1 gtid搭建主从
1、gtid相关参数设置
root@mysql57 15:30: [(none)]> show variables like '%gtid%';
+----------------------------------+-----------+
| Variable_name | Value |
+----------------------------------+-----------+
| binlog_gtid_simple_recovery | ON | //默认为on,不建议关闭。为快速从binlog日志中找到gtid信息
| enforce_gtid_consistency | ON | //该参数必须设置为on,保证gtid的一致性
| gtid_executed_compression_period | 1000 | //指定gtid_executed表压缩
| gtid_mode | ON | //打开gtid模式
| gtid_next | AUTOMATIC |
| gtid_owned | |
| gtid_purged | |
| session_track_gtids | OFF |
+----------------------------------+-----------+
8 rows in set (0.00 sec)
2、搭建主从需要关注参数
server_id //主从库server-id必须不一样
log_bin //主库必须打开binlog日志
binlog_format=row //建议使用row模式
gtid_mode=on //开启gtid
enforce_gtid_consitency=on //保证gtid一致性
log_slave_updates //5.6版本中使用gtid必须开启该参数,5.7.5以后该参数决定gtid信息持久化介质是哪些
3、使用gtid模式搭建主从复制
CHANGE MASTER TO
MASTER_HOST='master2.example.com',
MASTER_USER='replication',
MASTER_PASSWORD='password',
MASTER_PORT=3306,
MASTER_AUTO_POSITION=1;
2.2 传统复制架构 -> gtid复制架构
1、在MySQL 5.7.6之前,需要重启数据库修改
1)关闭主库,停止业务写入
2)等待从库追上主库的复制
3)修改主库、从库配置文件,添加“gtid_mode=on,enforce_gtid_consitency=on”,启动从库时指定–skip-slave-start避免从库启动时继续使用传统模式复制
4)检查主从复制是否修改为gtid模式,且复制状态是否正常
2、在MySQL 5.7.6之后,支持在线修改
1)在每台服务器上设置enforce_gtid_consistency=warn,允许所有事务可以违反gtid的一致性
root@mysql57 20:43: [(none)]> set global enforce_gtid_consistency=warn;
Query OK, 0 rows affected (0.00 sec)
root@mysql57 20:43: [(none)]> show variables like '%enforce%';
+--------------------------+-------+
| Variable_name | Value |
+--------------------------+-------+
| enforce_gtid_consistency | WARN |
+--------------------------+-------+
1 row in set (0.01 sec)
2)在每台服务器上设置enforce_gtid_consistency=on,保证所有事务都不可以违反gtid的一致性
root@mysql57 20:44: [(none)]> set global enforce_gtid_consistency=on;
Query OK, 0 rows affected (0.00 sec)
root@mysql57 20:44: [(none)]> show variables like '%enforce%';
+--------------------------+-------+
| Variable_name | Value |
+--------------------------+-------+
| enforce_gtid_consistency | ON |
+--------------------------+-------+
1 row in set (0.00 sec)
3)在每台服务器上设置gtid_mode=off_permissive,表示新事务是匿名事务,同时允许复制的事务是gtid或是匿名事务
root@mysql57 20:47: [repl_test]> show variables like '%gtid%';
+----------------------------------+----------------+
| Variable_name | Value |
+----------------------------------+----------------+
| binlog_gtid_simple_recovery | ON |
| enforce_gtid_consistency | ON |
| gtid_executed_compression_period | 1000 |
| gtid_mode | OFF_PERMISSIVE |
| gtid_next | AUTOMATIC |
| gtid_owned | |
| gtid_purged | |
| session_track_gtids | OFF |
+----------------------------------+----------------+
8 rows in set (0.00 sec)
4)在每台服务器上设置gtid_mode=on_permissive,表示新的事务是gtid事务,同时允许复制的事务是gtid或者匿名事务
root@mysql57 20:47: [repl_test]> set global gtid_mode=on_permissive;
Query OK, 0 rows affected (0.02 sec)
root@mysql57 20:48: [repl_test]> show variables like '%gtid%';
+----------------------------------+---------------+
| Variable_name | Value |
+----------------------------------+---------------+
| binlog_gtid_simple_recovery | ON |
| enforce_gtid_consistency | ON |
| gtid_executed_compression_period | 1000 |
| gtid_mode | ON_PERMISSIVE |
| gtid_next | AUTOMATIC |
| gtid_owned | |
| gtid_purged | |
| session_track_gtids | OFF |
+----------------------------------+---------------+
8 rows in set (0.00 sec)
5)在每台从服务器上等待状态参数Ongoing_anonymous_transaction_count的状态值为0,该参数表示正在处理的匿名事务数,只有该状态值降为0才可进行下一步
root@mysql 20:48: [(none)]> show global status like '%transaction%';
+-------------------------------------+-------+
| Variable_name | Value |
+-------------------------------------+-------+
| Ongoing_anonymous_transaction_count | 0 |
+-------------------------------------+-------+
1 row in set (0.00 sec)
6)在每台服务器上设置gtid_mode=on,此后从库只会复制gtid事务
root@mysql57 20:49: [repl_test]> set global gtid_mode=on;
Query OK, 0 rows affected (0.02 sec)
root@mysql57 20:50: [repl_test]> show variables like '%gtid%';
+----------------------------------+-----------+
| Variable_name | Value |
+----------------------------------+-----------+
| binlog_gtid_simple_recovery | ON |
| enforce_gtid_consistency | ON |
| gtid_executed_compression_period | 1000 |
| gtid_mode | ON |
| gtid_next | AUTOMATIC |
| gtid_owned | |
| gtid_purged | |
| session_track_gtids | OFF |
+----------------------------------+-----------+
8 rows in set (0.00 sec)
7)修改配置文件“gtid_mode=on,enforce_gtid_consitency=on”,保证数据库重启后仍是gtid
8)修改当前复制为gtid复制
root@mysql 20:51: [(none)]> stop slave;
Query OK, 0 rows affected (0.01 sec)
root@mysql 20:51: [(none)]>
root@mysql 20:51: [(none)]> change master to master_auto_position=1;
Query OK, 0 rows affected (0.01 sec)
9)检查复制状态以及复制模式
root@mysql 20:51: [(none)]> show slave status\G
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
Executed_Gtid_Set: ca3051f8-a265-11ea-923e-00163e15aea9:1-6
Auto_Position: 1
2.3 gtid复制架构 -> 传统复制架构
1)转笔从库主从复制,并修改当前复制为传统复制模式
##停止主从复制,并查看当前复制的位点信息
root@mysql 22:46: [(none)]> stop slave;
Query OK, 0 rows affected (0.00 sec)
root@mysql 22:46: [(none)]> show slave status\G
Master_Log_File: binlog.000005
Read_Master_Log_Pos: 1968
Auto_Position: 1
##修改gtid复制为传统复制
root@mysql 22:46: [(none)]> change master to master_log_file='binlog.000005',master_log_pos=1968,master_auto_position=0;
Query OK, 0 rows affected (0.02 sec)
root@mysql 22:47: [(none)]> start slave;
Query OK, 0 rows affected (0.01 sec)
##检查复制模式以及复制状态
root@mysql 22:47: [(none)]> show slave status\G
Master_Log_File: binlog.000005
Read_Master_Log_Pos: 2775
Auto_Position: 0
2)将每个服务器的gtid_mode设置为on_permissive,表示新的事务还是使用gtid,同时允许复制gtid事务和匿名事务
root@mysql 22:47: [(none)]> set global gtid_mode=on_permissive;
Query OK, 0 rows affected (0.01 sec)
root@mysql 22:51: [(none)]> show variables like '%gtid%';
+----------------------------------+---------------+
| Variable_name | Value |
+----------------------------------+---------------+
| binlog_gtid_simple_recovery | ON |
| enforce_gtid_consistency | ON |
| gtid_executed_compression_period | 1000 |
| gtid_mode | ON_PERMISSIVE |
| gtid_next | AUTOMATIC |
| gtid_owned | |
| gtid_purged | |
| session_track_gtids | OFF |
+----------------------------------+---------------+
8 rows in set (0.00 sec)
3)将每个服务器的gtid_mode设置为off_permissive,表示新的事务为匿名事务,同时允许复制gtid事务和匿名事务
root@mysql 22:51: [(none)]> set global gtid_mode=off_permissive;
Query OK, 0 rows affected (0.01 sec)
root@mysql 22:51: [(none)]> show variables like '%gtid%';
+----------------------------------+----------------+
| Variable_name | Value |
+----------------------------------+----------------+
| binlog_gtid_simple_recovery | ON |
| enforce_gtid_consistency | ON |
| gtid_executed_compression_period | 1000 |
| gtid_mode | OFF_PERMISSIVE |
| gtid_next | AUTOMATIC |
| gtid_owned | |
| gtid_purged | |
| session_track_gtids | OFF |
+----------------------------------+----------------+
8 rows in set (0.00 sec)
4)查看从库gtid_owned,等待该参数为空,表示当前已经无正在复制中的gtid事务,且后续全部都是匿名事务
root@mysql 22:54: [(none)]> show variables like '%gtid%';
+----------------------------------+-----------+
| Variable_name | Value |
+----------------------------------+-----------+
| binlog_gtid_simple_recovery | ON |
| enforce_gtid_consistency | ON |
| gtid_executed_compression_period | 1000 |
| gtid_mode | OFF |
| gtid_next | AUTOMATIC |
| gtid_owned | |
| gtid_purged | |
| session_track_gtids | OFF |
+----------------------------------+-----------+
8 rows in set (0.00 sec)
5)关闭从库的gtid模式
root@mysql 22:54: [(none)]> show variables like '%gtid%';
+----------------------------------+-----------+
| Variable_name | Value |
+----------------------------------+-----------+
| binlog_gtid_simple_recovery | ON |
| enforce_gtid_consistency | ON |
| gtid_executed_compression_period | 1000 |
| gtid_mode | OFF |
| gtid_next | AUTOMATIC |
| gtid_owned | |
| gtid_purged | |
| session_track_gtids | OFF |
+----------------------------------+-----------+
8 rows in set (0.00 sec)
##若主库此刻修改gtid_mode会出现报错:
root@mysql57 22:54: [repl_test]> set global gtid_mode=off;
ERROR 3111 (HY000): SET @@GLOBAL.GTID_MODE = OFF is not allowed because replication channel '' is configured in AUTO_POSITION mode. Execute CHANGE MASTER TO MASTER_AUTO_POSITION = 0 FOR CHANNEL '' before you set @@GLOBAL.GTID_MODE = OFF..
6)修改配置文件,保证重启后也不再使用gtid
gtid_mode=off
enforce_gtid_consistency=off
三、gtid的限制
由于gtid对事务一致性的要求,会导致以下一些问题无法支持:
1、事务中包含对多个存储引擎的查询更新,会导致对该事务分配多个gtid
2、主从库存储引擎不一致的情况下,会导致数据不一致
3、无法使用create table … select 的语句
root@mysql57 23:49: [repl_test]> create table t5 select * from t1;
ERROR 1786 (HY000): Statement violates GTID consistency: CREATE TABLE ... SELECT.
row模式下,create table … select其实会转换为两个单独的事务,一个是create table,一个是insert数据。当在事务中执行该语句时,一些情况下会导致两个事务分配了相同的事务id,这意味着从库会忽略掉插入数据的事务,从而导致主从数据不一致
4、只有在acticommit=1的情况下,才支持使用create temporary table和drop temporary table语句
root@mysql57 23:34: [repl_test]> show master status;
+---------------+----------+--------------+------------------+-------------------------------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+---------------+----------+--------------+------------------+-------------------------------------------+
| binlog.000010 | 1430 | | | ca3051f8-a265-11ea-923e-00163e15aea9:1-21 |
+---------------+----------+--------------+------------------+-------------------------------------------+
1 row in set (0.00 sec)
root@mysql57 23:50: [repl_test]> show variables like '%autocommit%';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| autocommit | ON |
+---------------+-------+
1 row in set (0.00 sec)
root@mysql57 23:50: [repl_test]> create temporary table tmp_t1 like t1;
Query OK, 0 rows affected (0.00 sec)
root@mysql57 23:50: [repl_test]> show master status;
+---------------+----------+--------------+------------------+-------------------------------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+---------------+----------+--------------+------------------+-------------------------------------------+
| binlog.000010 | 1430 | | | ca3051f8-a265-11ea-923e-00163e15aea9:1-21 |
+---------------+----------+--------------+------------------+-------------------------------------------+
1 row in set (0.00 sec)
root@mysql57 23:51: [repl_test]> drop temporary table tmp_t1;
Query OK, 0 rows affected (0.00 sec)
root@mysql57 23:51: [repl_test]> show master status;
+---------------+----------+--------------+------------------+-------------------------------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+---------------+----------+--------------+------------------+-------------------------------------------+
| binlog.000010 | 1644 | | | ca3051f8-a265-11ea-923e-00163e15aea9:1-22 |
+---------------+----------+--------------+------------------+-------------------------------------------+
1 row in set (0.00 sec)
##从库
root@mysql 23:51: [repl_test]> show tables;
+---------------------+
| Tables_in_repl_test |
+---------------------+
| t1 |
| t2 |
| t3 |
| t4 |
+---------------------+
4 rows in set (0.00 sec)
root@mysql 23:51: [repl_test]> show master status;
+------------------+----------+--------------+------------------+-------------------------------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+------------------+----------+--------------+------------------+-------------------------------------------+
| mysql-bin.000013 | 1588 | | | ca3051f8-a265-11ea-923e-00163e15aea9:1-22 |
+------------------+----------+--------------+------------------+-------------------------------------------+
1 row in set (0.00 sec)
root@mysql 23:51: [repl_test]> show slave status\G
*************************** 1. row ***************************
Slave_IO_State: Waiting for master to send event
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
Slave_SQL_Running_State: Slave has read all relay log; waiting for more updates
Retrieved_Gtid_Set: ca3051f8-a265-11ea-923e-00163e15aea9:18-22
Executed_Gtid_Set: ca3051f8-a265-11ea-923e-00163e15aea9:1-22
Auto_Position: 1
master创建临时表不产生gtid信息,导致从库无法同步该操作,而后续删除临时表的操作会产生相应的gtid信息并同步到从库,这种情况下就会导致主从复制报错中断
5、不推荐在开启gtid模式的实例上使用mysql_upgrate