暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

​MySQL GTID介绍及搭建GTID从库

陶老师运维笔记 2019-12-16
3490

MySQL GTID介绍及搭建GTID从库

1. GTID 介绍

1.1 GTID概念

  • https://dev.mysql.com/doc/refman/5.6/en/replication-gtids-concepts.html

GTID (Global Transaction ID) 是对于一个已提交事务的编号,并且是一个全局唯一的编号。GTID 实际上 是由 UUID+TID 组成的。其中UUID 是一个 MySQL 实例的唯一标识,记录在$datadir/auto.cnf。TID 代表了该实例上已经提交的事务数量,并且随着事务提交单调递增。如下是GTID的几个具体形式:

  1. #GTID

  2. 3E11FA47-71CA-11E1-9E33-C80AA9429562:23

  3. #一组连续的事务可以用 - 连接的事务序号范围表示

  4. e6954592-8dba-11e6-af0e-fa163e1cf111:1-5

  5. #多个 MySQL 实例的事务,它们之间用逗号分隔。如果来自同一 MySQL 实例的事务序号有多个范围区间,各组范围之间用冒号分隔。

  6. e6954592-8dba-11e6-af0e-fa163e1cf111:1-5:11-18,

  7. e6954592-8dba-11e6-af0e-fa163e1cf3f2:1-27

GTID:

  • GTID 是由 UUID+TID 组成的,UUID标识MySQL实例,TID 代表该实例上已提交的事务数量。

  • GTID 集合可以包含来自多个 MySQL 实例的事务,它们之间用逗号分隔。

  • 一组连续的事务可以用 - 连接的事务序号范围表示。

  • 使用 SHOW MASTER STATUS 实时看当前的事务执行数。

1.2 GTID查看

可以用SHOW MASTER STATUS实时看当前的事务执行数。

  1. show global variables like '%gtid%';

  2. select @@server_uuid;

  3. +--------------------------------------+

  4. | @@server_uuid |

  5. +--------------------------------------+

  6. | a01f3a3f-1eee-11ea-b1e4-a0369fac2de4 |

  7. +--------------------------------------+

  8. show master status;

  9. +------------------+----------+--------------+------------------+-------------------------------------------+

  10. | File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |

  11. +------------------+----------+--------------+------------------+-------------------------------------------+

  12. | mysql-bin.000002 | 191 | | | a01f3a3f-1eee-11ea-b1e4-a0369fac2de4:1-14 |

  13. +------------------+----------+--------------+------------------+-------------------------------------------+

  14. show global variables like 'gtid_executed';

  15. +---------------+-------------------------------------------+

  16. | Variable_name | Value |

  17. +---------------+-------------------------------------------+

  18. | gtid_executed | a01f3a3f-1eee-11ea-b1e4-a0369fac2de4:1-14 |

  19. +---------------+-------------------------------------------+

MySQL5.7后还可以通过mysql.gtid_executed表来查看。

  1. SELECT * FROM mysql.gtid_executed;

  2. +--------------------------------------+----------------+--------------+

  3. | source_uuid | interval_start | interval_end |

  4. +--------------------------------------+----------------+--------------+

  5. | aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa | 1 | 40 |

  6. | aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa | 1000003 | 1000004 |

  7. | aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa | 2000003 | 2000006 |

  8. +--------------------------------------+----------------+--------------+

1.3 GTID配置开启

主要配置:

  • serverid:设置MySQL实例的serverid,每个server_id不能一样

  • gtid_mode=ON:MySQL实例开启GTID模式

  • enforcegtidconsitency=ON:使用GTID模式复制时,需要开启,用来保证数据一致性。

  • log-bin: MySQL必须要开启binlog

  • log-slave-updates=1:决定SLAVE从Master接收到更新且执行是否记录到SLAVE的binlog中

  • binlog_format=ROW: binlog格式为row

  • skip-slave-start=1(可选): 当SLAVE数据库启动的时候,SLAVE不会启动复制

配置示例:

  1. #假定port为3106

  2. [mysqld]

  3. datadir=/data1/mysql_3106

  4. socket=/tmp/mysql3106.sock

  5. log-bin=mysql-bin # mysql 5.6必须项,mysql 5.7非必须项

  6. sync-binlog=1 # 建议项

  7. binlog_format=row # 建议项

  8. relay-log=relay-bin # 必须项

  9. server-id=413106 #必须项,不能和其它实例相同

  10. log-error=mysqld_error.log

  11. pid-file=mysqld.pid


  12. log-slave-updates = 1 #mysql5.6 必须

  13. enforce_gtid_consistency=on # 必须项

  14. gtid_mode=on # 必须项

查看情况:

  1. ## 开启GTID

  2. show global variables like '%gtid%';

  3. +---------------------------------+-------------------------------------------+

  4. | Variable_name | Value |

  5. +---------------------------------+-------------------------------------------+

  6. | binlog_gtid_simple_recovery | OFF |

  7. | enforce_gtid_consistency | ON |

  8. | gtid_executed | a01f3a3f-1eee-11ea-b1e4-a0369fac2de4:1-14 |

  9. | gtid_mode | ON |

  10. | gtid_owned | |

  11. | gtid_purged | |

  12. | simplified_binlog_gtid_recovery | OFF |

  13. +---------------------------------+-------------------------------------------+

1.4 GTID作用

主要有以下两点:

  • 根据 GTID 可以知道事务最初是在哪个实例上提交的

  • GTID 的存在方便了 Replication 的 Failover

MySQL 5.6 的 GTID 出现以前 Replication Failover 的操作过程。假设我们有一个如下图的环境:

此时,Server A 的服务器宕机,需要将业务切换到 Server B 上。同时,我们又需要将 Server C 的复制源改成 Server B。复制源修改的命令语法很简单即:

  1. CHANGE MASTER TO MASTER_HOST='xxx', MASTER_LOG_FILE='xxx', MASTER_LOG_POS=nnnn;

这种方式的难点在于,由于同一个事务在每台机器上所在的 binlog 名字和位置都不一样,那么怎么找到 Server C 当前同步停止点对应 Server B 上 masterlogfile 和 masterlogpos 的位置就成为了难题。

MySQL5.6 的 GTID 出现后,就显得非常的简单。由于同一事务的 GTID 在所有节点上的值一致,那么根据 Server C 当前停止点的 GTID 就能唯一定位到 Server B 上的GTID。甚至由于 MASTERAUTOPOSITION 功能的出现,我们都不需要知道 GTID 的具体值。直接使用以下命令就可以直接完成 Failover 的工作。

  1. CHANGE MASTER TO MASTER_HOST='xxx', MASTER_AUTO_POSITION=='xxx'

1.5 GTID复制限制

