复制4 - GTID
一. GTID的介绍
- Global Transaction Identifier – 全局事物ID
- GTID = Server_UUID + Transaction_ID
- Server_UUID 是全局唯一的
- Transaction_ID 是自增的
- GTID 的作用是替代 Filename + Position
root@mysqldb 22:28: [(none)]> show variables like '%server_uuid%';
+---------------+--------------------------------------+
| Variable_name | Value |
+---------------+--------------------------------------+
| server_uuid | 3c993697-f4b8-11ed-a315-000c2953dece |
+---------------+--------------------------------------+
1 row in set (0.01 sec)
在MySQL中看到的 UUID ,实际是保存在 $DATADIR/auto.cnf 中的,且该文件是MySQL服务器初始化的时候自动生成的。
[root@MySQL-Master ~]# cat /data/mysql/auto.cnf
[auto]
server-uuid=3c993697-f4b8-11ed-a315-000c2953dece
通过冷备做备份,拷贝$DATADIR时,记得要把备份中的auto.cnf给删除
二. GTID的意义
- 假设现在没有GTID
-
- 当Master宕机后,一个Slave被提升为New Master,如果需要继续维持复制关系,就需要把另外两个Slave的CHANGE MASTER指向New Master;
- 那问题来了,原来Slave是指向Master的Filename_M + Position_M的位置,现在要指向New Master上新的Filename_N + Position_N的位置,这两个位置是比较难对应起来的;
- 此时两个Slave要继续复制(CHANGE MASTER)会比较麻烦。
- 使用GTID
-
- 和上面一样的场景,两个Slave需要重新指向New Master,由于使用了GTID,目前Slave-A获取到的日志对应的GTID=G_A,Slave-B 获取到的日志对应的GTID=G_B;
- 此时New Master上是存在G_A和G_B(通过选举出来的,获取的日志应该是最多的),那两个Slave就可以直接使用G_A和G_B这两个GTID,通过指向New Master接着继续复制;
三. GTID的配置
[mysqld]
log_bin = bin.log
gtid_mode = ON
log_slave_updates = 1 # MySQL 5.6 必须开启参数 log_slave_updates (5.6版本的限制),该参数用于在slave上生成binlog
enforce_gtid_consistency = 1
- MySQL 5.6 升级到gtid模式需要停机重启
- MySQL 5.7 版本开始可以不开启 log_slave_updates
- MySQL 5.7.6 版本开始可以在线升级成gtid模式
四. 基于GTID的复制
- 在开启GTID后,使用 mysqldump 备份单个数据库时,会有 Warning ,大致意思为你只备份了部分数据库,但是启用GTID后包含了所有的事物。可以忽略该警告。
- mysqldump文件中有sql语句: SET @@GLOBAL.GTID_PURGED='3c993697-f4b8-11ed-a315-000c2953dece:1-16';,表示为:这部分的GTIDs对应的事物已经purged,Slave在还原备份后,进行复制时,要跳过这些GTIDs(对应的事物),发生主从复制异常时,也可以临时用这个方式来解决。
五. 基于GTID搭建主从复制
用master_auto_position代替binlog具体信息,其他不变
- mysqldump出要复制的数据库
- 从库导入数据
- change master to MASTER_HOST='192.168.220.10', MASTER_USER='repl', MASTER_PASSWORD='123456',master_auto_position=1;
- start slave
root@mysqldb 09:52: [(none)]> show slave status\G
*************************** 1. row ***************************
Slave_IO_State: Waiting for master to send event
Master_Host: 192.168.220.10
Master_User: repl
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: binlog.000010
Read_Master_Log_Pos: 670
Relay_Log_File: relay.000002
Relay_Log_Pos: 405
Relay_Master_Log_File: binlog.000010
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
Replicate_Do_DB:
Replicate_Ignore_DB:
Replicate_Do_Table:
Replicate_Ignore_Table:
Replicate_Wild_Do_Table:
Replicate_Wild_Ignore_Table:
Last_Errno: 0
Last_Error:
Skip_Counter: 0
Exec_Master_Log_Pos: 670
Relay_Log_Space: 642
Until_Condition: None
Until_Log_File:
Until_Log_Pos: 0
Master_SSL_Allowed: No
Master_SSL_CA_File:
Master_SSL_CA_Path:
Master_SSL_Cert:
Master_SSL_Cipher:
Master_SSL_Key:
Seconds_Behind_Master: 0
Master_SSL_Verify_Server_Cert: No
Last_IO_Errno: 0
Last_IO_Error:
Last_SQL_Errno: 0
Last_SQL_Error:
Replicate_Ignore_Server_Ids:
Master_Server_Id: 11
Master_UUID: 3c993697-f4b8-11ed-a315-000c2953dece
Master_Info_File: mysql.slave_master_info
SQL_Delay: 0
SQL_Remaining_Delay: NULL
Slave_SQL_Running_State: Slave has read all relay log; waiting for more updates
Master_Retry_Count: 86400
Master_Bind:
Last_IO_Error_Timestamp:
Last_SQL_Error_Timestamp:
Master_SSL_Crl:
Master_SSL_Crlpath:
Retrieved_Gtid_Set:
Executed_Gtid_Set: 3c993697-f4b8-11ed-a315-000c2953dece:1-18
Auto_Position: 1 -- 表示使用GTID复制
Replicate_Rewrite_DB:
Channel_Name:
1 row in set (0.00 sec)
六. GTID与Filename-Pos的对应
在binlog中,多了一个GTID的event,如下所示
root@mysqldb 10:03: [test_1]> show binlog events in 'binlog.000010';
+---------------+------+----------------+-----------+-------------+--------------------------------------------------------------------+
| Log_name | Pos | Event_type | Server_id | End_log_pos | Info |
+---------------+------+----------------+-----------+-------------+--------------------------------------------------------------------+
| binlog.000010 | 4 | Format_desc | 11 | 123 | Server ver: 5.7.9-log, Binlog ver: 4 |
| binlog.000010 | 123 | Previous_gtids | 11 | 194 | 3c993697-f4b8-11ed-a315-000c2953dece:1-16 |
| binlog.000010 | 194 | Gtid | 11 | 259 | SET @@SESSION.GTID_NEXT= '3c993697-f4b8-11ed-a315-000c2953dece:17' | -- 一个GTID的event
| binlog.000010 | 259 | Query | 11 | 331 | BEGIN |
| binlog.000010 | 331 | Rows_query | 11 | 389 | # insert into test_1 values(NULL,10) |
| binlog.000010 | 389 | Table_map | 11 | 439 | table_id: 108 (test.test_1) |
| binlog.000010 | 439 | Write_rows | 11 | 483 | table_id: 108 flags: STMT_END_F |
| binlog.000010 | 483 | Xid | 11 | 514 | COMMIT /* xid=26 */ |
| binlog.000010 | 514 | Gtid | 11 | 579 | SET @@SESSION.GTID_NEXT= '3c993697-f4b8-11ed-a315-000c2953dece:18' |
| binlog.000010 | 579 | Query | 11 | 670 | use `test`; flush privileges |
| binlog.000010 | 670 | Gtid | 11 | 735 | SET @@SESSION.GTID_NEXT= '3c993697-f4b8-11ed-a315-000c2953dece:19' |
| binlog.000010 | 735 | Query | 11 | 809 | BEGIN |
| binlog.000010 | 809 | Rows_query | 11 | 857 | # insert into t1 values(2) |
| binlog.000010 | 857 | Table_map | 11 | 904 | table_id: 109 (test_1.t1) |
| binlog.000010 | 904 | Write_rows | 11 | 944 | table_id: 109 flags: STMT_END_F |
| binlog.000010 | 944 | Xid | 11 | 975 | COMMIT /* xid=94 */ |
| binlog.000010 | 975 | Gtid | 11 | 1040 | SET @@SESSION.GTID_NEXT= '3c993697-f4b8-11ed-a315-000c2953dece:20' |
| binlog.000010 | 1040 | Query | 11 | 1114 | BEGIN |
| binlog.000010 | 1114 | Rows_query | 11 | 1162 | # insert into t1 values(3) |
| binlog.000010 | 1162 | Table_map | 11 | 1209 | table_id: 109 (test_1.t1) |
| binlog.000010 | 1209 | Write_rows | 11 | 1249 | table_id: 109 flags: STMT_END_F |
| binlog.000010 | 1249 | Xid | 11 | 1280 | COMMIT /* xid=95 */ |
+---------------+------+----------------+-----------+-------------+--------------------------------------------------------------------+
22 rows in set (0.00 sec)
通过扫描binlog中的GTID值,就可以知道GTID与Filename-Pos对应的关系,但是如果binlog非常大,扫描的量也是会很大的,所以在binlog开头部分有一个Previous_gtids的event,如下所示:
root@mysqldb 10:06: [test_1]> show binlog events in 'binlog.000011'\G
*************************** 1. row ***************************
Log_name: binlog.000011
Pos: 4
Event_type: Format_desc
Server_id: 11
End_log_pos: 123
Info: Server ver: 5.7.9-log, Binlog ver: 4
*************************** 2. row ***************************
Log_name: binlog.000011
Pos: 123
Event_type: Previous_gtids -- 表示在此之前,GTID运行到的范围是哪里
Server_id: 11
End_log_pos: 194
Info: 3c993697-f4b8-11ed-a315-000c2953dece:1-20
*************************** 3. row ***************************
Log_name: binlog.000011
Pos: 194
Event_type: Gtid
Server_id: 11
End_log_pos: 259
Info: SET @@SESSION.GTID_NEXT= '3c993697-f4b8-11ed-a315-000c2953dece:21'
如果我要的GTID比Previous_gtids的大,就扫描当前文件,反之则扫描之前的文件,依次类推。
因为binlog在rotate(rotate events)的时候,是知道当前最大的GTID的,可以将该值写入到下一个新的binlog的开头,即Previous_gtids
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义