GTID定义:
定义: | GTID即全局事务ID(global transaction identifier),一个事物对应一个GTID |
引入: | MySQL-5.6.5开始支持,MySQL-5.6.10后开始完善 |
组成: | GTID = server_uuid :transaction_id |
server_uuid | 首次启动时 MySQL 会自动生成一个 server_uuid,并且保存到 auto.cnf 文件,一个实例对应一个server_uuid |
transaction_id | 从 1 开始的自增计数,表示在这个主库上执行的第 n 个事务 |
开启GTID:
[mysqld] | |
#GTID | |
gtid_mode=on | 开启GTID |
enforce-gtid-consistency = on | 启用强一致性检查,避免create table...select操作 |
log-slave-updates=1 | 允许下端接入slave |
#binlog | |
log-bin=mysql-bin | 开启binlog |
binlog_format=row | binlog格式为row模式 |
GTID优缺点:
优点:
-
slave在做同步复制时,无须找到binlog日志和POS点,直接change master to master_auto_position=1即可,自动找点同步
-
搭建主从复制简单
缺点:
-
GTID同步复制是基于事务。所以Myisam表不支持,这可能导致多个GTID分配给同一个事务;
-
CREATE TABLE ...SELECT语句不支持。因为该语句会被拆分成createtable 和insert两个事务,并且这个两个事务被分配了同一个GTID,这会导致insert被备库忽略掉;
-
不支持CREATE TEMPORARY TABLE、DROP TEMPORARYTABLE 临时表操作;
-
Errant transaction问题:即从库不能进行任何事物型操作,会引入新的GTID,当binlog被清除后,再进行主从切换,会导致其他从库找不到此GTID,从而挂载不上
GTID原理:
GTID的最大特性就是它的Failover能力,如下架构,当主库A crash时,需要进行主从切换,将B或C其中一台提升为主,传统模式我们无法确认哪台数据较新,由于同一个事务在每台机器上所在的binlog名字和位置都不一样,那么怎么找到C当前同步停止点,对应B的master_log_file和master_log_pos,需要通过程序对比或者借助MHA等工具。
GTID出现后,这个问题就显得非常简单。由于同一事务的GTID在所有节点上的值一致,那么根据C
当前停止点的GTID就能唯一定位到B
上的GTID。甚至由于MASTER_AUTO_POSITION
功能的出现,我们都不需要知道GTID的具体值,直接使用CHANGE MASTER TO MASTER_HOST='xxx', MASTER_AUTO_POSITION=1
命令就可以直接完成failover的工作。
GTID主要参数说明:
show global variables like '%gtid%';
gtid_next | session级别,指定下一个GTID获取的方式,默认AUTOMATIC | 使用下一个自动产生的GTID,slave解析binlog,将GTID赋给gtid_next并于下一个事务使用此GTID; |
gtid_executed | 实例已执行的所有GTID集合 | slave使用GTID前先做检查,确保其没被使用过; reset master会将其重置为空; |
gtid_owned | 只读变量,分别描述session和global当前拥有的gtid集合 | 确保没有被其他session正在使用,多个客户端不可并发运行同一个事务; |
gtid_purged | 已清除的binlog中包含的GTID集合 | 服务器启动时,读取最旧binlog的previous_gtid_log_event并将其赋值; 每purge一个binlog,则重置一次; reset master会将其重置为空 |
GTID复制错误:
一、手动跳过错误事物(在从库上)
-
STOP SLAVE;
-
RESET MASTER;
-
SET @@GLOBAL.GTID_PURGED = 'f2b6c829-9c87-11e4-84e8-deadeb54b599:1-32';
-
START SLAVE;
上面这些命令的用意是,忽略 f2b6c829-9c87-11e4-84e8-deadeb54b599:32 这个GTID事务,下一次事务接着从 33 这个GTID开始,即可跳过上述错误。
注: 无论是否开启了GTID,都可以使用percona 的 pt-slave-restart工具去跳过错误。
二、Errant transaction问题修复:
此问题主要是采用GTID复制的情况下,在slave上进行了事物操作,此时这台slave就多出来一个或多个其他slave节点和master节点没有的事务。我们知道Binlog默认保留7天,7天后这些事物产生的binlog会被删除,当发生failover的时,这个slave被提升为主,由于其他从库已经找不到新主库事物所产生的binlog,此时其他从库会挂载不上,造成数据库单点,十分危险。
-
-
传统解决方案:通过在主库手动设置下一次事物GTID,执行一条空事物,实现跟从库一致
步骤 主 从 1 create table t1(id int);从库执行一个事物 2 show global variables like '%gtid%'
;| gtid_executed |984f9b33-2118-11e8-b4d2-8a5337dcf960:1-6 |
show global variables like '%gtid%'
;| gtid_executed | 9831a0f8-2118-11e8-b585-96f5258290c0:1,
984f9b33-2118-11e8-b4d2-8a5337dcf960:1-6
此时从库已经多了一个GTID
3 set gtid_next='9831a0f8-2118-11e8-b585-96f5258290c0:1'
;在session级别,指定此GTID给下一个事物
4 begin; 5 commit; 6 set gtid_next='automatic'; 7 show global variables like '%gtid%';
| gtid_executed | 9831a0f8-2118-11e8-b585-96f5258290c0:1,
984f9b33-2118-11e8-b4d2-8a5337dcf960:1-6
此时跟从库已经一致
-
通过类似一种“欺骗”方(优先选择此方式,无需操作主库)
我们可能知道从库是不允许有事物直接写入的,可能为了测试某条事物是否正确,这条事物生成的GTID完全可以不要,但是gtid_executed是不允许删除的。我们是否有其他方式呢?
通过上面的解释可以知道:
gtid_purged:已清除的binlog中包含的GTID集合,purged掉的GTID会包含到gtid_executed中;
gtid_executed:用来保存已经执行过的GTID,当reset master时,此值会被清空;
知道了这两点,我们是否可以通过reset master来清空gtid_executed,再手动指定gtid_purged,来同步到gtid_executed中来实现跟主库一致。
-
步骤 | 主 | 从 |
1 | create table t1(id int);从库执行一个事物 | |
2 | show global variables like '%gtid%';| gtid_executed |984f9b33-2118-11e8-b4d2-8a5337dcf960:1-6 | | show global variables like '%gtid%';| gtid_executed | 9831a0f8-2118-11e8-b585-96f5258290c0:1,984f9b33-2118-11e8-b4d2-8a5337dcf960:1-6此时从库已经多了一个GTID |
3 | stop slave; | |
4 | reset master; | |
5 | set @@GLOBAL.GTID_PURGED = '984f9b33-2118-11e8-b4d2-8a5337dcf960:1-6'; | |
6 | start slave; | |
7 | show global variables like '%gtid%';| gtid_executed |984f9b33-2118-11e8-b4d2-8a5337dcf960:1-6 |此时gtid_executed已经和主库一致 |
-
-
mysqlslavetrx优雅处理方式
此方法使用较少,不做详细介绍,可以查看官方文档
https://dev.mysql.com/doc/mysql-utilities/1.6/en/mysqlslavetrx.html
-
-
- https://www.percona.com/blog/2015/12/02/gtid-failover-with-mysqlslavetrx-fix-errant-transactions/
避免产生errant transaction问题,可以通过set sql_log_bin=off的方式在slave执行,执行后记得打开,但是也要考虑到数据一致性,若使用GTID,尽量少在从库操作。
来自http://mp.weixin.qq.com/s?__biz=MzA3NTMyNTI0NA==&mid=2648440901&idx=1&sn=8470ea6d5da066b21a7265e89ab68c20&chksm=875aea16b02d6300fe3aa283e136b4a54c2bb1a27fa7776bdb5382016c4c42488bb1a0174fdf&mpshare=1&scene=23&srcid=0312OtRIExO3qFgH76rNUVnv#rd