GTID的复制依赖于事务,因此在使用时不支持MySQL中可用的某些功能。

  • 非事务性存储引擎的更新 同一事务中不能同时更新事务表与非事务表(MyISAM),建议都选择 Innodb 作为默认的数据库引擎。


  • CREATE TABLE … SELECT 语句 CREATE TABLE … SELECT对于基于语句的复制是不安全的。使用基于行的复制时,此语句实际上记录为两个单独的事件 - 一个用于创建表,另一个用于将源表中的行插入刚刚创建的新表中。当在事务中执行此语句时,在某些情况下,这两个事件可能会接收相同的事务标识符,这意味着slave将跳过包含插入的事务。因此,使用基于GTID的复制时不支持CREATE TABLE … SELECT。

  • 临时表 使用GTID时(即,enforcegtidconsistency系统变量设置为ON时),事务,过程,函数和触发器内不支持CREATE TEMPORARY TABLE和DROP TEMPORARY TABLE语句。可以在启用GTID的情况下使用这些语句,但仅限于任何事务之外,并且仅使用autocommit = 1。

  • 防止执行不受支持的语句

         要防止执行会导致基于GTID的复制失败的语句,必须在启用GTID时使用–               enforce-gtid-consistency选项启动所有服务器。

  • 跳过事务 使用GTID时不支持sql slave skip counter。如果您需要跳过事务,请使用master的gtidexecuted变量的值; 有关详细信息,请参考 https://dev.mysql.com/doc/refman/5.7/en/replication-gtids-failover.html#replication-gtids-failover-empty

2. GTID工作原理

2.1 GTID 生命周期

master 更新数据时,会在事务前产生 GTID, 并记录到binlog日志中

slave 端的 i/o 线程将变更的 binlog,写入到本地的 relay log 中,读取值是根据 gitd_next变量
,告诉我们slave下一个执行哪个GTID。

sql 线程从 relay log 中获取 GTID,然后对比 slave 端的 binlog 是否有记录。如果有记录,说明该 GTID 的事务已经执行,slave 会忽略。如果没有记录,slave 就会从 relay log 中执行该 GTID 的事务,并记录到 binlog。

在解析过程中会判断是否有主键,如果没有就用二级索引,如果没有二级索引就用全部扫描。

GTID的生命周期:

  1. 客户端发送DDL/DML给master上,master首先对此事务生成一个唯一的gtid,假如为uuid_xxx:1,然后立即执行该事务中的操作。主从复制的情况下,sync-binlog基本上都会设置为1,这表示在每次提交事务时将缓存中的binlog刷盘。所以,在事务提交前,gtid以及事务相关操作的信息都在缓存中,提交后它们才写入到binlog file中,然后才会被dump线程dump出去。即只有提交了的事务,gtid和对应的事务操作才会记录到binlog文件中。记录的格式是先记录gtid,紧跟着再记录事务相关的操作。

  2. 当binlog传送到relay log中后,slave上的SQL线程首先读取该gtid,并 设置变量 gtidnext 的值为该gtid,表示下一个要操作的事务是该gtid。gtidnext 是基于会话的,不同会话的gtid_next不同。  

  3. 随后slave检测该gtid在自己的binlog中是否存在。如果存在,则放弃此gtid事务;如果不存在,则将此gtid写入到自己的binlog中,然后立刻执行该事务,并在自己的binlog中记录该事务相关的操作。注意,slave上replay的时候,gtid不是提交后才写到自己的binlog file的,而是判断gtid不存在后立即写入binlog file。通过这种在执行事务前先检查并写gtid到binlog的机制,不仅可以保证当前会话在此之前没有执行过该事务,还能保证没有其他会话读取了该gtid却没有提交。因为如果其他会话读取了该gtid会立即写入到binlog(不管是否已经开始执行事务),所以当前会话总能读取到binlog中的该gtid,于是当前会话就会放弃该事务。总之,一个gtid事务是决不允许多次执行、多个会话并行执行的。

  4. SLAVE不生成GTIDslave在重放relay log中的事务时,不会自己生成gtid,所以所有的slave(无论是何种方式的一主一从或一主多从复制架构)通过重放relay log中事务获取的gtid都来源于master,并永久保存在slave上。

2.2 GTID生成示例

GTID 的生成受 gtidnext 控制。在主服务器上gtidnext 是默认的 AUTOMATIC,即在每次事务提交时自动生成新的 GTID 。它从当前已执行的 GTID 集合(即 gtidexecuted )中,找一个大于 0 的未使用的最小值作为下个事务 GTID 。同时在 Binlog 的实际的更新事务事件前面插入一条 set gtidnext 事件。

这里以一条 insert 语句来看看 GTID 的生成过程:

Master:

  1. #操作前

  2. 192.110.103.41 : test > select @@server_uuid;

  3. +--------------------------------------+

  4. | @@server_uuid |

  5. +--------------------------------------+

  6. | a01f3a3f-1eee-11ea-b1e4-a0369fac2de4 |

  7. +--------------------------------------+

  8. 192.110.103.41 : test > flush logs;

  9. test>show master logs;

  10. +------------------+-----------+

  11. | Log_name | File_size |

  12. +------------------+-----------+

  13. ...

  14. | mysql-bin.000005 | 191 |

  15. +------------------+-----------+


  16. 192.110.103.41 : test > show master status;

  17. +------------------+----------+--------------+------------------+-------------------------------------------+

  18. | File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |

  19. +------------------+----------+--------------+------------------+-------------------------------------------+

  20. | mysql-bin.000005 | 191 | | | a01f3a3f-1eee-11ea-b1e4-a0369fac2de4:1-25 |

  21. +------------------+----------+--------------+------------------+-------------------------------------------+

  22. 1 row in set (0.00 sec)


  23. ## insert

  24. 192.110.103.41 : test > insert into t1 values(2,'li4');

  25. Query OK, 1 row affected (0.00 sec)


  26. 192.110.103.41 : test > show master status;

  27. +------------------+----------+--------------+------------------+-------------------------------------------+

  28. | File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |

  29. +------------------+----------+--------------+------------------+-------------------------------------------+

  30. | mysql-bin.000005 | 434 | | | a01f3a3f-1eee-11ea-b1e4-a0369fac2de4:1-26 |

  31. +------------------+----------+--------------+------------------+-------------------------------------------+

  32. 1 row in set (0.00 sec)


  33. 192.110.103.41 : test > show binlog events in 'mysql-bin.000005';

  34. +------------------+-----+----------------+-----------+-------------+--------------------------------------------------------------------+

  35. | Log_name | Pos | Event_type | Server_id | End_log_pos | Info |

  36. +------------------+-----+----------------+-----------+-------------+--------------------------------------------------------------------+

  37. | mysql-bin.000005 | 4 | Format_desc | 103413106 | 120 | Server ver: 5.6.27-log, Binlog ver: 4 |

  38. | mysql-bin.000005 | 120 | Previous_gtids | 103413106 | 191 | a01f3a3f-1eee-11ea-b1e4-a0369fac2de4:1-25 |

  39. | mysql-bin.000005 | 191 | Gtid | 103413106 | 239 | SET @@SESSION.GTID_NEXT= 'a01f3a3f-1eee-11ea-b1e4-a0369fac2de4:26' |

  40. | mysql-bin.000005 | 239 | Query | 103413106 | 311 | BEGIN |

  41. | mysql-bin.000005 | 311 | Table_map | 103413106 | 359 | table_id: 78 (test.t1) |

  42. | mysql-bin.000005 | 359 | Write_rows | 103413106 | 403 | table_id: 78 flags: STMT_END_F |

  43. | mysql-bin.000005 | 403 | Xid | 103413106 | 434 | COMMIT /* xid=132 */ |

  44. +------------------+-----+----------------+-----------+-------------+--------------------------------------------------------------------+

  45. 7 rows in set (0.01 sec)

SLAVE:

