> 基于已有的位置点主从复制架构,在线开启/关闭 GTID 复制
- 主库:192.168.195.141
- 从库:192.168.195.142
1. 什么是 GTID
GTID(Global Transaction Identifier,全局事务ID),会为每个事务分配一个唯一的事务ID,格式如下:
source_id:transaction_id- source_id:事务是在哪个实例上产生的,通常用实例的 server_uuid 来表示。
- transaction_id:事务的序列号,按照事务提交的顺序从1开始分配。
这样,可保证 GTID 在整个复制拓扑中都是全局唯一的。
2. GTID 的优点
- 全局唯一标识符:GTID 为每个事务提供一个全局唯一的标识符,避免了在复制拓扑中使用二进制日志文件和位置的复杂性。
- 简化配置:使用 GTID 可以更轻松地配置主从复制,无需手动跟踪二进制日志文件和位置。
- 故障恢复:GTID 简化了故障恢复过程,使得在主从之间重新建立复制关系更为容易。
- 避免重复应用:GTID 可以帮助防止在主从之间重复应用相同的事务,提高数据一致性。
3. 当前环境确认
3.1 主库配置文件 /etc/my.cnf(141)
[client] socket = /data/mysql/3306/data/mysql.sock [mysqld] basedir = /usr/local/mysql datadir = /data/mysql/3306/data user = mysql port = 3306 socket = /data/mysql/3306/data/mysql.sock log_error = /data/mysql/3306/data/mysqld.err log_timestamps = system log-bin = mysql-bin server-id = 13.2 从库配置文件 /etc/my.cnf(142)
[client] socket = /data/mysql/3306/data/mysql.sock [mysqld] basedir = /usr/local/mysql datadir = /data/mysql/3306/data user = mysql port = 3306 socket = /data/mysql/3306/data/mysql.sock log_error = /data/mysql/3306/data/mysqld.err log_timestamps = system server-id = 23.3 当前 GTID 状态
主库(141): gtid_mode = OFF enforce_gtid_consistency = OFF 从库(142): gtid_mode = OFF enforce_gtid_consistency = OFF Auto_Position = 0(基于位置点复制)4. GTID 相关参数
mysql>showvariableslike'%gtid%';+----------------------------------+----------------------------------------------+|Variable_name|Value|+----------------------------------+----------------------------------------------+|binlog_gtid_simple_recovery|ON||enforce_gtid_consistency|OFF||gtid_executed|||gtid_executed_compression_period|0||gtid_mode|OFF||gtid_next|AUTOMATIC||gtid_owned|||gtid_purged|||session_track_gtids|OFF|+----------------------------------+----------------------------------------------+参数解释:
gtid_mode:是否开启 GTID 复制。在 MySQL 5.7.6 之前,如果要开启或关闭 GTID 复制,必须重启实例。从 MySQL 5.7.6 开始,可在线开启 GTID 复制。
gtid_mode 可设置以下选项:
- OFF:所有新的事务和复制中的事务都必须是匿名事务(非 GTID 事务)。
- OFF_PERMISSIVE:新的事务是匿名事务,复制中的事务既可以是匿名事务,也可以是 GTID 事务。
- ON_PERMISSIVE:新的事务是 GTID 事务,复制中的事务既可以是匿名事务,也可以是 GTID 事务。
- ON:所有新的事务和复制中的事务都必须是 GTID 事务。
注意:对于该参数的修改,只能逐步修改,不能直接修改。如将 OFF 调整为 ON,只能按照
OFF -> OFF_PERMISSIVE -> ON_PERMISSIVE -> ON的顺序进行修改。enforce_gtid_consistency:用来检测是否有违反 GTID 限制的 SQL。
- OFF:关闭检测。
- ON:开启检测。如果操作违反了限制,会直接报错。
- WARN:开启检测。如果操作违反了限制,不会报错,只是会在错误日志中打印 Warning。
注意:如果要将 gtid_mode 设置为 ON,则 enforce_gtid_consistency 必须为 ON。
gtid_executed:MySQL 已经执行过的 GTID 集。
gtid_purged:MySQL 已经清除的 GTID 集,通常是被删除的 binlog 中的 GTID 集。
gtid_next:用来设置下一个 GTID 值,只能在会话级别设置。
- AUTOMATIC:自动获取下一个 GTID 值,默认值。
- ANONYMOUS:匿名事务。
- UUID:NUMBER:显式设置 GTID 值。常用于主从复制环境,从库跳过指定事务。
gtid_executed_compression_period:MySQL 会定期对 mysql.gtid_executed 表进行压缩。MySQL 8.0.23 开始默认值为 0,会根据需要进行压缩。
5. GTID 复制的限制
- 不支持
CREATE TABLE ... SELECT ...语句。从 MySQL 8.0.21 开始,该限制被取消。 - 不允许在事务、存储过程、函数、触发器中执行
CREATE TEMPORARY TABLE或DROP TEMPORARY TABLE操作。从 MySQL 8.0.13 开始,如果 binlog 格式为 ROW 或 MIXED,该限制被取消。 - 不能将 InnoDB 表和非 InnoDB 表放到一个事务内操作。
6. 在线开启 GTID 复制
步骤1:分别在主从上设置 ENFORCE_GTID_CONSISTENCY = WARN
观察一段时间,确保错误日志中没有生成警告。
-- 主库(141)执行SET@@GLOBAL.ENFORCE_GTID_CONSISTENCY=WARN;-- 从库(142)执行SET@@GLOBAL.ENFORCE_GTID_CONSISTENCY=WARN;步骤2:分别在主从上设置 ENFORCE_GTID_CONSISTENCY = ON
-- 主库(141)执行SET@@GLOBAL.ENFORCE_GTID_CONSISTENCY=ON;-- 从库(142)执行SET@@GLOBAL.ENFORCE_GTID_CONSISTENCY=ON;步骤3:分别在主从上设置 GTID_MODE = OFF_PERMISSIVE
次序任意。
-- 主库(141)执行SET@@GLOBAL.GTID_MODE=OFF_PERMISSIVE;-- 从库(142)执行SET@@GLOBAL.GTID_MODE=OFF_PERMISSIVE;步骤4:分别在主从上设置 GTID_MODE = ON_PERMISSIVE
-- 主库(141)执行SET@@GLOBAL.GTID_MODE=ON_PERMISSIVE;-- 从库(142)执行SET@@GLOBAL.GTID_MODE=ON_PERMISSIVE;步骤5:分别在主从上检查 ONGOING_ANONYMOUS_TRANSACTION_COUNT 的值为零
-- 主库(141)执行SHOWSTATUSLIKE'ONGOING_ANONYMOUS_TRANSACTION_COUNT';-- +-------------------------------------+-------+-- | Variable_name | Value |-- +-------------------------------------+-------+-- | Ongoing_anonymous_transaction_count | 0 |-- +-------------------------------------+-------+-- 从库(142)执行SHOWSTATUSLIKE'ONGOING_ANONYMOUS_TRANSACTION_COUNT';-- +-------------------------------------+-------+-- | Variable_name | Value |-- +-------------------------------------+-------+-- | Ongoing_anonymous_transaction_count | 0 |-- +-------------------------------------+-------+说明:该参数用来统计正在进行的匿名事务的数量,若为 0,则继续进行下一步。
步骤6:等待从库匿名事务应用完毕
首先,通过 show master status 获取主库当前二进制日志的位置点:
-- 主库(141)执行mysql>showmasterstatus;-- +------------------+----------+--------------+------------------+-------------------+-- | File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |-- +------------------+----------+--------------+------------------+-------------------+-- | mysql-bin.000004 | 157 | | | |-- +------------------+----------+--------------+------------------+-------------------+其次,在从库上执行 MASTER_POS_WAIT 函数:
-- 从库(142)执行mysql>selectMASTER_POS_WAIT('mysql-bin.000004',157);-- +-------------------------------------------+-- | MASTER_POS_WAIT('mysql-bin.000004',157) |-- +-------------------------------------------+-- | 0 |-- +-------------------------------------------+说明:该命令会一直阻塞,直到指定位置点的事务在从库上应用。返回 0 表示已应用完毕。
步骤7:分别在主从上设置 GTID_MODE = ON
-- 主库(141)执行setglobalgtid_mode=ON;-- 从库(142)执行setglobalgtid_mode=ON;步骤8:修改主从的配置文件,将 GTID 相关参数加上
主库 /etc/my.cnf(141)增加:
gtid_mode = ON enforce_gtid_consistency = ON完整配置文件:
[client] socket = /data/mysql/3306/data/mysql.sock [mysqld] basedir = /usr/local/mysql datadir = /data/mysql/3306/data user = mysql port = 3306 socket = /data/mysql/3306/data/mysql.sock log_error = /data/mysql/3306/data/mysqld.err log_timestamps = system log-bin = mysql-bin server-id = 1 gtid_mode = ON enforce_gtid_consistency = ON从库 /etc/my.cnf(142)增加:
gtid_mode = ON enforce_gtid_consistency = ON完整配置文件:
[client] socket = /data/mysql/3306/data/mysql.sock [mysqld] basedir = /usr/local/mysql datadir = /data/mysql/3306/data user = mysql port = 3306 socket = /data/mysql/3306/data/mysql.sock log_error = /data/mysql/3306/data/mysqld.err log_timestamps = system server-id = 2 gtid_mode = ON enforce_gtid_consistency = ON步骤9:将基于 binlog 位置点的复制修改为 GTID 复制
-- 从库(142)执行stop slave;change mastertomaster_auto_position=1;startslave;说明:使用 GTID 复制后,只需设置
MASTER_AUTO_POSITION = 1,无需指定MASTER_LOG_FILE和MASTER_LOG_POS。
验证 GTID 复制状态
-- 从库(142)执行showslavestatus\GSlave_IO_Running: Yes Slave_SQL_Running: Yes Seconds_Behind_Master: 0 Retrieved_Gtid_Set: Executed_Gtid_Set: d5728692-8354-11f1-8acf-000c29048d1f:1 Auto_Position: 1-- 主库(141)执行showvariableslike'%gtid%';gtid_mode = ON enforce_gtid_consistency = ON gtid_executed = d5728692-8354-11f1-8acf-000c29048d1f:1数据同步测试
-- 主库(141)执行INSERTINTOtest_rep.t1VALUES(2,'gtid_test');SELECT*FROMtest_rep.t1;-- +----+-------------+-- | id | name |-- +----+-------------+-- | 1 | master_data |-- | 2 | gtid_test |-- +----+-------------+-- 从库(142)执行SELECT*FROMtest_rep.t1;-- +----+-------------+-- | id | name |-- +----+-------------+-- | 1 | master_data |-- | 2 | gtid_test |-- +----+-------------+✅ GTID 复制开启后数据同步正常。
7. 在线关闭 GTID 复制
步骤1:将从库上基于 GTID 的复制修改为基于 binlog 位置点的复制
(1)关闭 slave
-- 从库(142)执行stop slave;(2)查看 show slave status 的值
-- 从库(142)执行showslavestatus\G获取Relay_Master_Log_File和Exec_Master_Log_Pos的值:
Relay_Master_Log_File: mysql-bin.000005 Exec_Master_Log_Pos: 448(3)执行 change master to 语句
-- 从库(142)执行change mastertomaster_auto_position=0,master_log_file='mysql-bin.000005',master_log_pos=448;(4)开启复制
-- 从库(142)执行startslave;验证:
Slave_IO_Running: Yes Slave_SQL_Running: Yes Seconds_Behind_Master: 0 Auto_Position: 0步骤2:分别在主从上设置 GTID_MODE = ON_PERMISSIVE
-- 主库(141)执行setglobalgtid_mode=ON_PERMISSIVE;-- 从库(142)执行setglobalgtid_mode=ON_PERMISSIVE;步骤3:分别在主从上设置 GTID_MODE = OFF_PERMISSIVE
-- 主库(141)执行setglobalgtid_mode=OFF_PERMISSIVE;-- 从库(142)执行setglobalgtid_mode=OFF_PERMISSIVE;步骤4:分别在主从上检查 gtid_owned 变量的值
-- 主库(141)执行select@@global.gtid_owned;-- +--------------------+-- | @@global.gtid_owned |-- +--------------------+-- | |-- +--------------------+-- 从库(142)执行select@@global.gtid_owned;-- +--------------------+-- | @@global.gtid_owned |-- +--------------------+-- | |-- +--------------------+如果为空,则继续进行下一步。
步骤5:等待所有的 GTID 事务应用完
基于 MASTER_POS_WAIT 函数:
-- 主库(141)执行showmasterstatus;-- +------------------+----------+--------------+------------------+----------------------------------------+-- | File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |-- +------------------+----------+--------------+------------------+----------------------------------------+-- | mysql-bin.000007 | 197 | | | d5728692-8354-11f1-8acf-000c29048d1f:1 |-- +------------------+----------+--------------+------------------+----------------------------------------+-- 从库(142)执行selectMASTER_POS_WAIT('mysql-bin.000007',197);-- +-------------------------------------------+-- | MASTER_POS_WAIT('mysql-bin.000007',197) |-- +-------------------------------------------+-- | 0 |-- +-------------------------------------------+步骤6:分别在主从上设置 GTID_MODE = OFF
-- 主库(141)执行setglobalgtid_mode=OFF;-- 从库(142)执行setglobalgtid_mode=OFF;步骤7:修改主从的配置文件,将 GTID 相关参数显式设置为 OFF
主库 /etc/my.cnf(141):
[client] socket = /data/mysql/3306/data/mysql.sock [mysqld] basedir = /usr/local/mysql datadir = /data/mysql/3306/data user = mysql port = 3306 socket = /data/mysql/3306/data/mysql.sock log_error = /data/mysql/3306/data/mysqld.err log_timestamps = system log-bin = mysql-bin server-id = 1 gtid_mode = OFF enforce_gtid_consistency = OFF从库 /etc/my.cnf(142):
[client] socket = /data/mysql/3306/data/mysql.sock [mysqld] basedir = /usr/local/mysql datadir = /data/mysql/3306/data user = mysql port = 3306 socket = /data/mysql/3306/data/mysql.sock log_error = /data/mysql/3306/data/mysqld.err log_timestamps = system server-id = 2 gtid_mode = OFF enforce_gtid_consistency = OFF验证关闭 GTID 后的状态
-- 主库(141)执行showvariableslike'%gtid%';-- gtid_mode = OFF-- enforce_gtid_consistency = OFF-- 从库(142)执行showslavestatus\G-- Slave_IO_Running: Yes-- Slave_SQL_Running: Yes-- Seconds_Behind_Master: 0-- Auto_Position: 0数据同步测试
-- 主库(141)执行INSERTINTOtest_rep.t1VALUES(3,'after_gtid_off');SELECT*FROMtest_rep.t1;-- +----+-----------------+-- | id | name |-- +----+-----------------+-- | 1 | master_data |-- | 2 | gtid_test |-- | 3 | after_gtid_off |-- +----+-----------------+-- 从库(142)执行SELECT*FROMtest_rep.t1;-- +----+-----------------+-- | id | name |-- +----+-----------------+-- | 1 | master_data |-- | 2 | gtid_test |-- | 3 | after_gtid_off |-- +----+-----------------+✅ 关闭 GTID 后主从复制仍然正常,数据同步 OK。
8. 当前最终状态
GTID 已重新在线开启,当前环境为 GTID 复制模式:
主库(141): gtid_mode = ON enforce_gtid_consistency = ON gtid_executed = d5728692-8354-11f1-8acf-000c29048d1f:1 从库(142): gtid_mode = ON enforce_gtid_consistency = ON Auto_Position = 1 Slave_IO_Running = Yes Slave_SQL_Running = Yes9. gtid_mode 修改顺序总结
| 操作 | 修改顺序 |
|---|---|
| 在线开启 GTID | OFF → OFF_PERMISSIVE → ON_PERMISSIVE → ON |
| 在线关闭 GTID | ON → ON_PERMISSIVE → OFF_PERMISSIVE → OFF |
注意:不能跳步修改,必须逐步进行。开启时 enforce_gtid_consistency 需先设为 WARN 观察,再设为 ON,最后再逐步修改 gtid_mode。