MySQL GTID介绍及搭建GTID从库
文章来源: 陶老师运维笔记- 微信公众号
1. GTID 介绍
1.1 GTID概念
GTID (Global Transaction ID) 是对于一个已提交事务的编号,并且是一个全局唯一的编号。 GTID 实际上 是由 UUID+TID 组成的。其中UUID 是一个 MySQL 实例的唯一标识,记录在$datadir/auto.cnf。TID 代表了该实例上已经提交的事务数量,并且随着事务提交单调递增。
如下是GTID的几个具体形式:
#GTID
3E11FA47-71CA-11E1-9E33-C80AA9429562:23
#一组连续的事务可以用 - 连接的事务序号范围表示
e6954592-8dba-11e6-af0e-fa163e1cf111:1-5
#多个 MySQL 实例的事务,它们之间用逗号分隔。如果来自同一 MySQL 实例的事务序号有多个范围区间,各组范围之间用冒号分隔。
e6954592-8dba-11e6-af0e-fa163e1cf111:1-5:11-18,
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实时看当前的事务执行数。
show global variables like '%gtid%';
select @@server_uuid;
+--------------------------------------+
| @@server_uuid |
+--------------------------------------+
| a01f3a3f-1eee-11ea-b1e4-a0369fac2de4 |
+--------------------------------------+
show master status;
+------------------+----------+--------------+------------------+-------------------------------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+------------------+----------+--------------+------------------+-------------------------------------------+
| mysql-bin.000002 | 191 | | | a01f3a3f-1eee-11ea-b1e4-a0369fac2de4:1-14 |
+------------------+----------+--------------+------------------+-------------------------------------------+
show global variables like 'gtid_executed';
+---------------+-------------------------------------------+
| Variable_name | Value |
+---------------+-------------------------------------------+
| gtid_executed | a01f3a3f-1eee-11ea-b1e4-a0369fac2de4:1-14 |
+---------------+-------------------------------------------+
MySQL5.7后还可以通过mysql.gtid_executed表来查看。
SELECT * FROM mysql.gtid_executed;
+--------------------------------------+----------------+--------------+
| source_uuid | interval_start | interval_end |
+--------------------------------------+----------------+--------------+
| aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa | 1 | 40 |
| aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa | 1000003 | 1000004 |
| aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa | 2000003 | 2000006 |
+--------------------------------------+----------------+--------------+
1.3 GTID配置开启
主要配置:
- server_id: 设置MySQL实例的server_id,每个server_id不能一样
- gtid_mode=ON: MySQL实例开启GTID模式
- enforce_gtid_consitency=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不会启动复制
配置示例:
#假定port为3106
[mysqld]
datadir=/data1/mysql_3106
socket=/tmp/mysql3106.sock
log-bin=mysql-bin # mysql 5.6必须项,mysql 5.7非必须项
sync-binlog=1 # 建议项
binlog_format=row # 建议项
relay-log=relay-bin # 必须项
server-id=413106 #必须项,不能和其它实例相同
log-error=mysqld_error.log
pid-file=mysqld.pid
log-slave-updates = 1 #mysql5.6 必须
enforce_gtid_consistency=on # 必须项
gtid_mode=on # 必须项
查看情况:
## 开启GTID
show global variables like '%gtid%';
+---------------------------------+-------------------------------------------+
| Variable_name | Value |
+---------------------------------+-------------------------------------------+
| binlog_gtid_simple_recovery | OFF |
| enforce_gtid_consistency | ON |
| gtid_executed | a01f3a3f-1eee-11ea-b1e4-a0369fac2de4:1-14 |
| gtid_mode | ON |
| gtid_owned | |
| gtid_purged | |
| simplified_binlog_gtid_recovery | OFF |
+---------------------------------+-------------------------------------------+
1.4 GTID作用
主要有以下两点:
- 根据 GTID 可以知道事务最初是在哪个实例上提交的
- GTID 的存在方便了 Replication 的 Failover
MySQL 5.6 的 GTID 出现以前 Replication Failover 的操作过程。假设我们有一个如下图的环境:
此时,Server A 的服务器宕机,需要将业务切换到 Server B 上。同时,我们又需要将 Server C 的复制源改成 Server B。复制源修改的命令语法很简单即:
CHANGE MASTER TO MASTER_HOST='xxx', MASTER_LOG_FILE='xxx', MASTER_LOG_POS=nnnn;
这种方式的难点在于,由于同一个事务在每台机器上所在的 binlog 名字和位置都不一样,那么怎么找到 Server C 当前同步停止点对应 Server B 上 master_log_file 和 master_log_pos 的位置就成为了难题。
MySQL5.6 的 GTID 出现后,就显得非常的简单。
由于同一事务的 GTID 在所有节点上的值一致,那么根据 Server C 当前停止点的 GTID 就能唯一定位到 Server B 上的GTID。甚至由于 MASTER_AUTO_POSITION 功能的出现,我们都不需要知道 GTID 的具体值。直接使用以下命令就可以直接完成 Failover 的工作。
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时(即,enforce_gtid_consistency系统变量设置为ON时),事务,过程,函数和触发器内不支持CREATE TEMPORARY TABLE和DROP TEMPORARY TABLE语句。 可以在启用GTID的情况下使用这些语句,但仅限于任何事务之外,并且仅使用autocommit = 1。防止执行不受支持的语句
要防止执行会导致基于GTID的复制失败的语句,必须在启用GTID时使用–enforce-gtid-consistency选项启动所有服务器。跳过事务
使用GTID时不支持sql_slave_skip_counter。 如果您需要跳过事务,请使用master的gtid_executed变量的值; 有关详细信息,请参考
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的生命周期:
客户端发送DDL/DML给master上,master首先对此事务生成一个唯一的gtid,假如为uuid_xxx:1,然后立即执行该事务中的操作。
主从复制的情况下,sync-binlog基本上都会设置为1,这表示在每次提交事务时将缓存中的binlog刷盘。所以,在事务提交前,gtid以及事务相关操作的信息都在缓存中,提交后它们才写入到binlog file中,然后才会被dump线程dump出去。
即只有提交了的事务,gtid和对应的事务操作才会记录到binlog文件中。记录的格式是先记录gtid,紧跟着再记录事务相关的操作。当binlog传送到relay log中后,slave上的SQL线程首先读取该gtid,并 设置变量 gtid_next 的值为该gtid,表示下一个要操作的事务是该gtid。gtid_next 是基于会话的,不同会话的gtid_next不同。
随后slave检测该gtid在自己的binlog中是否存在。如果存在,则放弃此gtid事务;如果不存在,则将此gtid写入到自己的binlog中,然后立刻执行该事务,并在自己的binlog中记录该事务相关的操作。
注意,slave上replay的时候,gtid不是提交后才写到自己的binlog file的,而是判断gtid不存在后立即写入binlog file。
通过这种在执行事务前先检查并写gtid到binlog的机制,不仅可以保证当前会话在此之前没有执行过该事务,还能保证没有其他会话读取了该gtid却没有提交。因为如果其他会话读取了该gtid会立即写入到binlog(不管是否已经开始执行事务),所以当前会话总能读取到binlog中的该gtid,于是当前会话就会放弃该事务。总之,一个gtid事务是决不允许多次执行、多个会话并行执行的。SLAVE不生成GTID。slave在重放relay log中的事务时,不会自己生成gtid,所以所有的slave(无论是何种方式的一主一从或一主多从复制架构)通过重放relay log中事务获取的gtid都来源于master,并永久保存在slave上。
2.2 GTID生成示例
GTID 的生成受 gtid_next 控制。 在主服务器上gtid_next 是默认的 AUTOMATIC,即在每次事务提交时自动生成新的 GTID 。它从当前已执行的 GTID 集合(即 gtid_executed )中,找一个大于 0 的未使用的最小值作为下个事务 GTID 。同时在 Binlog 的实际的更新事务事件前面插入一条 set gtid_next 事件。
这里以一条 insert 语句来看看 GTID 的生成过程:
Master:
#操作前
192.110.103.41 : test > select @@server_uuid;
+--------------------------------------+
| @@server_uuid |
+--------------------------------------+
| a01f3a3f-1eee-11ea-b1e4-a0369fac2de4 |
+--------------------------------------+
192.110.103.41 : test > flush logs;
test>show master logs;
+------------------+-----------+
| Log_name | File_size |
+------------------+-----------+
...
| mysql-bin.000005 | 191 |
+------------------+-----------+
192.110.103.41 : test > show master status;
+------------------+----------+--------------+------------------+-------------------------------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+------------------+----------+--------------+------------------+-------------------------------------------+
| mysql-bin.000005 | 191 | | | a01f3a3f-1eee-11ea-b1e4-a0369fac2de4:1-25 |
+------------------+----------+--------------+------------------+-------------------------------------------+
1 row in set (0.00 sec)
## insert
192.110.103.41 : test > insert into t1 values(2,'li4');
Query OK, 1 row affected (0.00 sec)
192.110.103.41 : test > show master status;
+------------------+----------+--------------+------------------+-------------------------------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+------------------+----------+--------------+------------------+-------------------------------------------+
| mysql-bin.000005 | 434 | | | a01f3a3f-1eee-11ea-b1e4-a0369fac2de4:1-26 |
+------------------+----------+--------------+------------------+-------------------------------------------+
1 row in set (0.00 sec)
192.110.103.41 : test > show binlog events in 'mysql-bin.000005';
+------------------+-----+----------------+-----------+-------------+--------------------------------------------------------------------+
| Log_name | Pos | Event_type | Server_id | End_log_pos | Info |
+------------------+-----+----------------+-----------+-------------+--------------------------------------------------------------------+
| mysql-bin.000005 | 4 | Format_desc | 103413106 | 120 | Server ver: 5.6.27-log, Binlog ver: 4 |
| mysql-bin.000005 | 120 | Previous_gtids | 103413106 | 191 | a01f3a3f-1eee-11ea-b1e4-a0369fac2de4:1-25 |
| mysql-bin.000005 | 191 | Gtid | 103413106 | 239 | SET @@SESSION.GTID_NEXT= 'a01f3a3f-1eee-11ea-b1e4-a0369fac2de4:26' |
| mysql-bin.000005 | 239 | Query | 103413106 | 311 | BEGIN |
| mysql-bin.000005 | 311 | Table_map | 103413106 | 359 | table_id: 78 (test.t1) |
| mysql-bin.000005 | 359 | Write_rows | 103413106 | 403 | table_id: 78 flags: STMT_END_F |
| mysql-bin.000005 | 403 | Xid | 103413106 | 434 | COMMIT /* xid=132 */ |
+------------------+-----+----------------+-----------+-------------+--------------------------------------------------------------------+
7 rows in set (0.01 sec)
SLAVE:
在从库上回放主库的 Binlog 时,先执行 SET @@SESSION.GTID_NEXT语句,然后再执行 insert 语句,确保在主和备上这条 insert 对应于相同的 GTID。
#slave上信息
show master logs;
+------------------+-----------+
| Log_name | File_size |
+------------------+-----------+
| mysql-bin.000001 | 5762 |
...
| mysql-bin.000004 | 425 |
+------------------+-----------+
4 rows in set (0.01 sec)
192.110.103.42 : test > show binlog events in 'mysql-bin.000004';
+------------------+-----+----------------+-----------+-------------+--------------------------------------------------------------------+
| Log_name | Pos | Event_type | Server_id | End_log_pos | Info |
+------------------+-----+----------------+-----------+-------------+--------------------------------------------------------------------+
| mysql-bin.000004 | 4 | Format_desc | 103423106 | 120 | Server ver: 5.6.27-log, Binlog ver: 4 |
| mysql-bin.000004 | 120 | Previous_gtids | 103423106 | 191 | a01f3a3f-1eee-11ea-b1e4-a0369fac2de4:1-25 |
| mysql-bin.000004 | 191 | Gtid | 103413106 | 239 | SET @@SESSION.GTID_NEXT= 'a01f3a3f-1eee-11ea-b1e4-a0369fac2de4:26' |
| mysql-bin.000004 | 239 | Query | 103413106 | 302 | BEGIN |
| mysql-bin.000004 | 302 | Table_map | 103413106 | 350 | table_id: 72 (test.t1) |
| mysql-bin.000004 | 350 | Write_rows | 103413106 | 394 | table_id: 72 flags: STMT_END_F |
| mysql-bin.000004 | 394 | Xid | 103413106 | 425 | COMMIT /* xid=124 */ |
+------------------+-----+----------------+-----------+-------------+--------------------------------------------------------------------+
7 rows in set (0.00 sec)
192.110.103.42 : test > show slave status\G
*************************** 1. row ***************************
Slave_IO_State: Waiting for master to send event
Master_Host: 192.110.103.41
Master_User: repl
Master_Port: 3106
Connect_Retry: 60
Master_Log_File: mysql-bin.000005
Read_Master_Log_Pos: 434
Relay_Log_File: relay-bin.000013
Relay_Log_Pos: 550
Relay_Master_Log_File: mysql-bin.000005
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
Exec_Master_Log_Pos: 434
Relay_Log_Space: 998
Seconds_Behind_Master: 0
Master_Server_Id: 103413106
Master_UUID: a01f3a3f-1eee-11ea-b1e4-a0369fac2de4
Master_Info_File: /data1/mysql_3106/master.info
Slave_SQL_Running_State: Slave has read all relay log; waiting for the slave I/O thread to update it
Retrieved_Gtid_Set: a01f3a3f-1eee-11ea-b1e4-a0369fac2de4:1-26
Executed_Gtid_Set: a01f3a3f-1eee-11ea-b1e4-a0369fac2de4:1-26
Auto_Position: 1
2.3 常用GTID参数说明
2.3.1 GTID重要的变量
1) gtid_executed
在当前实例上已执行过的 GTID 集合,实际上包含了所有记录到 binlog 中的事务。设置 set sql_log_bin=0 后执行的事务不会生成 binlog 事件,也不会被记录到 gtid_executed 中。执行 RESET MASTER 可以将gtid_executed变量置空。
2)gtid_purged
gtid_purged表示已经purge掉的gtid。只有 gtid_executed 为空时才能手动设置该变量,此时会同时更新 gtid_executed 为和 gtid_purged 相同的值。(gtid_executed 为空意味着要么之前没有启动过基于 GTID 的复制,要么执行过 RESET MASTER。执行 RESET MASTER 时同样也会把 gtid_purged 置空,即始终保持 gtid_purged 是 gtid_executed 的子集。)
在slave上设置该项时,表示稍后启动io线程和SQL线程都跳过这些gtid,slave上设置时应该让此项的gtid集合等于master上 gtid_executed 的值。
binlog 不可能永远驻留在服务上,需要定期进行清理(通过 expire_logs_days 定期清理)日志。
gtid_purged系统变量(@@global.gtid_purged)用于记录本机上已经执行过,但是已经被清除了的 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说明
192.110.103.42 : test > show slave status\G
*************************** 1. row ***************************
Slave_IO_State: Waiting for master to send event
Master_Host: 192.110.103.41
...
Master_Log_File: mysql-bin.000005
Exec_Master_Log_Pos: 434
Master_UUID: a01f3a3f-1eee-11ea-b1e4-a0369fac2de4
Retrieved_Gtid_Set: a01f3a3f-1eee-11ea-b1e4-a0369fac2de4:1-26
Executed_Gtid_Set: a01f3a3f-1eee-11ea-b1e4-a0369fac2de4:1-26
Auto_Position: 1
- Retrieved_Gtid_Set:在开启了gtid复制(即gtid_mode=on)时,slave在启动io线程的时候会检查自己的relay log,并从中检索出gtid集合。也就是说,这代表的是slave已经从master中复制了哪些事务过来。检索出来的gtid不会再请求master发送过来。
- Executed_Gtid_Set:在开启了gtid复制(即gtid_mode=on)时,它表示已经向自己的binlog中写入了哪些gtid集合。注意,这个值是根据一些状态信息计算出来的,并非binlog中能看到的那些。
- Auto_Position:开启gtid时是否自动获取binlog坐标。1表示开启,这是gtid复制的默认值。
2.3.3 binlog中gtid说明
用slave机器上binlog示例做gtid说明。
#slave机器上binlog示例.
/usr/local/mysql-5.6.27/bin/mysqlbinlog mysql-bin.000003
/*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=1*/;
# at 4
#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
BINLOG '
kxb2XQ+BHCoGdAAAAHgAAAAAAAQANS42LjI3LWxvZwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAEzgNAAgAEgAEBAQEEgAAXAAEGggAAAAICAgCAAAACgoKGRkAAfIo
a40=
'/*!*/;
# at 120
#191215 19:18:43 server id 103423106 end_log_pos 191 CRC32 0xfaf65b70 Previous-GTIDs
# a01f3a3f-1eee-11ea-b1e4-a0369fac2de4:1-24 ### 行1
# at 191
#191215 19:19:08 server id 103413106 end_log_pos 239 CRC32 0xf260d744 GTID [commit=yes] ### 行2
SET @@SESSION.GTID_NEXT= 'a01f3a3f-1eee-11ea-b1e4-a0369fac2de4:25'/*!*/; ###行3
# at 239
#191215 19:19:08 server id 103413106 end_log_pos 302 CRC32 0xd6f210a9 Query thread_id=12 exec_time=0 error_code=0
SET TIMESTAMP=1576408748/*!*/;
...
BEGIN
/*!*/;
# at 302
#191215 19:19:08 server id 103413106 end_log_pos 350 CRC32 0x5970d846 Table_map: `test`.`t1` mapped to number 72
# at 350
#191215 19:19:08 server id 103413106 end_log_pos 394 CRC32 0x36e14e8a Delete_rows: table id 72 flags: STMT_END_F
BINLOG '
rBb2XRNx9SkGMAAAAF4BAAAAAEgAAAAAAAEABHRlc3QAAnQxAAIDDwKWAABG2HBZ
rBb2XSBx9SkGLAAAAIoBAAAAAEgAAAAAAAEAAgAC//wCAAAAA2xpNIpO4TY=
'/*!*/;
# at 394
#191215 19:19:08 server id 103413106 end_log_pos 425 CRC32 0x68da9583 Xid = 113
COMMIT/*!*/;
SET @@SESSION.GTID_NEXT= 'AUTOMATIC' /* added by mysqlbinlog */ /*!*/; ## 行6
# at 425
#191215 20:20:39 server id 103423106 end_log_pos 472 CRC32 0x1a938cf2 Rotate to mysql-bin.000004 pos: 4
DELIMITER ;
# End of log file
ROLLBACK /* added by mysqlbinlog */;
/*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/;
/*!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中配置gtid_mode=ON,log_slave_updates,enforce_gtid_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配置示例:
#假定port为3106
[mysqld]
datadir=/data1/mysql_3106
socket=/tmp/mysql3106.sock
log-bin=mysql-bin # mysql 5.6必须项,mysql 5.7非必须项
sync-binlog=1 # 建议项
binlog_format=row # 建议项
relay-log=relay-bin # 必须项
server-id=413106 #必须项,不能和其它实例相同
log-error=mysqld_error.log
pid-file=mysqld.pid
log-slave-updates = 1 #mysql5.6 必须,mysql5.7非必须
enforce_gtid_consistency=on # 必须项
gtid_mode=on # 必须项
2)Slave配置示例:
#port为3106
[mysqld]
datadir=/data1/mysql_3106
socket=/tmp/mysql3106.sock
log-bin=mysql-bin # mysql 5.6必须项,mysql 5.7非必须项
sync-binlog=1 # 建议项
binlog_format=row # 建议项
relay-log=relay-bin # 必须项
server-id=423106 # 必须项,不能和其它实例相同
log-error=mysqld_error.log
pid-file=mysqld.pid
log-slave-updates = 1 #mysql5.6 必须,mysql5.7非必须
enforce_gtid_consistency=on # 必须项
gtid_mode=on # 必须项
log-slave-updates = 1 选项会增大了从服务器的IO负载, 在MySQL5.7版本已非必须。
3.3 启动MySQL
su - mysql -c "/usr/local/mysql/bin/mysqld_safe --defaults-file=/data1/mysql_3106/etc/my.cnf &"
3.4 创建复制账号
在master上创建一个用于复制的用户repl。
# master上执行
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语法略有区别。
# MySQL5.6slave上执行
#reset slave all;
reset master;
CHANGE MASTER TO MASTER_HOST='192.110.103.41', MASTER_PORT=3106, MASTER_USER='repl', MASTER_PASSWORD='repl',MASTER_AUTO_POSITION = 1;
start slave;
show slave status\G
## MySQL5.7 slave命令
#MySQL 5.7,没有在change master to语句中加入user和password项,而是在start slave语句中使用,否则会警告。
change master to master_host='192.110.103.41',master_port=3106,master_auto_position=1;
start slave user='repl' password='repl';
show slave status\G
3.6 检查验证
检查GTID情况
## 开启GTID
#show global variables like '%gtid%';
#Master实例上
192.110.103.41 : (none) > show master status;
+------------------+----------+--------------+------------------+-------------------------------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+------------------+----------+--------------+------------------+-------------------------------------------+
| mysql-bin.000002 | 1233 | | | a01f3a3f-1eee-11ea-b1e4-a0369fac2de4:1-19 |
+------------------+----------+--------------+------------------+-------------------------------------------+
1 row in set (0.00 sec)
192.110.103.41 : (none) > show global variables like '%gtid%';
+---------------------------------+-------------------------------------------+
| Variable_name | Value |
+---------------------------------+-------------------------------------------+
| binlog_gtid_simple_recovery | OFF |
| enforce_gtid_consistency | ON |
| gtid_executed | a01f3a3f-1eee-11ea-b1e4-a0369fac2de4:1-19 |
| gtid_mode | ON |
| gtid_owned | |
| gtid_purged | |
| simplified_binlog_gtid_recovery | OFF |
+---------------------------------+-------------------------------------------+
## slave 实例上
root@127.0.0.1 : (none) > show master status;
+------------------+----------+--------------+------------------+-------------------------------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+------------------+----------+--------------+------------------+-------------------------------------------+
| mysql-bin.000001 | 5261 | | | a01f3a3f-1eee-11ea-b1e4-a0369fac2de4:1-19 |
+------------------+----------+--------------+------------------+-------------------------------------------+
1 row in set (0.00 sec)
查看主从同步情况:
root@127.0.0.1 : (none) > show slave status\G
*************************** 1. row ***************************
Slave_IO_State: Waiting for master to send event
Master_Host: 192.110.103.41
Master_User: repl
Master_Port: 3106
Connect_Retry: 60
Master_Log_File: mysql-bin.000002
Read_Master_Log_Pos: 1233
Relay_Log_File: relay-bin.000004
Relay_Log_Pos: 1443
Relay_Master_Log_File: mysql-bin.000002
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
Replicate_Wild_Ignore_Table:
Last_Errno: 0
Last_Error:
Skip_Counter: 0
Exec_Master_Log_Pos: 1233
Relay_Log_Space: 1728
Until_Condition: None
Seconds_Behind_Master: 0
Master_Server_Id: 103413106
Master_UUID: a01f3a3f-1eee-11ea-b1e4-a0369fac2de4
Master_Info_File: /data1/mysql_3106/master.info
SQL_Delay: 0
SQL_Remaining_Delay: NULL
Slave_SQL_Running_State: Slave has read all relay log; waiting for the slave I/O thread to update it
Master_Retry_Count: 86400
...
Master_SSL_Crlpath:
Retrieved_Gtid_Set: a01f3a3f-1eee-11ea-b1e4-a0369fac2de4:1-19
Executed_Gtid_Set: a01f3a3f-1eee-11ea-b1e4-a0369fac2de4:1-19
Auto_Position: 1
1 row in set (0.00 sec)
验证数据:
#master
create table if not exists t1 (id int(10) PRIMARY KEY AUTO_INCREMENT,name varchar(50) NOT NULL);
insert into t1 values(1,'zhang3');
#slave
select * from t1;
+----+--------+
| id | name |
+----+--------+
| 1 | zhang3 |
+----+--------+
4. 添加新的slave到gtid复制集群
线上环境,往往会定期删除一部分binlog。咱们模似这种情况下从库制作。
当master没有删除过任何binlog时,可以方便地向复制结构中添加新的slave,因为slave会复制所有的binlog到自己relay log中并replay。即类似上节的命令即可 change master to master_host='xxx',master_port=3xx,master_auto_position=1;。
当master删除过一部分binlog后,在向复制结构中添加新的slave时,必须先获取到master binlog中当前已记录的第一个gtid之前的所有数据,然后恢复到slave上。只有slave上具有了这部分基准数据,才能保证和master的数据一致性。
4.1 在master实例上删除binlog
master实例用 purge master logs to 'xxx';来清理binlog。
#master上执行
>flush logs;
>show master logs;
+------------------+-----------+
| Log_name | File_size |
+------------------+-----------+
| mysql-bin.000001 | 4266 |
...
| mysql-bin.000005 | 481 |
| mysql-bin.000006 | 191 |
+------------------+-----------+
>purge master logs to 'mysql-bin.000006';
test > show master logs;
+------------------+-----------+
| Log_name | File_size |
+------------------+-----------+
| mysql-bin.000006 | 191 |
+------------------+-----------+
1 row in set (0.00 sec)
192.110.103.41 : test > show master status;
+------------------+----------+--------------+------------------+-------------------------------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+------------------+----------+--------------+------------------+-------------------------------------------+
| mysql-bin.000006 | 191 | | | a01f3a3f-1eee-11ea-b1e4-a0369fac2de4:1-26 |
+------------------+----------+--------------+------------------+-------------------------------------------+
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。
#在master上执行
/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)传输备份文件
#slave机器
nc -l 1234 | tar xzvf - >my3106.sql
#master机器发送
tar czvf - my3106.sql| nc 192.110.103.43 1234
5)新从库reset master
备份文件信息: 备份文件里包含了设置 gtid_purged 的语句,需要reset master,否则会出错。
SET @MYSQLDUMP_TEMP_LOG_BIN = @@SESSION.SQL_LOG_BIN;
SET @@SESSION.SQL_LOG_BIN= 0;
-- GTID state at the beginning of the backup
--
SET @@GLOBAL.GTID_PURGED='a01f3a3f-1eee-11ea-b1e4-a0369fac2de4:1-26'; #这儿可能出错.
--
-- Position to start replication or point-in-time recovery from
--
-- CHANGE MASTER TO MASTER_LOG_FILE='mysql-bin.000006', MASTER_LOG_POS=191;
--
-- Current Database: `mysql`
--
CREATE DATABASE /*!32312 IF NOT EXISTS*/ `mysql` /*!40100 DEFAULT CHARACTER SET utf8 */;
USE `mysql`;
--
-- Table structure for table `columns_priv`
DROP TABLE IF EXISTS `columns_priv`;...
在从库恢复数据前需要先通过 reset master 清空 gtid_executed 变量。
#从库上reset master
root@127.0.0.1 : (none) > show master status;
+------------------+----------+--------------+------------------+-------------------------------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+------------------+----------+--------------+------------------+-------------------------------------------+
| mysql-bin.000002 | 191 | | | 49a0c8e8-1f45-11ea-b419-a0369fa6cd30:1-14 |
+------------------+----------+--------------+------------------+-------------------------------------------+
1 row in set (0.00 sec)
root@127.0.0.1 : (none) > show global variables like '%gtid%';
+---------------------------------+-------------------------------------------+
| Variable_name | Value |
+---------------------------------+-------------------------------------------+
| binlog_gtid_simple_recovery | OFF |
| enforce_gtid_consistency | ON |
| gtid_executed | 49a0c8e8-1f45-11ea-b419-a0369fa6cd30:1-14 |
| gtid_mode | ON |
| gtid_owned | |
| gtid_purged | |
| simplified_binlog_gtid_recovery | OFF |
+---------------------------------+-------------------------------------------+
7 rows in set (0.01 sec)
root@127.0.0.1 : (none) > reset master;
Query OK, 0 rows affected (0.00 sec)
root@127.0.0.1 : (none) > show global variables like '%gtid%';
+---------------------------------+-------+
| Variable_name | Value |
+---------------------------------+-------+
| binlog_gtid_simple_recovery | OFF |
| enforce_gtid_consistency | ON |
| gtid_executed | |
| gtid_mode | ON |
| gtid_owned | |
| gtid_purged | |
| simplified_binlog_gtid_recovery | OFF |
+---------------------------------+-------+
7 rows in set (0.00 sec)
root@127.0.0.1 : (none) > show master status;
+------------------+----------+--------------+------------------+-------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+------------------+----------+--------------+------------------+-------------------+
| mysql-bin.000001 | 151 | | | |
+------------------+----------+--------------+------------------+-------------------+
1 row in set (0.00 sec)
说明:
若没有reset master,执行设置 GTID_PURGED 的 SQL 时会出错误GLOBAL.GTID_PURGED can only be set when @@GLOBAL.GTID_EXECUTED is empty:
/usr/local/mysql/bin/mysql -h 127.0.0.1 -P 3106 -uroot -p < my3106.sql
Enter password:
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)新从库导入备份数据
#导入数据
/usr/local/mysql/bin/mysql -h 127.0.0.1 -P 3106 -uroot -p < my3106.sql
Enter password:
导入数据后slave状态
导入备份数据后,可注意到gtid_executed, gtid_purged的值都已更改。
root@127.0.0.1 : (none) > show global variables like '%gtid%';
+---------------------------------+-------------------------------------------+
| Variable_name | Value |
+---------------------------------+-------------------------------------------+
| binlog_gtid_simple_recovery | OFF |
| enforce_gtid_consistency | ON |
| gtid_executed | a01f3a3f-1eee-11ea-b1e4-a0369fac2de4:1-26 |
| gtid_mode | ON |
| gtid_owned | |
| gtid_purged | a01f3a3f-1eee-11ea-b1e4-a0369fac2de4:1-26 |
| simplified_binlog_gtid_recovery | OFF |
+---------------------------------+-------------------------------------------+
7 rows in set (0.00 sec)
root@127.0.0.1 : (none) > show master status;
+------------------+----------+--------------+------------------+-------------------------------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+------------------+----------+--------------+------------------+-------------------------------------------+
| mysql-bin.000002 | 191 | | | a01f3a3f-1eee-11ea-b1e4-a0369fac2de4:1-26 |
+------------------+----------+--------------+------------------+-------------------------------------------+
7)change master
由于恢复出 MySQL 实例已经被设置了正确的 GTID_EXECUTED ,下面以 master_auto_postion = 1 的方式 CHANGE MASTER 到原来的主节点即可开始复制。
CHANGE MASTER TO MASTER_HOST='192.110.103.41', MASTER_PORT=3106, MASTER_USER='repl', MASTER_PASSWORD='repl',MASTER_AUTO_POSITION = 1;
Query OK, 0 rows affected, 2 warnings (0.01 sec)
root@127.0.0.1 : (none) > show slave status\G
Executed_Gtid_Set: a01f3a3f-1eee-11ea-b1e4-a0369fac2de4:1-26
Auto_Position: 1
1 row in set (0.00 sec)
root@127.0.0.1 : (none) > start slave;
Query OK, 0 rows affected (0.00 sec)
root@127.0.0.1 : (none) > show slave status\G
Retrieved_Gtid_Set: a01f3a3f-1eee-11ea-b1e4-a0369fac2de4:27
Executed_Gtid_Set: a01f3a3f-1eee-11ea-b1e4-a0369fac2de4:1-27
Auto_Position: 1
4.5 用innobackup搭建GTID从库
1)备份master
#授权
#grant all on *.* to backup@'127.0.0.1' identified by 'backup';
#备份
backup_path=/data1/mysqlbackup/`date +%Y%m%d`/mysql_3106
mkdir -p $backup_path
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
#应用
innobackupex --apply-log $backup_path/full_backup-`date +'%Y%m%d'`
cp /data1/mysql_3106/my3106.cnf $backup_path/full_backup-`date +'%Y%m%d'`
2)传输备份数据
#scp -pr $backup_path/full_backup-`date +'%Y%m%d'` 192.110.103.43:data1/
或用nc传输
#slave接收方
nc -l 1234 | tar xzvf - >full_backup-20191216
#传输方
cd $backup_path/
tar czvf - full_backup-`date +'%Y%m%d'` | nc 192.110.103.43 1234
3)将备份恢复到slave
innobackupex [--defaults-file=MY.CNF] --copy-back [--defaults-group=GROUP-NAME] BACKUP-DIR
innobackupex --defaults-file=/data1/full_backup-`date +'%Y%m%d'`/my3106.cnf --copy-back /data1/full_backup-`date +'%Y%m%d'`
#
chown -R mysql:mysql mysql_3106
4)启动MySQL
vim /data1/mysql_3106/my3106.cnf #修改server_id等。
#
su - mysql -c "/usr/local/mysql/bin/mysqld_safe --defaults-file=/data1/mysql_3106/my3106.cnf &"
启动时状态
192.110.103.43 : (none) > show global variables like '%gtid%';
+---------------------------------+-------+
| Variable_name | Value |
+---------------------------------+-------+
| binlog_gtid_simple_recovery | OFF |
| enforce_gtid_consistency | ON |
| gtid_executed | |
| gtid_mode | ON |
| gtid_owned | |
| gtid_purged | |
| simplified_binlog_gtid_recovery | OFF |
+---------------------------------+-------+
7 rows in set (0.00 sec)
192.110.103.43 : (none) > show master status;
+------------------+----------+--------------+------------------+-------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+------------------+----------+--------------+------------------+-------------------+
| mysql-bin.000001 | 151 | | | |
+------------------+----------+--------------+------------------+-------------------+
1 row in set (0.00 sec)
192.110.103.43 : (none) > show slave status\G
Empty set (0.00 sec)
5)查看主的GTID位置
xtrabackup备份数据集却不备份binlog,所以必须先获取此次备份结束时的最后一个事务ID,并在slave上明确指定跳过这些事务,否则slave会再次从master上复制这些binlog并执行,导致数据重复执行。
可以从数据目录中的xtrabackup_info文件中获取。如果不是xtrabackup备份的,那么可以直接从master的show global variables like "gtid_executed";中获取,它表示master中已执行过的事务。
查看xtrabackup_info:
cat xtrabackup_binlog_info
mysql-bin.000006 964 a01f3a3f-1eee-11ea-b1e4-a0369fac2de4:1-30
#cat xtrabackup_info
uuid = e5ea7e25-1fad-11ea-b1e4-a0369fac2de4
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
ibbackup_version = 2.4.8
server_version = 5.6.27-log
binlog_pos = filename 'mysql-bin.000006', position '964', GTID of the last change 'a01f3a3f-1eee-11ea-b1e4-a0369fac2de4:1-30'
其中binlog_pos中的GTID对应的就是已备份的数据对应的事务。换句话说,这里的gtid集合1-30表示这30个事务不需要进行复制。
或者在master上直接查看executed的值,注意不是gtid_purged的值,master上的gtid_purged表示的是曾经删除掉的binlog。
#master执行
192.110.103.41 : (none) > show global variables like '%gtid%';
+---------------------------------+-------------------------------------------+
| Variable_name | Value |
+---------------------------------+-------------------------------------------+
| binlog_gtid_simple_recovery | OFF |
| enforce_gtid_consistency | ON |
| gtid_executed | a01f3a3f-1eee-11ea-b1e4-a0369fac2de4:1-30 |
| gtid_mode | ON |
| gtid_owned | |
| gtid_purged | a01f3a3f-1eee-11ea-b1e4-a0369fac2de4:1-26 |
| simplified_binlog_gtid_recovery | OFF |
+---------------------------------+-------------------------------------------+
7 rows in set (0.00 sec)
6)change master开启复制功能
可以在启动slave线程之前使用gtid_purged变量来指定需要跳过的gtid集合。但因为要设置gtid_purged必须保证全局变量gtid_executed为空,所以先在slave上执行reset master(注意,不是reset slave),再设置gtid_purged。
#在新的 slave上执行
#stop slave;
reset slave all;
reset master ;
show master logs;
+------------------+-----------+
| Log_name | File_size |
+------------------+-----------+
| mysql-bin.000001 | 151 |
+------------------+-----------+
set @@global.gtid_purged='a01f3a3f-1eee-11ea-b1e4-a0369fac2de4:1-30';
CHANGE MASTER TO MASTER_HOST='192.110.103.41', MASTER_PORT=3106, MASTER_USER='repl', MASTER_PASSWORD='repl',MASTER_AUTO_POSITION = 1;
start slave;
192.110.103.43 : (none) > show slave status\G
*************************** 1. row ***************************
Slave_IO_State: Waiting for master to send event
Master_Host: 192.110.103.41
Master_User: repl
Master_Port: 3106
Master_Log_File: mysql-bin.000006
Read_Master_Log_Pos: 964
Relay_Log_File: relay-bin.000002
Relay_Log_Pos: 408
Relay_Master_Log_File: mysql-bin.000006
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
Skip_Counter: 0
Exec_Master_Log_Pos: 964
Seconds_Behind_Master: 0
Master_Server_Id: 103413106
Master_UUID: a01f3a3f-1eee-11ea-b1e4-a0369fac2de4
Executed_Gtid_Set: a01f3a3f-1eee-11ea-b1e4-a0369fac2de4:1-30
Auto_Position: 1
1 row in set (0.00 sec)
#
192.110.103.43 : (none) > show master status;
+------------------+----------+--------------+------------------+-------------------------------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+------------------+----------+--------------+------------------+-------------------------------------------+
| mysql-bin.000002 | 191 | | | a01f3a3f-1eee-11ea-b1e4-a0369fac2de4:1-30 |
+------------------+----------+--------------+------------------+-------------------------------------------+
1 row in set (0.00 sec)
查看binlog文件内容
/usr/local/mysql/bin/mysqlbinlog -v --base64-output=decode-rows mysql-bin.000002
##
DELIMITER /*!*/;
# at 4
#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
# Warning: this binlog is either in use or was not closed properly.
# at 120
#191216 11:53:44 server id 103433106 end_log_pos 191 CRC32 0xccbdbaae Previous-GTIDs
# a01f3a3f-1eee-11ea-b1e4-a0369fac2de4:1-30
DELIMITER ;
# End of log file
ROLLBACK /* added by mysqlbinlog */;
5. GTID常见问题处理
5.1 跳过GTID复制错误
在基于 GTID 的复制拓扑中,要想修复从库的 SQL 线程错误,过去的 SQL_SLAVE_SKIP_COUNTER 方式不再适用。需要通过设置 gtid_next 或 gtid_purged 来完成,当然前提是已经确保主从数据一致,仅仅需要跳过复制错误让复制继续下去。
【现象】
192.110.103.43 : test > show slave status\G
*************************** 1. row ***************************
Slave_IO_State: Waiting for master to send event
Master_Host: 192.110.103.41
Master_User: repl
Master_Port: 3106
Master_Log_File: mysql-bin.000007
Slave_IO_Running: Yes
Slave_SQL_Running: No
Last_Errno: 1062
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
Skip_Counter: 0
Seconds_Behind_Master: NULL
Master_SSL_Verify_Server_Cert: No
Last_SQL_Errno: 1062
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
Retrieved_Gtid_Set: a01f3a3f-1eee-11ea-b1e4-a0369fac2de4:31-35
Executed_Gtid_Set: a01f3a3f-1eee-11ea-b1e4-a0369fac2de4:1-34,
bb35a83e-1fb2-11ea-b6e3-a0369fa6cd30:1
Auto_Position: 1
【原因】
从库和主库数据不一致,从库存在Duplicate entry ,导致同步异常。
【处理】
以前非GTID可以如下,
#普通复制
stop slave;
set global sql_slave_skip_counter = 1;
start slave;
但是GTID复制执行sql_slave_skip_counter将会出错。
#若是GTID复制时将会出错
set global sql_slave_skip_counter = 1;
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复处理方法如下:
#master
flush logs;
192.110.103.41 : test > show master status;
show global variables like '%gtid%';
show binlog events in 'mysql-bin.000007';
#slave
由于在这个GTID必须是连续的,正常情况同一个服务器产生的GTID是不会存在空缺的。所以不能简单的skip掉一个事务,只能通过注入空事物的方法替换掉一个实际操作事务。
192.110.103.43 : test >show slave status\G
当前Executed_Gtid_Set的值a01f3a3f-1eee-11ea-b1e4-a0369fac2de4:1-34
Retrieved_Gtid_Set: a01f3a3f-1eee-11ea-b1e4-a0369fac2de4:31-35
Executed_Gtid_Set: a01f3a3f-1eee-11ea-b1e4-a0369fac2de4:1-34,
bb35a83e-1fb2-11ea-b6e3-a0369fa6cd30:1
#处理:
stop slave;
set gtid_next='a01f3a3f-1eee-11ea-b1e4-a0369fac2de4:35'; --(last_executed_slave_gtid_on_master + 1)
begin;commit;
set gtid_next='AUTOMATIC';
start slave;
show slave status\G;
设置gtid_next的方法一次只能跳过一个事务,要批量的跳过事务可以通过设置gtid_purged完成。
5.2 从库同步error 1236 ,master has purged binary logs
【现象】
192.110.103.43 : test > show slave status\G
*************************** 1. row ***************************
Slave_IO_State:
Master_Host: 192.110.103.41
Master_User: repl
Master_Port: 3106
Connect_Retry: 60
Master_Log_File:
Relay_Log_File: relay-bin.000001
Relay_Log_Pos: 4
Slave_IO_Running: No
Slave_SQL_Running: Yes
Skip_Counter: 0
Seconds_Behind_Master: 0
Last_IO_Errno: 1236
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.'
Master_UUID: a01f3a3f-1eee-11ea-b1e4-a0369fac2de4
Slave_SQL_Running_State: Slave has read all relay log; waiting for the slave I/O thread to update it
Retrieved_Gtid_Set:
Executed_Gtid_Set: a01f3a3f-1eee-11ea-b1e4-a0369fac2de4:35-36
Auto_Position: 1
【原因】
该错误常是发现在从库的io进程从主库拉取日志时,主库上的binlog被删除了,导致从库获取不到对应的binglog file。
【解决】
方法1: 使用mysqldump或xtrabackup重新搭建GTID从库。
方法2:
在master执行,查看被purge的GTID:
在主上执行,查看被purge的GTID:
192.110.103.41 : test > flush logs;
192.110.103.41 : test > purge master logs to 'mysql-bin.000008';
Query OK, 0 rows affected (0.00 sec)
192.110.103.41 : test > show global variables like 'gtid_purged';
+---------------+-------------------------------------------+
| Variable_name | Value |
+---------------+-------------------------------------------+
| gtid_purged | a01f3a3f-1eee-11ea-b1e4-a0369fac2de4:1-36 |
+---------------+-------------------------------------------+
在从上执行,跳过这个GTID:
192.110.103.43 : test > stop slave;
Query OK, 0 rows affected (0.00 sec)
192.110.103.43 : test > set global gtid_purged = 'a01f3a3f-1eee-11ea-b1e4-a0369fac2de4:1-36';
ERROR 1840 (HY000): @@GLOBAL.GTID_PURGED can only be set when @@GLOBAL.GTID_EXECUTED is empty.
192.110.103.43 : test > reset master;
Query OK, 0 rows affected (0.00 sec)
192.110.103.43 : test > set global gtid_purged = 'a01f3a3f-1eee-11ea-b1e4-a0369fac2de4:1-36';
Query OK, 0 rows affected (0.00 sec)
192.110.103.43 : test > show global variables like '%gtid%';
+---------------------------------+-------------------------------------------+
| Variable_name | Value |
+---------------------------------+-------------------------------------------+
| binlog_gtid_simple_recovery | OFF |
| enforce_gtid_consistency | ON |
| gtid_executed | a01f3a3f-1eee-11ea-b1e4-a0369fac2de4:1-36 |
| gtid_mode | ON |
| gtid_owned | |
| gtid_purged | a01f3a3f-1eee-11ea-b1e4-a0369fac2de4:1-36 |
| simplified_binlog_gtid_recovery | OFF |
+---------------------------------+-------------------------------------------+
7 rows in set (0.00 sec)
192.110.103.43 : test > start slave;
Query OK, 0 rows affected (0.00 sec)
#发现同步正常
192.110.103.43 : test > show slave status\G
*************************** 1. row ***************************
Slave_IO_State: Waiting for master to send event
Master_Host: 192.110.103.41
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
Seconds_Behind_Master: 0
Slave_SQL_Running_State: Slave has read all relay log; waiting for the slave I/O thread to update it
Master_Retry_Count: 86400
Retrieved_Gtid_Set:
Executed_Gtid_Set: a01f3a3f-1eee-11ea-b1e4-a0369fac2de4:1-36
Auto_Position: 1
5.3 主库故障进行切换,恢复服务
【现象】
有一MySQL集群,Server1为主,Server2,Server3为从库。某天Server1故障,需要恢复服务。
【处理】
1)选择新的主库
主有故障时:(切换步骤,需要把其中的一个从设置为主,另一个设置为其的从库)
1:检查从库上,完成事务的从,谁最接近主库
server2: show salve status\G;
Master_Log_File: mysql-bin3306.000002 ---(越大越接近)
Read_Master_Log_Pos: 4156773
Exec_Master_Log_Pos: 4156773
server3: show salve status\G;
Master_Log_File: mysql-bin3306.000001 ---(越大越接近)
Read_Master_Log_Pos: 83795320
Exec_Master_Log_Pos: 83795320
相比之下server2完成的事务要比server3更接近或则等于server1,现在需要把server3设置为server2的从库。
2)切换
从库server3,上重新指定主库信息(指向server2)
mysql> stop slave; #千万不要执行 reset master,否则会从最先的GTID上开始执行。
change master to master_host='192.x.x.41',master_user='rep',master_password='rep',master_port=3306,master_auto_position=1; #指定到server2从上
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介绍
- Mysql基于GTID复制模式-运维小结
- https://www.cnblogs.com/abobo/p/4242417.html
- https://dbaplus.cn/news-11-857-1.html