在从库上回放主库的 Binlog 时,先执行 SET @@SESSION.GTID_NEXT语句,然后再执行 insert 语句,确保在主和备上这条 insert 对应于相同的 GTID。

  1. #slave上信息

  2. show master logs;

  3. +------------------+-----------+

  4. | Log_name | File_size |

  5. +------------------+-----------+

  6. | mysql-bin.000001 | 5762 |

  7. ...

  8. | mysql-bin.000004 | 425 |

  9. +------------------+-----------+

  10. 4 rows in set (0.01 sec)

  11. 192.110.103.42 : test > show binlog events in 'mysql-bin.000004';

  12. +------------------+-----+----------------+-----------+-------------+--------------------------------------------------------------------+

  13. | Log_name | Pos | Event_type | Server_id | End_log_pos | Info |

  14. +------------------+-----+----------------+-----------+-------------+--------------------------------------------------------------------+

  15. | mysql-bin.000004 | 4 | Format_desc | 103423106 | 120 | Server ver: 5.6.27-log, Binlog ver: 4 |

  16. | mysql-bin.000004 | 120 | Previous_gtids | 103423106 | 191 | a01f3a3f-1eee-11ea-b1e4-a0369fac2de4:1-25 |

  17. | mysql-bin.000004 | 191 | Gtid | 103413106 | 239 | SET @@SESSION.GTID_NEXT= 'a01f3a3f-1eee-11ea-b1e4-a0369fac2de4:26' |

  18. | mysql-bin.000004 | 239 | Query | 103413106 | 302 | BEGIN |

  19. | mysql-bin.000004 | 302 | Table_map | 103413106 | 350 | table_id: 72 (test.t1) |

  20. | mysql-bin.000004 | 350 | Write_rows | 103413106 | 394 | table_id: 72 flags: STMT_END_F |

  21. | mysql-bin.000004 | 394 | Xid | 103413106 | 425 | COMMIT /* xid=124 */ |

  22. +------------------+-----+----------------+-----------+-------------+--------------------------------------------------------------------+

  23. 7 rows in set (0.00 sec)


  24. 192.110.103.42 : test > show slave status\G

  25. *************************** 1. row ***************************

  26. Slave_IO_State: Waiting for master to send event

  27. Master_Host: 192.110.103.41

  28. Master_User: repl

  29. Master_Port: 3106

  30. Connect_Retry: 60

  31. Master_Log_File: mysql-bin.000005

  32. Read_Master_Log_Pos: 434

  33. Relay_Log_File: relay-bin.000013

  34. Relay_Log_Pos: 550

  35. Relay_Master_Log_File: mysql-bin.000005

  36. Slave_IO_Running: Yes

  37. Slave_SQL_Running: Yes

  38. Exec_Master_Log_Pos: 434

  39. Relay_Log_Space: 998

  40. Seconds_Behind_Master: 0

  41. Master_Server_Id: 103413106

  42. Master_UUID: a01f3a3f-1eee-11ea-b1e4-a0369fac2de4

  43. Master_Info_File: /data1/mysql_3106/master.info

  44. Slave_SQL_Running_State: Slave has read all relay log; waiting for the slave I/O thread to update it

  45. Retrieved_Gtid_Set: a01f3a3f-1eee-11ea-b1e4-a0369fac2de4:1-26

  46. Executed_Gtid_Set: a01f3a3f-1eee-11ea-b1e4-a0369fac2de4:1-26

  47. Auto_Position: 1

2.3 常用GTID参数说明

2.3.1 GTID重要的变量

1) gtidexecuted 

 在当前实例上已执行过的 GTID 集合,实际上包含了所有记录到 binlog 中的事务。设置 set sqllogbin=0 后执行的事务不会生成 binlog 事件,也不会被记录到 gtidexecuted 中。执行 RESET MASTER 可以将gtid_executed变量置空。

2)gtidpurged

gtidpurged表示已经purge掉的gtid。只有 gtidexecuted 为空时才能手动设置该变量,此时会同时更新 gtidexecuted 为和 gtidpurged 相同的值。(gtidexecuted 为空意味着要么之前没有启动过基于 GTID 的复制,要么执行过 RESET MASTER。执行 RESET MASTER 时同样也会把 gtidpurged 置空,即始终保持 gtidpurged 是 gtidexecuted 的子集。)在slave上设置该项时,表示稍后启动io线程和SQL线程都跳过这些gtid,slave上设置时应该让此项的gtid集合等于master上 gtidexecuted 的值。

binlog 不可能永远驻留在服务上,需要定期进行清理(通过 expirelogsdays 定期清理)日志。gtidpurged系统变量(@@global.gtidpurged)用于记录本机上已经执行过,但是已经被清除了的 binlog 事务集合。 它是 gtid_executed 的子集。

以下类别的GTID在此gtid_purged集合中:

  • 在slave上禁用binlog提交的复制事务的GTID

  • 已写入已清除的binlog的事务的GTID

  • 由语句SET @@global.gtid_purged明确添加到集合中的GTID

3) gtid_next

会话级变量,指示如何产生下一个GTID。可能的取值如下:

项目说明
AUTOMATIC自动生成下一个 GTID,实现上是分配一个当前实例上尚未执行过的序号最小的 GTID。
ANONYMOUS设置后执行事务不会产生GTID。
显式指定的GTID可以指定任意形式合法的 GTID 值,但不能是当前 gtid_executed 中的已经包含的 GTID,否则下次执行事务时会报错。

2.3.2 show slave status中gtid说明

  1. 192.110.103.42 : test > show slave status\G

  2. *************************** 1. row ***************************

  3. Slave_IO_State: Waiting for master to send event

  4. Master_Host: 192.110.103.41

  5. ...

  6. Master_Log_File: mysql-bin.000005

  7. Exec_Master_Log_Pos: 434

  8. Master_UUID: a01f3a3f-1eee-11ea-b1e4-a0369fac2de4

  9. Retrieved_Gtid_Set: a01f3a3f-1eee-11ea-b1e4-a0369fac2de4:1-26

  10. Executed_Gtid_Set: a01f3a3f-1eee-11ea-b1e4-a0369fac2de4:1-26

  11. Auto_Position: 1

  • RetrievedGtidSet:在开启了gtid复制(即gtid_mode=on)时,slave在启动io线程的时候会检查自己的relay log,并从中检索出gtid集合。也就是说,这代表的是slave已经从master中复制了哪些事务过来。检索出来的gtid不会再请求master发送过来。

  • ExecutedGtidSet:在开启了gtid复制(即gtid_mode=on)时,它表示已经向自己的binlog中写入了哪些gtid集合。注意,这个值是根据一些状态信息计算出来的,并非binlog中能看到的那些。

  • Auto_Position:开启gtid时是否自动获取binlog坐标。1表示开启,这是gtid复制的默认值。

2.3.3 binlog中gtid说明

