问题引入:前面讲解了如何搭建主从复制,在实验的时候,我发现一个问题,如果是GTID模式,比如 从库缺少一条数据,重启主从的时候,不用再从库set global sql_slave_skip_counter=1;直接start slave 就把数据同步过来了,这是为什么呢?
原因:开启GTID以后,无法使用sql_slave_skip_counter跳过事务,因为主库会把从库缺失的GTID,发送给从库,所以skip是没有用的。
GTID即全局事务ID (global transaction identifier), 其保证为每一个在主上提交的事务在复制集群中可以生成一个唯一的ID。GTID最初由google实现,官方MySQL在5.6才加入该功能。mysql主从结构在一主一从情况下对于GTID来说就没有优势了,而对于2台主以上的结构优势异常明显,可以在数据不丢失的情况下切换新主。使用GTID需要注意: 在构建主从复制之前,在一台将成为主的实例上进行一些操作(如数据清理等),通过GTID复制,这些在主从成立之前的操作也会被复制到从服务器上,引起复制失败。也就是说通过GTID复制都是从最先开始的事务日志开始,即使这些操作在复制之前执行。比如在server1上执行一些drop、delete的清理操作,接着在server2上执行change的操作,会使得server2也进行server1的清理操作。

gtid_executed

在当前实例上执行过的 GTID 集合,实际上包含了所有记录到 binlog 中的事务。设置 set sql_log_bin=0 后执行的事务不会生成 binlog 事件,也不会被记录到 gtid_executed 中。执行 RESET MASTER 可以将该变量置空。
gtid_purgedbinlog不可能永远驻留在服务上,需要定期进行清理(通过 expire_logs_days 可以控制定期清理间隔),否则迟早它会把磁盘用尽。gtid_purged 用于记录本机上已经执行过,但是已经被清除了的 binlog 事务集合。它是 gtid_executed 的子集。只有 gtid_executed 为空时才能手动设置该变量,此时会同时更新 gtid_executed 为和 gtid_purged 相同的值。
gtid_executed 为空意味着要么之前没有启动过基于 GTID 的复制,要么执行过 RESET MASTER。执行 RESET MASTER 时同样也会把 gtid_purged 置空,即始终保持 gtid_purged 是 gtid_executed 的子集。
purge binary logs to 'mysql-bin3306.000003'; #日志被purge
gtid_next会话级变量,指示如何产生下一个GTID。可能的取值如下:-AUTOMATIC: 自动生成下一个 GTID,实现上是分配一个当前实例上尚未执行过的序号最小的 GTID。-ANONYMOUS: 设置后执行事务不会产生GTID。-显式指定的GTID: 可以指定任意形式合法的 GTID 值,但不能是当前 gtid_executed 中的已经包含的 GTID,否则下次执行事务时会报错。
GTID的优缺点
GTID的优点1、一个事务对应一个唯一ID,一个GTID在一个服务器上只会执行一次;2、GTID是用来代替传统复制的方法,GTID复制与普通复制模式的最大不同就是不需要指定二进制文件名和位置;3、减少手工干预和降低服务故障时间,当主机挂了之后通过软件从众多的备机中提升一台备机为主机;
GTID复制是怎么实现自动同步,自动对应位置的呢?比如这样一个主从架构:ServerC <-----ServerA ----> ServerB即一个主数据库ServerA,两个从数据库ServerB和ServerC
当主机ServerA 挂了之后 ,此时ServerB执行完了所有从ServerA 传过来的事务,ServerC 延时一点。这个时候需要把 ServerB 提升为主机 ,Server C 继续为备机;当ServerC 链接ServerB 之后,首先在自己的二进制文件中找到从ServerA传过来的最新的GTID,然后将这个GTID 发送到ServerB ,ServerB 获得这个GTID之后,就开始从这个GTID的下一个GTID开始发送事务给ServerC。这种自我寻找复制位置的模式减少事务丢失的可能性以及故障恢复的时间。
GTID的缺点(限制)1、不支持非事务引擎;2、不支持create table ... select 语句复制(主库直接报错);(原理: 会生成两个sql, 一个是DDL创建表SQL, 一个是insert into 插入数据的sql; 由于DDL会导致自动提交, 所以这个sql至少需要两个GTID, 但是GTID模式下, 只能给这个sql生成一个GTID)3、不允许一个SQL同时更新一个事务引擎表和非事务引擎表;4、在一个复制组中,必须要求统一开启GTID或者是关闭GTID;5、开启GTID需要重启 (mysql5.7除外);6、 开启GTID后,就不再使用原来的传统复制方式;7、 对于create temporary table 和 drop temporary table语句不支持;8、不支持sql_slave_skip_counter;
在线开启步骤:
1、要求:
(1)必须是5.7.6版本以上的mysql
(2)GTID状态为OFF
2、开启步骤:
(1):SET GLOBAL ENFORCE_GTID_CONSISTENCY = 'WARN';
(2):SET GLOBAL ENFORCE_GTID_CONSISTENCY = 'ON';
(3):SET GLOBAL GTID_MODE = 'OFF_PERMISSIVE';
(4):SET GLOBAL GTID_MODE = 'ON_PERMISSIVE';
(5):SET GLOBAL GTID_MODE = 'ON';
3、要永久启用,在my.cnf配置文件中添加参数:
gtid-mode=ON
enforce-gtid-consistency
在线关闭步骤:
1、要求:
(1)必须是5.7.6版本以上的mysql
(2)GTID状态为OFF
2、关闭步骤:
(1):stop slave;
(2):SET GLOBAL GTID_MODE = 'ON_PERMISSIVE';
(3):SET GLOBAL GTID_MODE = 'OFF_PERMISSIVE';
(4):SET GLOBAL GTID_MODE = 'OFF';
注:
每次开启和关闭时,都是这样一个过程:
打开-->过度模式-->完全打开
停止-->过度模式-->完全关闭

GTID如何跳过事务
开启GTID以后,无法使用sql_slave_skip_counter跳过事务,因为主库会把从库缺失的GTID,发送给从库,所以skip是没有用的。为了提前发现问题,在gtid模式下,直接禁止使用
set global sql_slave_skip_counter =x。正确的做法: 通过
set grid_next= 'aaaa'('aaaa'为待跳过的事务),然后执行BIGIN; 接着COMMIT产生一个空事务,占据这个GTID,再START SLAVE,会发现下一条事务的GTID已经执行过,就会跳过这个事务了如果一个GTID已经执行过,再遇到重复的GTID,从库会直接跳过,可看作GTID执行的幂等性。

主库上查找

如果是pos 872,则找到对应的GTID


GTID跳过复制错误的方法总结
1)对于跳过一个错误,找到无法执行事务的编号,比如是2a09ee6e-645d-11e7-a96c-000c2953a1cb:1-10



