mysql GTID复制机制

MySQL 的 GTID(Global Transaction Identifier,全局事务标识符)复制机制是 MySQL 5.6 及以上版本引入的一种高级复制功能,旨在简化主从复制的管理,提高数据一致性和故障恢复的可靠性。相比传统的基于二进制日志位置(binlog position)的复制方式,GTID 复制通过为每个事务分配一个全局唯一标识符,极大地方便了复制的配置和维护。

GTID 复制的基本原理

GTID 是一个全局唯一的事务 ID,由两部分组成:

  • 服务器 UUID:每个 MySQL 实例有一个唯一的标识符,通常在服务器启动时生成,存储在 auto.cnf 文件中。
  • 事务序列号:一个递增的数字,表示该服务器上的事务顺序。

GTID 的格式通常是这样的:UUID:Transaction_ID,例如 3e11fa47-71ca-11e1-9e33-c80aa9429562:23

Transaction_id 是在该主库上生成的事务序列号,从1开始,1-2代表第二个事务;第1-n代表n个事务

           Retrieved_Gtid_Set: 4dfe51b2-f2b7-11ef-8924-0242c0a8d704:1-5
            Executed_Gtid_Set: 4a308329-f2b7-11ef-97f0-0242c0a8d703:1-2,
4dfe51b2-f2b7-11ef-8924-0242c0a8d704:1-5
4dfe51b2-f2b7-11ef-8924-0242c0a8d704:1-5

UUID: 4dfe51b2-f2b7-11ef-8924-0242c0a8d704
Transaction_ID: 1-5

在 GTID 复制中,主库(Master)上执行的每个事务都会被分配一个 GTID,并记录在二进制日志中。从库(Slave)通过读取主库的二进制日志,获取并应用这些带有 GTID 的事务。从库会跟踪已应用的 GTID 集合(gtid_executed),从而确保不会重复执行相同的事务。

GTID 复制的工作流程

  1. 主库端

    • 每次提交事务时,主库生成一个 GTID,并将其与事务一起记录到二进制日志中。
    • 二进制日志通过复制通道传输给从库。
  2. 从库端

    • 从库通过复制线程(IO 线程和 SQL 线程)读取主库的二进制日志。
    • 从库检查事务的 GTID 是否已经存在于自己的 gtid_executed 集合中。
    • 如果 GTID 未执行,从库应用该事务,并更新自己的 GTID 集合;如果已执行,则跳过。
  3. 一致性保障

    • GTID 确保事务在主从之间严格按照提交顺序应用,避免了传统复制中因日志位置偏移导致的不一致问题。

630513926c5905e5e3546394a3b2af0b.png

GTID 复制的优点

  • 简化故障切换:传统复制需要手动计算日志文件和位置,而 GTID 允许从库自动定位到正确的复制点,便于主从切换。
  • 数据一致性:GTID 保证事务只被应用一次,避免重复或遗漏。
  • 多源复制支持:GTID 在多主复制场景中更容易管理事务来源。
  • 易于监控和管理:通过 gtid_executedgtid_purged 等变量,可以清晰地了解复制状态。

gtid模式下binlog结构

498159c5e4acacb6501ce38d9b06d42f.png

➜  test mysqlbinlog mysql-bin.000001 
# The proper term is pseudo_replica_mode, but we use this compatibility alias
# to make the statement usable on server versions 8.0.24 and older.
/*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=1*/;
/*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/;
DELIMITER /*!*/;
# at 4
#250224 22:06:25 server id 3  end_log_pos 123 CRC32 0x2b74819b 	Start: binlog v 4, server v 5.7.44-log created 250224 22:06:25 at startup
ROLLBACK/*!*/;
BINLOG '
4Xy8Zw8DAAAAdwAAAHsAAAAAAAQANS43LjQ0LWxvZwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAADhfLxnEzgNAAgAEgAEBAQEEgAAXwAEGggAAAAICAgCAAAACgoKKioAEjQA
AZuBdCs=
'/*!*/;
# at 123
#250224 22:06:25 server id 3  end_log_pos 154 CRC32 0x558a01da 	Previous-GTIDs  
 ### 1.Previous-GTIDs代表的gtid集合是曾经的gtid,换句话说是被purge掉的事务


# [empty]
# at 154
#250224 22:10:16 server id 3  end_log_pos 219 CRC32 0xbb953763 	GTID	last_committed=0	sequence_number=1	rbr_only=no	original_committed_timestamp=0	immediate_commit_timestamp=0	transaction_length=0
# original_commit_timestamp=0 (1970-01-01 08:00:00.000000 CST)
# immediate_commit_timestamp=0 (1970-01-01 08:00:00.000000 CST)
/*!80001 SET @@session.original_commit_timestamp=0*//*!*/;
/*!80014 SET @@session.original_server_version=0*//*!*/;
/*!80014 SET @@session.immediate_server_version=0*//*!*/;
SET @@SESSION.GTID_NEXT= '4dfe51b2-f2b7-11ef-8924-0242c0a8d704:1'/*!*/; ### 2.purged 事物