用slave机器上binlog示例做gtid说明。

  1. #slave机器上binlog示例.

  2. /usr/local/mysql-5.6.27/bin/mysqlbinlog mysql-bin.000003

  3. /*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=1*/;

  4. # at 4

  5. #191215 19:18:43 server id 103423106 end_log_pos 120 CRC32 0x8d6b28f2 Start: binlog v 4, server v 5.6.27-log created 191215 19:18:43

  6. BINLOG '

  7. kxb2XQ+BHCoGdAAAAHgAAAAAAAQANS42LjI3LWxvZwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

  8. AAAAAAAAAAAAAAAAAAAAAAAAEzgNAAgAEgAEBAQEEgAAXAAEGggAAAAICAgCAAAACgoKGRkAAfIo

  9. a40=

  10. '/*!*/;

  11. # at 120

  12. #191215 19:18:43 server id 103423106 end_log_pos 191 CRC32 0xfaf65b70 Previous-GTIDs

  13. # a01f3a3f-1eee-11ea-b1e4-a0369fac2de4:1-24 ### 行1

  14. # at 191

  15. #191215 19:19:08 server id 103413106 end_log_pos 239 CRC32 0xf260d744 GTID [commit=yes] ### 行2

  16. SET @@SESSION.GTID_NEXT= 'a01f3a3f-1eee-11ea-b1e4-a0369fac2de4:25'/*!*/; ###行3

  17. # at 239

  18. #191215 19:19:08 server id 103413106 end_log_pos 302 CRC32 0xd6f210a9 Query thread_id=12 exec_time=0 error_code=0

  19. SET TIMESTAMP=1576408748/*!*/;

  20. ...

  21. BEGIN

  22. /*!*/;

  23. # at 302

  24. #191215 19:19:08 server id 103413106 end_log_pos 350 CRC32 0x5970d846 Table_map: `test`.`t1` mapped to number 72

  25. # at 350

  26. #191215 19:19:08 server id 103413106 end_log_pos 394 CRC32 0x36e14e8a Delete_rows: table id 72 flags: STMT_END_F


  27. BINLOG '

  28. rBb2XRNx9SkGMAAAAF4BAAAAAEgAAAAAAAEABHRlc3QAAnQxAAIDDwKWAABG2HBZ

  29. rBb2XSBx9SkGLAAAAIoBAAAAAEgAAAAAAAEAAgAC//wCAAAAA2xpNIpO4TY=

  30. '/*!*/;

  31. # at 394

  32. #191215 19:19:08 server id 103413106 end_log_pos 425 CRC32 0x68da9583 Xid = 113

  33. COMMIT/*!*/;

  34. SET @@SESSION.GTID_NEXT= 'AUTOMATIC' /* added by mysqlbinlog */ /*!*/; ## 行6

  35. # at 425

  36. #191215 20:20:39 server id 103423106 end_log_pos 472 CRC32 0x1a938cf2 Rotate to mysql-bin.000004 pos: 4

  37. DELIMITER ;

  38. # End of log file

  39. ROLLBACK /* added by mysqlbinlog */;

  40. /*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/;

  41. /*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=0*/;

  • "注意行1"中Previous-GTIDs代表的gtid集合是曾经的gtid,换句话说是被purge掉的事务。

  • "注意行2"是两个事务的gtid信息。它们写在每个事务的前面。

  • "注意行3"设置了GTID_NEXT的值,表示读取到了该事务后,那么必须要执行的是稍后列出的这个事务。

  • "注意行6"是在所有事务执行结束时设置的,表示自动获取gtid的值。它对复制是隐身的(也就是说不会dump线程不会将它dump出去),该行的结尾也说了,这一行是mysqlbinlog添加的。

3. 搭建GTID复制主从

全新环境搭建GTID主从复制。主要步骤:

  • 安装MySQL: 安装MySQL软件.

  • 配置文件修改: 在my.cnf中配置gtidmode=ON,logslaveupdates,enforcegtid_consistency等参数。

  • 启动MySQL: 修改配置后,启动MySQL。

  • 配置主从关系: change master建立GTID主从复制关系。

3.1 安装MySQL

安装MySQL软件,详细步骤见官方参考。

https://dev.mysql.com/doc/refman/5.6/en/binary-installation.html

3.2 修改配置支持GTID

本实验的MySQL ,Master实例ip为192.110.103.41,port为3106。从库为ip为192.110.103.42,port为3106。1)Master配置示例:

  1. #假定port为3106

  2. [mysqld]

  3. datadir=/data1/mysql_3106

  4. socket=/tmp/mysql3106.sock

  5. log-bin=mysql-bin # mysql 5.6必须项,mysql 5.7非必须项

  6. sync-binlog=1 # 建议项

  7. binlog_format=row # 建议项

  8. relay-log=relay-bin # 必须项

  9. server-id=413106 #必须项,不能和其它实例相同

  10. log-error=mysqld_error.log

  11. pid-file=mysqld.pid


  12. log-slave-updates = 1 #mysql5.6 必须,mysql5.7非必须

  13. enforce_gtid_consistency=on # 必须项

  14. gtid_mode=on # 必须项

2)Slave配置示例:

  1. #port为3106

  2. [mysqld]

  3. datadir=/data1/mysql_3106

  4. socket=/tmp/mysql3106.sock

  5. log-bin=mysql-bin # mysql 5.6必须项,mysql 5.7非必须项

  6. sync-binlog=1 # 建议项

  7. binlog_format=row # 建议项

  8. relay-log=relay-bin # 必须项

  9. server-id=423106 # 必须项,不能和其它实例相同

  10. log-error=mysqld_error.log

  11. pid-file=mysqld.pid


  12. log-slave-updates = 1 #mysql5.6 必须,mysql5.7非必须

  13. enforce_gtid_consistency=on # 必须项

  14. gtid_mode=on # 必须项

log-slave-updates = 1 选项会增大了从服务器的IO负载, 在MySQL5.7版本已非必须。

3.3 启动MySQL

  1. su - mysql -c "/usr/local/mysql/bin/mysqld_safe --defaults-file=/data1/mysql_3106/etc/my.cnf &"

3.4 创建复制账号

在master上创建一个用于复制的用户repl。

  1. # master上执行

  2. GRANT SUPER,REPLICATION CLIENT, REPLICATION SLAVE ON *.* TO repl@'192.%.%.%' identified by 'repl';

3.5 建立主从关系

在从库上执行change Master,以建立主从关系,因为master上的binlog没有删除过,所以在slave上直接change master to配置连接参数。注意: MySQL5.6和MySQL5.7 change语法略有区别。

  1. # MySQL5.6slave上执行

  2. #reset slave all;

  3. reset master;

  4. CHANGE MASTER TO MASTER_HOST='192.110.103.41', MASTER_PORT=3106, MASTER_USER='repl', MASTER_PASSWORD='repl',MASTER_AUTO_POSITION = 1;

  5. start slave;

  6. show slave status\G


  7. ## MySQL5.7 slave命令

  8. #MySQL 5.7,没有在change master to语句中加入user和password项,而是在start slave语句中使用,否则会警告。

  9. change master to master_host='192.110.103.41',master_port=3106,master_auto_position=1;

  10. start slave user='repl' password='repl';

  11. show slave status\G

3.6 检查验证

