4

MySQL--GTID是什么

 1 year ago
source link: https://blog.51cto.com/u_13874232/5692063
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

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 table 和 drop 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执行的幂等性。

因为是通过GTID来进行复制的,也需要跳过这个事务从而继续复制,这个事务可以到主上的binlog里面查看:因为不知道找哪个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;

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK