MySQL–GTID是什么

GTID作用

主从环境中主库的dump线程可以直接通过GTID定位到需要发送的binary log的位置,而不需要指定binary log的文件名和位置,因而切换极为方便。

GTID实际上是由UUID+TID (即transactionId)组成的。其中UUID(即server_uuid) 产生于auto.conf文件(cat /data/mysql/data/auto.cnf),是一个MySQL实例的唯一标识。TID代表了该实例上已经提交的事务数量,并且随着事务提交单调递增,所以GTID能够保证每个MySQL实例事务的执行(不会重复执行同一个事务,并且会补全没有执行的事务)。GTID在一组复制中,全局唯一。 

对于2台主以上的结构优势异常明显,可以在数据不丢失的情况下切换新主。

通过GTID复制,这些在主从成立之前的操作也会被复制到从服务器上,引起复制失败。也就是说通过GTID复制都是从最先开始的事务日志开始,即使这些操作在复制之前执行。比如在server1上执行一些drop、delete的清理操作,接着在server2上执行change的操作,会使得server2也进行server1的清理操作。

直接使用CHANGE MASTER TO MASTER_HOST='xxx', MASTER_AUTO_POSITION命令就可以直接完成failover的工作。

GTID变量和表

gtid_executed 表

是GTID持久化的一个介质,实例重启后所有的内存信息都会丢失,GTID模块初始化需要读取GTID持久化介质。

gtid_executed变量

表示数据库中执行了哪些GTID,它是一个处于内存中的GTID SET。

gtid_purged变量

表示由于删除binary log,已经丢失的GTID event,它是一个处于内存中的GTID set。搭建从库时,通常需要使用set global gtid_purged命令设置本变量,用于表示这个备份已经执行了哪些gtid操作,手动删除binary log 不会更新这个变量。

gtid_executed变量和gtid_purged变量这两个变量分别表示,数据库执行了哪些GTID操作,又有哪些GTID操作由于删除binary log 已经丢失了。

变量更新时机

主库更新时机
(1)gtid_executed变量一定是实时更新的。在order commit的flush阶段生成GTID,在commit阶段才计入。
(2)mysql.executed表在binary log切换时更新
(3)gtid_purged变量在清理binary log时修改,比如purge binary logs 或者超过expire_logs_days的设置后

从库更新时机
log_slave_updates关闭
(1)从库mysql.executed 未开启log_slave_updates情况下,只能通过实时更新mysql.executed表来保存
(2)gtid_executed变量实时更新
(3)gtid_purged变量实时更新

log_slave_updates打开
从库mysql.executed 开启log_slave_updates情况下,更新和主库一模一样。

通用修改时机
gtid_executed 表
gtid_executed 表 在执行reset master ,set global gtid_purged命令时设置本表
gtid_executed变量
gtid_executed变量 reset aster清空本变量,set global gtid_executed命令时设置本变量
mysql启动时初始化设置

gtid_purged 变量
reset master清空本变量
set global gtid_purged 设置本变量
mysql启动初始化设置

GTID模块初始化流程

1、获取到server_uuid
2、读取mysql.gtid_executed表,但是该表不包含当前binlog的GTID
3、读取binlog,先反向扫描,获取最后一个binlog中包含的最新GITD,然后正向扫描,获取第一个binary log中的lost GTID。
4、将只在binlog的GTID加入mysql.gtid_executed表和gtid_executed变量。此时mysql.gtid_executed表和gtid_executed变量也正确了
5、初始化gtid_purged,扫描到的lost GTID。

开启GTID

MySQL 5.6 版本,在my.cnf文件中添加:

gtid_mode=on (必选)                    #开启gtid功能
log_bin=log-bin=mysql-bin (必选) #开启binlog二进制日志功能
log-slave-updates=1 (必选) #也可以将1写为on
enforce-gtid-consistency=1 (必选) #也可以将1写为on

MySQL 5.7或更高版本,在my.cnf文件中添加:

gtid_mode=on    (必选)
enforce-gtid-consistency=1 (必选)
log_bin=mysql-bin (可选) #高可用切换,最好开启该功能
log-slave-updates=1 (可选) #高可用切换,最好打开该功能

GTID的缺点

-  不支持非事务引擎;
- 不支持create table ... select 语句复制(主库直接报错);(原理: 会生成两个sql, 一个是DDL创建表SQL, 一个是insert into 插入数据的sql; 由于DDL会导致自动提交, 所以这个sql至少需要两个GTID, 但是GTID模式下, 只能给这个sql生成一个GTID)
- 不允许一个SQL同时更新一个事务引擎表和非事务引擎表;
- 在一个复制组中,必须要求统一开启GTID或者是关闭GTID;
- 开启GTID需要重启 (mysql5.7除外);
- 开启GTID后,就不再使用原来的传统复制方式;
- 对于create temporary tabledrop temporary table语句不支持;
- 不支持sql_slave_skip_counter;