检查GTID情况

  1. ## 开启GTID

  2. #show global variables like '%gtid%';

  3. #Master实例上

  4. 192.110.103.41 : (none) > show master status;

  5. +------------------+----------+--------------+------------------+-------------------------------------------+

  6. | File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |

  7. +------------------+----------+--------------+------------------+-------------------------------------------+

  8. | mysql-bin.000002 | 1233 | | | a01f3a3f-1eee-11ea-b1e4-a0369fac2de4:1-19 |

  9. +------------------+----------+--------------+------------------+-------------------------------------------+

  10. 1 row in set (0.00 sec)


  11. 192.110.103.41 : (none) > show global variables like '%gtid%';

  12. +---------------------------------+-------------------------------------------+

  13. | Variable_name | Value |

  14. +---------------------------------+-------------------------------------------+

  15. | binlog_gtid_simple_recovery | OFF |

  16. | enforce_gtid_consistency | ON |

  17. | gtid_executed | a01f3a3f-1eee-11ea-b1e4-a0369fac2de4:1-19 |

  18. | gtid_mode | ON |

  19. | gtid_owned | |

  20. | gtid_purged | |

  21. | simplified_binlog_gtid_recovery | OFF |

  22. +---------------------------------+-------------------------------------------+


  23. ## slave 实例上

  24. root@127.0.0.1 : (none) > show master status;

  25. +------------------+----------+--------------+------------------+-------------------------------------------+

  26. | File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |

  27. +------------------+----------+--------------+------------------+-------------------------------------------+

  28. | mysql-bin.000001 | 5261 | | | a01f3a3f-1eee-11ea-b1e4-a0369fac2de4:1-19 |

  29. +------------------+----------+--------------+------------------+-------------------------------------------+

  30. 1 row in set (0.00 sec)

查看主从同步情况:

  1. root@127.0.0.1 : (none) > show slave status\G

  2. *************************** 1. row ***************************

  3. Slave_IO_State: Waiting for master to send event

  4. Master_Host: 192.110.103.41

  5. Master_User: repl

  6. Master_Port: 3106

  7. Connect_Retry: 60

  8. Master_Log_File: mysql-bin.000002

  9. Read_Master_Log_Pos: 1233

  10. Relay_Log_File: relay-bin.000004

  11. Relay_Log_Pos: 1443

  12. Relay_Master_Log_File: mysql-bin.000002

  13. Slave_IO_Running: Yes

  14. Slave_SQL_Running: Yes

  15. Replicate_Wild_Ignore_Table:

  16. Last_Errno: 0

  17. Last_Error:

  18. Skip_Counter: 0

  19. Exec_Master_Log_Pos: 1233

  20. Relay_Log_Space: 1728

  21. Until_Condition: None

  22. Seconds_Behind_Master: 0

  23. Master_Server_Id: 103413106

  24. Master_UUID: a01f3a3f-1eee-11ea-b1e4-a0369fac2de4

  25. Master_Info_File: /data1/mysql_3106/master.info

  26. SQL_Delay: 0

  27. SQL_Remaining_Delay: NULL

  28. Slave_SQL_Running_State: Slave has read all relay log; waiting for the slave I/O thread to update it

  29. Master_Retry_Count: 86400

  30. ...

  31. Master_SSL_Crlpath:

  32. Retrieved_Gtid_Set: a01f3a3f-1eee-11ea-b1e4-a0369fac2de4:1-19

  33. Executed_Gtid_Set: a01f3a3f-1eee-11ea-b1e4-a0369fac2de4:1-19

  34. Auto_Position: 1

  35. 1 row in set (0.00 sec)

验证数据:

  1. #master

  2. create table if not exists t1 (id int(10) PRIMARY KEY AUTO_INCREMENT,name varchar(50) NOT NULL);

  3. insert into t1 values(1,'zhang3');

  4. #slave

  5. select * from t1;

  6. +----+--------+

  7. | id | name |

  8. +----+--------+

  9. | 1 | zhang3 |

  10. +----+--------+

4. 添加新的slave到gtid复制集群

线上环境,往往会定期删除一部分binlog。咱们模似这种情况下从库制作。

当master没有删除过任何binlog时,可以方便地向复制结构中添加新的slave,因为slave会复制所有的binlog到自己relay log中并replay。即类似上节的命令即可 change master to masterhost='xxx',masterport=3xx,masterautoposition=1;

当master删除过一部分binlog后,在向复制结构中添加新的slave时,必须先获取到master binlog中当前已记录的第一个gtid之前的所有数据,然后恢复到slave上。只有slave上具有了这部分基准数据,才能保证和master的数据一致性。

4.1 在master实例上删除binlog

master实例用 purge master logs to 'xxx';来清理binlog。

  1. #master上执行

  2. >flush logs;

  3. >show master logs;

  4. +------------------+-----------+

  5. | Log_name | File_size |

  6. +------------------+-----------+

  7. | mysql-bin.000001 | 4266 |

  8. ...

  9. | mysql-bin.000005 | 481 |

  10. | mysql-bin.000006 | 191 |

  11. +------------------+-----------+

  12. >purge master logs to 'mysql-bin.000006';

  13. test > show master logs;

  14. +------------------+-----------+

  15. | Log_name | File_size |

  16. +------------------+-----------+

  17. | mysql-bin.000006 | 191 |

  18. +------------------+-----------+

  19. 1 row in set (0.00 sec)

  20. 192.110.103.41 : test > show master status;

  21. +------------------+----------+--------------+------------------+-------------------------------------------+

  22. | File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |

  23. +------------------+----------+--------------+------------------+-------------------------------------------+

  24. | mysql-bin.000006 | 191 | | | a01f3a3f-1eee-11ea-b1e4-a0369fac2de4:1-26 |

  25. +------------------+----------+--------------+------------------+-------------------------------------------+

4.2 GTID从库搭建步骤

使用骏马金龙老师的MGR图来说明搭建过程:

来源: 骏马金龙MGR介绍 https://www.cnblogs.com/f-ck-need-u/p/9164823.html

假如当前master的gtid为A3,已经purge掉的gtid为"1-->A1",备份到slave上的数据为1-A2部分。

如果A1 = 0,表示master的binlog没有被Purge过。slave可以直接开启gtid复制,但这样可能速度较慢,因为slave要复制所有binlog。也可以将master数据备份到slave上,然后设置 gtid_purged 跳过备份结束时的gtid,这样速度较快。

如果A1 != 0,表示master上的binlog中删除了一部分gtid。此时slave上必须先从master处恢复purge掉的那部分日志对应的数据。上图中备份结束时的GTID为A2。然后slave开启复制,唯一需要考虑的是"是否需要设置 gtid_purged 跳过一部分gtid以避免重复执行"。

备份数据到slave上,方式可以是mysqldump、冷备份、xtrabackup备份都行。由于gtid复制的特性,所需要的操作都很少,也很简单,前提是理解了"gtid的生命周期"。

4.3 用mysqldump搭建GTID从库

1)安装MySQL

在需要制作从库的机器上安装MySQL并开启GTID。

2)开启GTID

开启GTID配置,并启动MySQL服务。

3)制做全量备份

在主库上用mysqldump做一个全量备份,这里使用 --all-databases选项是因为基于 GTID 的复制会记录全部的事务, 所以要构建一个完整的dump。

  1. #在master上执行

  2. /usr/local/mysql-5.6.27/bin/mysqldump --all-databases --default-character-set=utf8 --triggers -R -q --events --master-data=2 --single-transaction --host=127.0.0.1 --port=3106 --user=root -pxx > my3106.sql

4)传输备份文件

  1. #slave机器

  2. nc -l 1234 | tar xzvf - >my3106.sql

  3. #master机器发送

  4. tar czvf - my3106.sql| nc 192.110.103.43 1234

5)新从库reset master