# at 219
#250224 22:10:16 server id 3  end_log_pos 313 CRC32 0x101009d7 	Query	thread_id=2	exec_time=0	error_code=0
SET TIMESTAMP=1740406216/*!*/;
SET @@session.pseudo_thread_id=2/*!*/;
SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=0, @@session.unique_checks=1, @@session.autocommit=1/*!*/;
SET @@session.sql_mode=1436549152/*!80005 &~0x1003ff00*//*!*/;
SET @@session.auto_increment_increment=1, @@session.auto_increment_offset=1/*!*/;
/*!\C latin1 *//*!*/;
SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8/*!*/;
SET @@session.lc_time_names=0/*!*/;
SET @@session.collation_database=DEFAULT/*!*/;
create database gaga
/*!*/;
# at 313
#250224 22:12:25 server id 3  end_log_pos 378 CRC32 0x89b3e865 	GTID	last_committed=1	sequence_number=2	rbr_only=no	original_committed_timestamp=0	immediate_commit_timestamp=0	transaction_length=0
# original_commit_timestamp=0 (1970-01-01 08:00:00.000000 CST)
# immediate_commit_timestamp=0 (1970-01-01 08:00:00.000000 CST)
/*!80001 SET @@session.original_commit_timestamp=0*//*!*/;
/*!80014 SET @@session.original_server_version=0*//*!*/;
/*!80014 SET @@session.immediate_server_version=0*//*!*/;
SET @@SESSION.GTID_NEXT= '4dfe51b2-f2b7-11ef-8924-0242c0a8d704:2'/*!*/;  ### 3.新的事务的gtid信息,写在每个事务的前面

# at 378
#250224 22:12:25 server id 3  end_log_pos 479 CRC32 0xde92108b 	Query	thread_id=2	exec_time=0	error_code=0
use `gaga`/*!*/;
SET TIMESTAMP=1740406345/*!*/;
create table t2 (id int(4))   # 创建表
/*!*/;
# at 479
#250224 22:12:39 server id 3  end_log_pos 544 CRC32 0xa14d2919 	GTID	last_committed=2	sequence_number=3	rbr_only=yes	original_committed_timestamp=0	immediate_commit_timestamp=0	transaction_length=0
/*!50718 SET TRANSACTION ISOLATION LEVEL READ COMMITTED*//*!*/;
# original_commit_timestamp=0 (1970-01-01 08:00:00.000000 CST)
# immediate_commit_timestamp=0 (1970-01-01 08:00:00.000000 CST)
/*!80001 SET @@session.original_commit_timestamp=0*//*!*/;
/*!80014 SET @@session.original_server_version=0*//*!*/;
/*!80014 SET @@session.immediate_server_version=0*//*!*/;
SET @@SESSION.GTID_NEXT= '4dfe51b2-f2b7-11ef-8924-0242c0a8d704:3'/*!*/;
# at 544  ### 4.
#250224 22:12:39 server id 3  end_log_pos 616 CRC32 0x6d656f4e 	Query	thread_id=2	exec_time=0	error_code=0
SET TIMESTAMP=1740406359/*!*/;
BEGIN
/*!*/;
# at 616
#250224 22:12:39 server id 3  end_log_pos 661 CRC32 0x063fcfc8 	Table_map: `gaga`.`t2` mapped to number 113
# at 661
#250224 22:12:39 server id 3  end_log_pos 706 CRC32 0x4ecef684 	Write_rows: table id 113 flags: STMT_END_F

BINLOG '
V368ZxMDAAAALQAAAJUCAAAAAHEAAAAAAAEABGdhZ2EAAnQyAAEDAAHIzz8G
V368Zx4DAAAALQAAAMICAAAAAHEAAAAAAAEAAgAB//4BAAAA/t4AAACE9s5O
'/*!*/;
# at 706
#250224 22:12:39 server id 3  end_log_pos 737 CRC32 0x3e164934 	Xid = 7019
COMMIT/*!*/;
# at 737
#250224 22:17:30 server id 3  end_log_pos 760 CRC32 0x197523e6 	Stop
SET @@SESSION.GTID_NEXT= 'AUTOMATIC' /* added by mysqlbinlog */ /*!*/;
DELIMITER ;
# End of log file
/*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/;
/*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=0*/;

建立GTID复制方式

  • 1.基于gtid主动同步复制
  • 2.基于冷备份 + 自定义gtid复制开始位置
    621664bbf3327659c5b877ce17bfa396.png

注意事项

  • GTID 与非 GTID 的兼容性:如果从传统复制升级到 GTID,需要确保所有事务都转换为 GTID 模式。

  • 跳过错误事务:可以用 SET GTID_NEXT='specific_gtid'; 跳过有问题的 GTID。

  • 性能开销:GTID 会稍微增加日志大小和复制管理的开销,但在现代硬件上影响通常不大。

  • 执行过gtid mysql.gtid_executed

Refer