GTID主从
Gtid概念
从 MySQL 5.6.5 开始新增了一种基于 GTID 的复制方式。通过 GTID保证了每个在主库上提交的事务在集群中有一个唯一的ID。这种方式强化了数据库的主备一致性,故障恢复以及容错能力。
在原来基于二进制日志的复制中,从库需要告知主库要从哪个偏移量进行增量同步,如果指定错误会造成数据的遗漏,从而造成数据的不一致。借助GTID,在发生主备切换的情况下,MySQL的其它从库可以自动在新主库上找到正确的复制位置,这大大简化了复杂复制拓扑下集群的维护,也减少了人为设置复制位置发生误操作的风险。另外,基于GTID的复制可以忽略已经执行过的事务,减少了数据发生不一致的风险。
什么是Gitd
GTID (Global Transaction ID) 是对于一个已提交事务的编号,并且是一个全局唯一的编号。全局事务唯一编号,他是连续的,不重复的。
GTID 实际上 是由UUID+TID 组成的。其中 UUID 是一个 MySQL 实例的唯一标识(保存在auto.cnf中)。TID代表了该实例上已经提交的事务数量,并且随着事务提交单调递增
例如:77cf5494-00ce-11ec-9c86-000c290c7222:122
GTID 集合可以包含来自多个 MySQL 实例的事务,它们之间用逗号分隔。
如果来自同一MySQL实例的事务序号有多个范围区间,各组范围之间用冒号分隔。例如:77cf5494-00ce-11ec-9c86-000c290c7222:1-188,
f5fcd8f6-6053-11eb-98d4-000c290c7222:1-7可以使用show master status实时查看当前事务执行数
Gtid的作用
Gtid采用了新的复制协议,旧协议是,首先从服务器上在一个特定的偏移量位置连接到主服务器上一个给定的二进制日志文件,然后主服务器再从给定的连接点开始发送所有的事件。
新协议有所不同,支持以全局统一事务ID (GTID)为基础的复制。当在主库上提交事务或者被从库应用时,可以定位和追踪每一个事务。GTID复制是全部以事务为基础,使得检查主从一致性变得非常简单。如果所有主库上提交的事务也同样提交到从库上,一致性就得到了保证。
Gtid的工作原理
①当一个事务在主库端执行并提交时,产生GTID,一同记录到binlog日志中。
②binlog传输到slave,并存储到slave的relaylog后,读取这个GTID的这个值设置gtid_next变量,即告诉Slave,下一个要执行的GTID值。
③sql线程从relay log中获取GTID,然后对比slave端的binlog是否有该GTID。
④如果有记录,说明该GTID的事务已经执行,slave会忽略。
⑤如果没有记录,slave就会执行该GTID事务,并记录该GTID到自身的binlog,
在读取执行事务前会先检查其他session持有该GTID,确保不被重复执行。
⑥在解析过程中会判断是否有主键,如果没有就用二级索引,如果没有就用全部扫描
Gtid的优势
1.配置简单,change master to只需要master_auto_position=1,不用想传统主从指定pos点
2.基于 GTID 的复制可以忽略已经执行过的事务,减少了数据发生不一致的风险;
3.避免因为设置位点信息不准确而造成主从不一致的情况。
配置
gtid_mode=on
enforce_gtid_consistency=true #强制gtid号一致
log_slave_updates=1 #从库要写binlog
#主从都开启gtid
gtid_mode=on
enforce_gtid_consistency=true
log_slave_updates=1
从库上:
CHANGE MASTER TO
MASTER_HOST='192.168.190.128',
MASTER_USER='repl',
MASTER_PASSWORD='123456',
MASTER_PORT=3306,
master_auto_position=1,
MASTER_CONNECT_RETRY=10;
start slave;
恢复
#与传统主从一样,show binlog events in找到起点和终点的gtid范围
mysqlbinlog --skip-gtids --include-gtids='uuid:1-700' 二进制日志文件 > db.sql
#跳过某些gtid不截取需要使用参数--exclude-gtids=' '(例如跳过3和5)
mysqlbinlog --skip-gtids --include-gtids='uuid:1-700' --exclude-gtids='uuid:3,uuid:5' 二进制日志文件 > db.sql
一些方法:
方法一:自动同步主库
适用于master刚用不就,binlog都在
让新的从库master_auto_position=1,自动同步主库(前提是主库上要有所有binlog,且必须在一开始就用gtid)
原理是直接获取master所有的GTID并执行
优点:简单方便。
缺点:如果binlog太多,数据完全同步需要时间较长,并且master一开始就启用了GTUD。
方法二:
1、Xtrabackup_binlog_info文件中,包含global.gtid_purged=’XXXXXX:XXXX’的信息。
2、然后到slave去手工的 SET @@GLOBAL.GTID_PURGED=’XXXXXX:XXXX’。
3、恢复备份,开启change master to 命令。
方法三:
适用于拥有较大数据的情况。
1、通过master或者其他slave的备份搭建新的slave。
2、原理:获取master的数据和这些数据对应的GTID范围,然后通过slave设置master_auto_position=1,自动同步,跳过备份包含的gtid。
3、缺点:相对来说有点复杂。
注意点:
带有 GTID 信息的 dump 文件, 要求目标数据库实例必须开启 GTID 功能, 且当前数据库中无其他 GTID 信息. 如果目标数据库中已经记录了一条或一条以上的 GTID 信息, 那么在导入数据库时会报出类似如下的错误
ERROR 1840 (HY000) at line 24: @@GLOBAL.GTID_PURGED can only be set when @@GLOBAL.GTID_EXECUTED is empty
当前GTID_EXECUTED参数已经有值,而从集群倒出来的dump文件中包含了SET @@GLOBAL.GTID_PURGED的操作
GTID 从库误写入操作处理
例如主库创建某个表,从库因为已有这个表,从库sql线程执行失败,导致从库sql线程关闭
查看监控信息:
Last_SQL_Error: Error 'Can't create database 'oldboy'; database exists' on query. Default database: 'oldboy'. Query: 'create database oldboy'
Retrieved_Gtid_Set: 71bfa52e-4aae-11e9-ab8c-000c293b577e:1-3
Executed_Gtid_Set: 71bfa52e-4aae-11e9-ab8c-000c293b577e:1-2,
7ca4a2b7-4aae-11e9-859d-000c298720f6:1
注入空事物的方法:
stop slave;
set gtid_next='99279e1e-61b7-11e9-a9fc-000c2928f5dd:3';
begin;commit;
set gtid_next='AUTOMATIC';
这里的xxxxx:N 也就是你的slave sql thread报错的GTID,或者说是你想要跳过的GTID。
最好的解决方案:重新构建主从环境