备份文件信息: 备份文件里包含了设置 gtid_purged 的语句,需要reset master,否则会出错

  1. SET @MYSQLDUMP_TEMP_LOG_BIN = @@SESSION.SQL_LOG_BIN;

  2. SET @@SESSION.SQL_LOG_BIN= 0;

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

  4. --


  5. SET @@GLOBAL.GTID_PURGED='a01f3a3f-1eee-11ea-b1e4-a0369fac2de4:1-26'; #这儿可能出错.

  6. --

  7. -- Position to start replication or point-in-time recovery from

  8. --


  9. -- CHANGE MASTER TO MASTER_LOG_FILE='mysql-bin.000006', MASTER_LOG_POS=191;

  10. --

  11. -- Current Database: `mysql`

  12. --


  13. CREATE DATABASE /*!32312 IF NOT EXISTS*/ `mysql` /*!40100 DEFAULT CHARACTER SET utf8 */;

  14. USE `mysql`;

  15. --

  16. -- Table structure for table `columns_priv`

  17. DROP TABLE IF EXISTS `columns_priv`;...

在从库恢复数据前需要先通过 reset master 清空 gtid_executed 变量

  1. #从库上reset master

  2. root@127.0.0.1 : (none) > show master status;

  3. +------------------+----------+--------------+------------------+-------------------------------------------+

  4. | File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |

  5. +------------------+----------+--------------+------------------+-------------------------------------------+

  6. | mysql-bin.000002 | 191 | | | 49a0c8e8-1f45-11ea-b419-a0369fa6cd30:1-14 |

  7. +------------------+----------+--------------+------------------+-------------------------------------------+

  8. 1 row in set (0.00 sec)


  9. root@127.0.0.1 : (none) > show global variables like '%gtid%';

  10. +---------------------------------+-------------------------------------------+

  11. | Variable_name | Value |

  12. +---------------------------------+-------------------------------------------+

  13. | binlog_gtid_simple_recovery | OFF |

  14. | enforce_gtid_consistency | ON |

  15. | gtid_executed | 49a0c8e8-1f45-11ea-b419-a0369fa6cd30:1-14 |

  16. | gtid_mode | ON |

  17. | gtid_owned | |

  18. | gtid_purged | |

  19. | simplified_binlog_gtid_recovery | OFF |

  20. +---------------------------------+-------------------------------------------+

  21. 7 rows in set (0.01 sec)


  22. root@127.0.0.1 : (none) > reset master;

  23. Query OK, 0 rows affected (0.00 sec)


  24. root@127.0.0.1 : (none) > show global variables like '%gtid%';

  25. +---------------------------------+-------+

  26. | Variable_name | Value |

  27. +---------------------------------+-------+

  28. | binlog_gtid_simple_recovery | OFF |

  29. | enforce_gtid_consistency | ON |

  30. | gtid_executed | |

  31. | gtid_mode | ON |

  32. | gtid_owned | |

  33. | gtid_purged | |

  34. | simplified_binlog_gtid_recovery | OFF |

  35. +---------------------------------+-------+

  36. 7 rows in set (0.00 sec)


  37. root@127.0.0.1 : (none) > show master status;

  38. +------------------+----------+--------------+------------------+-------------------+

  39. | File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |

  40. +------------------+----------+--------------+------------------+-------------------+

  41. | mysql-bin.000001 | 151 | | | |

  42. +------------------+----------+--------------+------------------+-------------------+

  43. 1 row in set (0.00 sec)

说明:若没有reset master,执行设置 GTIDPURGED 的 SQL 时会出错误GLOBAL.GTIDPURGED can only be set when @@GLOBAL.GTID_EXECUTED is empty

  1. /usr/local/mysql/bin/mysql -h 127.0.0.1 -P 3106 -uroot -p < my3106.sql

  2. Enter password:

  3. ERROR 1840 (HY000) at line 24: @@GLOBAL.GTID_PURGED can only be set when @@GLOBAL.GTID_EXECUTED is empty.

如果不希望备份文件中生成设置 GTID_PURGED 的 SQL,可以给 mysqldump传入 --set-gtid-purged=OFF 关闭。

6)新从库导入备份数据

  1. #导入数据

  2. /usr/local/mysql/bin/mysql -h 127.0.0.1 -P 3106 -uroot -p < my3106.sql

  3. Enter password:

导入数据后slave状态

导入备份数据后,可注意到gtidexecuted, gtidpurged的值都已更改。

  1. root@127.0.0.1 : (none) > show global variables like '%gtid%';

  2. +---------------------------------+-------------------------------------------+

  3. | Variable_name | Value |

  4. +---------------------------------+-------------------------------------------+

  5. | binlog_gtid_simple_recovery | OFF |

  6. | enforce_gtid_consistency | ON |

  7. | gtid_executed | a01f3a3f-1eee-11ea-b1e4-a0369fac2de4:1-26 |

  8. | gtid_mode | ON |

  9. | gtid_owned | |

  10. | gtid_purged | a01f3a3f-1eee-11ea-b1e4-a0369fac2de4:1-26 |

  11. | simplified_binlog_gtid_recovery | OFF |

  12. +---------------------------------+-------------------------------------------+

  13. 7 rows in set (0.00 sec)


  14. root@127.0.0.1 : (none) > show master status;

  15. +------------------+----------+--------------+------------------+-------------------------------------------+

  16. | File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |

  17. +------------------+----------+--------------+------------------+-------------------------------------------+

  18. | mysql-bin.000002 | 191 | | | a01f3a3f-1eee-11ea-b1e4-a0369fac2de4:1-26 |

  19. +------------------+----------+--------------+------------------+-------------------------------------------+

7)change master

由于恢复出 MySQL 实例已经被设置了正确的 GTIDEXECUTED ,下面以 masterauto_postion = 1 的方式 CHANGE MASTER 到原来的主节点即可开始复制。

  1. CHANGE MASTER TO MASTER_HOST='192.110.103.41', MASTER_PORT=3106, MASTER_USER='repl', MASTER_PASSWORD='repl',MASTER_AUTO_POSITION = 1;

  2. Query OK, 0 rows affected, 2 warnings (0.01 sec)


  3. root@127.0.0.1 : (none) > show slave status\G

  4. Executed_Gtid_Set: a01f3a3f-1eee-11ea-b1e4-a0369fac2de4:1-26

  5. Auto_Position: 1

  6. 1 row in set (0.00 sec)


  7. root@127.0.0.1 : (none) > start slave;

  8. Query OK, 0 rows affected (0.00 sec)

  9. root@127.0.0.1 : (none) > show slave status\G

  10. Retrieved_Gtid_Set: a01f3a3f-1eee-11ea-b1e4-a0369fac2de4:27

  11. Executed_Gtid_Set: a01f3a3f-1eee-11ea-b1e4-a0369fac2de4:1-27

  12. Auto_Position: 1

4.5 用innobackup搭建GTID从库

1)备份master

  1. #授权

  2. #grant all on *.* to backup@'127.0.0.1' identified by 'backup';

  3. #备份

  4. backup_path=/data1/mysqlbackup/`date +%Y%m%d`/mysql_3106

  5. mkdir -p $backup_path

  6. innobackupex --defaults-file=/data1/mysql_3106/my3106.cnf -H 127.0.0.1 -P 3106 --user=backup --password=backup --parallel=4 --throttle=4 --no-timestamp --slave-info $backup_path/full_backup-`date +'%Y%m%d'` >> $backup_path/mybackup.log 2>&1

  7. #应用

  8. innobackupex --apply-log $backup_path/full_backup-`date +'%Y%m%d'`

  9. cp /data1/mysql_3106/my3106.cnf $backup_path/full_backup-`date +'%Y%m%d'`