GTID跳过事务的方法

开启GTID以后,无法使用sql_slave_skip_counter跳过事务,因为主库会把从库缺失的GTID,发送给从库,所以skip是没有用的。

为了提前发现问题,在gtid模式下,直接禁止使用set global sql_slave_skip_counter =x。

正确的做法: 通过set gtid_next= 'aaaa'('aaaa'为待跳过的事务),然后执行BIGIN; 接着COMMIT产生一个空事务,占据这个GTID,再START SLAVE,会发现下一条事务的GTID已经执行过,就会跳过这个事务了。如果一个GTID已经执行过,再遇到重复的GTID,从库会直接跳过,可看作GTID执行的幂等性。

1、show slave status里的信息里可以找到在执行Master里的POS:151
2、通过mysqlbinlog找到了GTID:
3、stop slave;
4、set session gtid_next='4e659069-3cd8-11e5-9a49-001c4270714e:1'
5、begin; commit;
6、SET SESSION GTID_NEXT = AUTOMATIC; #把gtid_next设置回来
7、start slave; #开启复制
1)对于跳过一个错误,找到无法执行事务的编号,比如是2a09ee6e-645d-11e7-a96c-000c2953a1cb:1-10
mysql> stop slave;
mysql> set gtid_next='2a09ee6e-645d-11e7-a96c-000c2953a1cb:1-10';
mysql> begin;
mysql> commit;
mysql> set gtid_next='AUTOMATIC';
mysql> start slave;

2)上面方法只能跳过一个事务,那么对于一批如何跳过?
在主库执行"show master status",看主库执行到了哪里,比如:2a09ee6e-645d-11e7-a96c-000c2953a1cb:1-33,那么操作如下:
mysql> stop slave;
mysql> reset master;
mysql> set global gtid_purged='2a09ee6e-645d-11e7-a96c-000c2953a1cb:1-33';
mysql> start slave;

如何升级成 GTID replication 

先介绍几个重要GTID_MODE的参数:
GTID_MODE = OFF
不产生Normal_GTID,只接受来自master的ANONYMOUS_GTID

GTID_MODE = OFF_PERMISSIVE
不产生Normal_GTID,可以接受来自master的ANONYMOUS_GTID & Normal_GTID

GTID_MODE = ON_PERMISSIVE
产生Normal_GTID,可以接受来自master的ANONYMOUS_GTID & Normal_GTID

GTID_MODE = ON
产生Normal_GTID,只接受来自master的Normal_GTID

归纳总结:
1)当master产生Normal_GTID的时候,如果slave的gtid_mode(OFF)不能接受Normal_GTID,那么就会报错
2)当master产生ANONYMOUS_GTID的时候,如果slave的gtid_mode(ON)不能接受ANONYMOUS_GTID,那么就会报错
3)设置auto_position的条件: 当master的gtid_mode=ON,slave可以为OFF_PERMISSIVE,ON_PERMISSIVE,ON
除此之外,都不能设置auto_position = on

============================================
下面开始说下如何online 升级为GTID模式?

step 1: 每台server执行
检查错误日志,直到没有错误出现,才能进行下一步
mysql> SET @@GLOBAL.ENFORCE_GTID_CONSISTENCY = WARN;

step 2: 每台server执行
mysql> SET @@GLOBAL.ENFORCE_GTID_CONSISTENCY = ON;

step 3: 每台server执行
不用关心一组复制集群的server的执行顺序,只需要保证每个Server都执行了,才能进行下一步
mysql> SET @@GLOBAL.GTID_MODE = OFF_PERMISSIVE;

step 4: 每台server执行
不用关心一组复制集群的server的执行顺序,只需要保证每个Server都执行了,才能进行下一步
mysql> SET @@GLOBAL.GTID_MODE = ON_PERMISSIVE;

step 5: 在每台server上执行,如果ONGOING_ANONYMOUS_TRANSACTION_COUNT=0就可以
不需要一直为0,只要出现过0一次,就ok
mysql> SHOW STATUS LIKE 'ONGOING_ANONYMOUS_TRANSACTION_COUNT';

step 6: 确保所有anonymous事务传递到slave上了
#master上执行
mysql> SHOW MASTER STATUS;

#每个slave上执行
mysql> SELECT MASTER_POS_WAIT(file, position);

或者,等一段时间,只要不是大的延迟,一般都没问题

step 7: 每台Server上执行
mysql> SET @@GLOBAL.GTID_MODE = ON;

step 8: 在每台server上将my.cnf中添加好gtid配置
gtid_mode=on
enforce-gtid-consistency=1
log_bin=mysql-bin
log-slave-updates=1

step 9: 在从机上通过change master语句进行复制
mysql> STOP SLAVE;
mysql> CHANGE MASTER TO MASTER_AUTO_POSITION = 1;
mysql> START SLAVE;
发表评论

相关文章