2)传输备份数据

  1. #scp -pr $backup_path/full_backup-`date +'%Y%m%d'` 192.110.103.43:data1/

  2. 或用nc传输

  3. #slave接收方

  4. nc -l 1234 | tar xzvf - >full_backup-20191216

  5. #传输方

  6. cd $backup_path/

  7. tar czvf - full_backup-`date +'%Y%m%d'` | nc 192.110.103.43 1234

3)将备份恢复到slave

  1. innobackupex [--defaults-file=MY.CNF] --copy-back [--defaults-group=GROUP-NAME] BACKUP-DIR

  2. innobackupex --defaults-file=/data1/full_backup-`date +'%Y%m%d'`/my3106.cnf --copy-back /data1/full_backup-`date +'%Y%m%d'`

  3. #

  4. chown -R mysql:mysql mysql_3106

4)启动MySQL

  1. vim /data1/mysql_3106/my3106.cnf #修改server_id等。

  2. #

  3. su - mysql -c "/usr/local/mysql/bin/mysqld_safe --defaults-file=/data1/mysql_3106/my3106.cnf &"

启动时状态

  1. 192.110.103.43 : (none) > show global variables like '%gtid%';

  2. +---------------------------------+-------+

  3. | Variable_name | Value |

  4. +---------------------------------+-------+

  5. | binlog_gtid_simple_recovery | OFF |

  6. | enforce_gtid_consistency | ON |

  7. | gtid_executed | |

  8. | gtid_mode | ON |

  9. | gtid_owned | |

  10. | gtid_purged | |

  11. | simplified_binlog_gtid_recovery | OFF |

  12. +---------------------------------+-------+

  13. 7 rows in set (0.00 sec)


  14. 192.110.103.43 : (none) > show master status;

  15. +------------------+----------+--------------+------------------+-------------------+

  16. | File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |

  17. +------------------+----------+--------------+------------------+-------------------+

  18. | mysql-bin.000001 | 151 | | | |

  19. +------------------+----------+--------------+------------------+-------------------+

  20. 1 row in set (0.00 sec)


  21. 192.110.103.43 : (none) > show slave status\G

  22. Empty set (0.00 sec)

5)查看主的GTID位置

xtrabackup备份数据集却不备份binlog,所以必须先获取此次备份结束时的最后一个事务ID,并在slave上明确指定跳过这些事务,否则slave会再次从master上复制这些binlog并执行,导致数据重复执行。可以从数据目录中的xtrabackupinfo文件中获取。如果不是xtrabackup备份的,那么可以直接从master的show global variables like "gtidexecuted";中获取,它表示master中已执行过的事务。

查看xtrabackup_info:

  1. cat xtrabackup_binlog_info

  2. mysql-bin.000006 964 a01f3a3f-1eee-11ea-b1e4-a0369fac2de4:1-30

  3. #cat xtrabackup_info

  4. uuid = e5ea7e25-1fad-11ea-b1e4-a0369fac2de4

  5. tool_command = --defaults-file=/data1/mysql_3106/my3106.cnf -H 127.0.0.1 -P 3106 --user=backup --password=... --parallel=4 --throttle=4 --no-timestamp /data1/mysqlbackup/20191216/mysql_3106/full_backup-20191216

  6. ibbackup_version = 2.4.8

  7. server_version = 5.6.27-log

  8. binlog_pos = filename 'mysql-bin.000006', position '964', GTID of the last change 'a01f3a3f-1eee-11ea-b1e4-a0369fac2de4:1-30'

其中binlogpos中的GTID对应的就是已备份的数据对应的事务。换句话说,这里的gtid集合1-30表示这30个事务不需要进行复制。或者在master上直接查看executed的值,注意不是gtidpurged的值,master上的gtid_purged表示的是曾经删除掉的binlog。

  1. #master执行

  2. 192.110.103.41 : (none) > show global variables like '%gtid%';

  3. +---------------------------------+-------------------------------------------+

  4. | Variable_name | Value |

  5. +---------------------------------+-------------------------------------------+

  6. | binlog_gtid_simple_recovery | OFF |

  7. | enforce_gtid_consistency | ON |

  8. | gtid_executed | a01f3a3f-1eee-11ea-b1e4-a0369fac2de4:1-30 |

  9. | gtid_mode | ON |

  10. | gtid_owned | |

  11. | gtid_purged | a01f3a3f-1eee-11ea-b1e4-a0369fac2de4:1-26 |

  12. | simplified_binlog_gtid_recovery | OFF |

  13. +---------------------------------+-------------------------------------------+

  14. 7 rows in set (0.00 sec)

6)change master开启复制功能

可以在启动slave线程之前使用gtidpurged变量来指定需要跳过的gtid集合。但因为要设置gtidpurged必须保证全局变量gtidexecuted为空,所以先在slave上执行reset master(注意,不是reset slave),再设置gtidpurged。

  1. #在新的 slave上执行

  2. #stop slave;


  3. reset slave all;

  4. reset master ;

  5. show master logs;

  6. +------------------+-----------+

  7. | Log_name | File_size |

  8. +------------------+-----------+

  9. | mysql-bin.000001 | 151 |

  10. +------------------+-----------+


  11. set @@global.gtid_purged='a01f3a3f-1eee-11ea-b1e4-a0369fac2de4:1-30';


  12. CHANGE MASTER TO MASTER_HOST='192.110.103.41', MASTER_PORT=3106, MASTER_USER='repl', MASTER_PASSWORD='repl',MASTER_AUTO_POSITION = 1;


  13. start slave;


  14. 192.110.103.43 : (none) > show slave status\G

  15. *************************** 1. row ***************************

  16. Slave_IO_State: Waiting for master to send event

  17. Master_Host: 192.110.103.41

  18. Master_User: repl

  19. Master_Port: 3106

  20. Master_Log_File: mysql-bin.000006

  21. Read_Master_Log_Pos: 964

  22. Relay_Log_File: relay-bin.000002

  23. Relay_Log_Pos: 408

  24. Relay_Master_Log_File: mysql-bin.000006

  25. Slave_IO_Running: Yes

  26. Slave_SQL_Running: Yes

  27. Skip_Counter: 0

  28. Exec_Master_Log_Pos: 964

  29. Seconds_Behind_Master: 0

  30. Master_Server_Id: 103413106

  31. Master_UUID: a01f3a3f-1eee-11ea-b1e4-a0369fac2de4

  32. Executed_Gtid_Set: a01f3a3f-1eee-11ea-b1e4-a0369fac2de4:1-30

  33. Auto_Position: 1

  34. 1 row in set (0.00 sec)

  35. #

  36. 192.110.103.43 : (none) > show master status;

  37. +------------------+----------+--------------+------------------+-------------------------------------------+

  38. | File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |

  39. +------------------+----------+--------------+------------------+-------------------------------------------+

  40. | mysql-bin.000002 | 191 | | | a01f3a3f-1eee-11ea-b1e4-a0369fac2de4:1-30 |

  41. +------------------+----------+--------------+------------------+-------------------------------------------+

  42. 1 row in set (0.00 sec)

查看binlog文件内容

  1. /usr/local/mysql/bin/mysqlbinlog -v --base64-output=decode-rows mysql-bin.000002


  2. ##

  3. DELIMITER /*!*/;

  4. # at 4

  5. #191216 11:53:44 server id 103433106 end_log_pos 120 CRC32 0xcf599810 Start: binlog v 4, server v 5.6.27-log created 191216 11:53:44

  6. # Warning: this binlog is either in use or was not closed properly.

  7. # at 120

  8. #191216 11:53:44 server id 103433106 end_log_pos 191 CRC32 0xccbdbaae Previous-GTIDs

  9. # a01f3a3f-1eee-11ea-b1e4-a0369fac2de4:1-30

  10. DELIMITER ;

  11. # End of log file

  12. ROLLBACK /* added by mysqlbinlog */;


5. GTID常见问题处理

5.1 跳过GTID复制错误

在基于 GTID 的复制拓扑中,要想修复从库的 SQL 线程错误,过去的 SQLSLAVESKIPCOUNTER 方式不再适用。需要通过设置 gtidnext 或 gtid_purged 来完成,当然前提是已经确保主从数据一致,仅仅需要跳过复制错误让复制继续下去。

【现象】

  1. 192.110.103.43 : test > show slave status\G

  2. *************************** 1. row ***************************

  3. Slave_IO_State: Waiting for master to send event

  4. Master_Host: 192.110.103.41

  5. Master_User: repl

  6. Master_Port: 3106

  7. Master_Log_File: mysql-bin.000007

  8. Slave_IO_Running: Yes

  9. Slave_SQL_Running: No

  10. Last_Errno: 1062

  11. Last_Error: Could not execute Write_rows event on table test.tt; Duplicate entry '4' for key 'PRIMARY', Error_code: 1062; handler error HA_ERR_FOUND_DUPP_KEY; the event's master log mysql-bin.000007, end_log_pos 891

  12. Skip_Counter: 0

  13. Seconds_Behind_Master: NULL

  14. Master_SSL_Verify_Server_Cert: No

  15. Last_SQL_Errno: 1062

  16. Last_SQL_Error: Could not execute Write_rows event on table test.tt; Duplicate entry '4' for key 'PRIMARY', Error_code: 1062; handler error HA_ERR_FOUND_DUPP_KEY; the event's master log mysql-bin.000007, end_log_pos 891


  17. Retrieved_Gtid_Set: a01f3a3f-1eee-11ea-b1e4-a0369fac2de4:31-35

  18. Executed_Gtid_Set: a01f3a3f-1eee-11ea-b1e4-a0369fac2de4:1-34,

  19. bb35a83e-1fb2-11ea-b6e3-a0369fa6cd30:1

  20. Auto_Position: 1

【原因】

从库和主库数据不一致,从库存在Duplicate entry ,导致同步异常。

【处理】

以前非GTID可以如下,

  1. #普通复制

  2. stop slave;

  3. set global sql_slave_skip_counter = 1;

  4. start slave;

但是GTID复制执行sqlslaveskip_counter将会出错。

  1. #若是GTID复制时将会出错

  2. set global sql_slave_skip_counter = 1;

  3. ERROR 1858 (HY000): sql_slave_skip_counter can not be set when the server is running with @@GLOBAL.GTID_MODE = ON. Instead, for each transaction that you want to skip, generate an empty transaction with the same GTID as the transaction

GTID复处理方法如下:

  1. #master

  2. flush logs;

  3. 192.110.103.41 : test > show master status;

  4. show global variables like '%gtid%';

  5. show binlog events in 'mysql-bin.000007';


  6. #slave

  7. 由于在这个GTID必须是连续的,正常情况同一个服务器产生的GTID是不会存在空缺的。所以不能简单的skip掉一个事务,只能通过注入空事物的方法替换掉一个实际操作事务。


  8. 192.110.103.43 : test >show slave status\G

  9. 当前Executed_Gtid_Set的值a01f3a3f-1eee-11ea-b1e4-a0369fac2de4:1-34

  10. Retrieved_Gtid_Set: a01f3a3f-1eee-11ea-b1e4-a0369fac2de4:31-35

  11. Executed_Gtid_Set: a01f3a3f-1eee-11ea-b1e4-a0369fac2de4:1-34,

  12. bb35a83e-1fb2-11ea-b6e3-a0369fa6cd30:1


  13. #处理:

  14. stop slave;

  15. set gtid_next='a01f3a3f-1eee-11ea-b1e4-a0369fac2de4:35'; --(last_executed_slave_gtid_on_master + 1)

  16. begin;commit;

  17. set gtid_next='AUTOMATIC';

  18. start slave;

  19. show slave status\G;

设置gtidnext的方法一次只能跳过一个事务,要批量的跳过事务可以通过设置gtidpurged完成。

5.2 从库同步error 1236 ,master has purged binary logs

【现象】

  1. show slave status\G

  2. *************************** 1. row ***************************

  3. Slave_IO_State:

  4. Master_Host: 192.110.103.41

  5. Master_User: repl

  6. Master_Port: 3106

  7. Slave_IO_Running: No

  8. Slave_SQL_Running: Yes

  9. Last_IO_Errno: 1236

  10. Last_IO_Error: Got fatal error 1236 from master when reading data from binary log: 'The slave is connecting using CHANGE MASTER TO MASTER_AUTO_POSITION = 1, but the master has purged binary logs containing GTIDs that the slave requires.'

【原因】 该错误常是发现在从库的io进程从主库拉取日志时,主库上的binlog被删除了,导致从库获取不到对应的binglog file。

【解决】 使用mysqldump或xtrabackup重新搭建GTID从库。

5.3 主库故障进行切换,恢复服务

【现象】 有一MySQL集群,Server1为主,Server2,Server3为从库。某天Server1故障,需要恢复服务。

【处理】

1)选择新的主库

  1. 主有故障时:(切换步骤,需要把其中的一个从设置为主,另一个设置为其的从库)

  2. 1:检查从库上,完成事务的从,谁最接近主库


  3. server2: show salve status\G;


  4. Master_Log_File: mysql-bin3306.000002 ---(越大越接近)

  5. Read_Master_Log_Pos: 4156773

  6. Exec_Master_Log_Pos: 4156773


  7. server3: show salve status\G;


  8. Master_Log_File: mysql-bin3306.000001 ---(越大越接近)

  9. Read_Master_Log_Pos: 83795320

  10. Exec_Master_Log_Pos: 83795320


  11. 相比之下server2完成的事务要比server3更接近或则等于server1,现在需要把server3设置为server2的从库。

2)切换

  1. 从库server3,上重新指定主库信息(指向server2

  2. mysql> stop slave; #千万不要执行 reset master,否则会从最先的GTID上开始执行。

  3. change master to master_host='192.x.x.41',master_user='rep',master_password='rep',master_port=3306,master_auto_position=1; #指定到server2从上

  4. start slave; #成功的切换到新主

3)善后

修改域名及通知业务方观察服务。若是未来server1主库恢复也可切换到server2(完成的事务最接近主库)做为server2从库。

参考:

  • 陶老师运维笔记-掘金畅读版 https://juejin.im/post/5df71dbcf265da33e347f092

  • https://dev.mysql.com/doc/refman/5.6/en/replication-gtids-howto.html

  •  http://cenalulu.github.io/mysql/mysql-5-6-gtid-basic/ 

  • https://blog.csdn.net/wanbin6470398/article/details/83022476

  • 骏马金龙 GTID介绍

  • https://dbaplus.cn/news-11-857-1.html

  • https://www.cnblogs.com/abobo/p/4242417.html

最后修改时间:2019-12-17 12:28:12
文章转载自陶老师运维笔记,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论