先说一下mysql5.5跳过事务方法
GTID跳过有两种方法,一种是普通的跳过一个事务的方法,另外一个是在基于主库搭建新的slave的时候.
一、普通跳过一个事务的方法。
通过show slave status\G找到冲突的GTID号.
然后执行
SET gtid_next = ‘冲突的GTID号’;
BEGIN;COMMIT;
SET gtid_next = ‘AUTOMATIC’;
START SLAVE;
这就可以跳过一个事务了,原理在于通过执行一个空事务代替master传递过来的冲突事务.
二、通过备份的dump.sql文件搭建新的slave.
开启gtid以后,使用mysqldump备份,一般系统会要求你使用–all-databases参数,避免主库和从库有部分数据不一致。
备份以后,dump.sql里面会有这样一条语句.
SET @@GLOBAL.GTID_PURGED='0140505e-4230-11e4-b7c9-000c29da163d:1-8,dd079e18-4244-11e4-b851-000c29da163e:1-2';
这个就是当前主库已经执行过的GTID,也就是dump.sql里面的数据已经包含的GTID,对于这些GTID,slave是不用执行了,所以我们需要设置slave从这些
GTID以后开始复制.方法就是上面这条sql.
将dump.sql直接导入到slave以后.就可以直接change master了.
如果你是想通过这个方法跳过某个或者某些GTID,那么有点不同了.
set @@GLOBAL.GTID_PURGED是有要求的,也就是GTID_PURGED必须为空才可以设置,如何把GTID_PURGED清空呢.也就是需要执行
(root:hostname)[test]> show global variables like '%gtid%'; +--------------------------+-------------------------------------------------------------------------------------------------------------------------------+ | Variable_name | Value | +--------------------------+-------------------------------------------------------------------------------------------------------------------------------+ | enforce_gtid_consistency | ON | | gtid_executed | 0140505e-4230-11e4-b7c9-000c29da163d:1-25, dd079e18-4244-11e4-b851-000c29da163e:1-2, dda2f003-4244-11e4-b851-000c29da163f:1-3 | | gtid_mode | ON | | gtid_owned | | | gtid_purged | 0140505e-4230-11e4-b7c9-000c29da163d:1-8, dd079e18-4244-11e4-b851-000c29da163e:1-2 | +--------------------------+-------------------------------------------------------------------------------------------------------------------------------+ 5 rows in set (0.00 sec) (root:hostname)[test]> reset master; Query OK, 0 rows affected (0.02 sec) (root:hostname)[test]> show global variables like '%gtid%'; +--------------------------+-------+ | Variable_name | Value | +--------------------------+-------+ | enforce_gtid_consistency | ON | | gtid_executed | | | gtid_mode | ON | | gtid_owned | | | gtid_purged | | +--------------------------+-------+ 5 rows in set (0.00 sec) (root:hostname)[test]> stop slave; //清掉SLAVE信息. (root:hostname)[test]> reset slave all;然后设置gtid_purged,这个ID就是你要跳过过的GTID,注意这里GTID还要包含gtid_executed里面其他UUID的GTID(本机的可以不再设置了)。
(root:hostname)[test]> set @@global.gtid_purged='0140505e-4230-11e4-b7c9-000c29da163d:1-25,dd079e18-4244-11e4-b851-000c29da163e:1-2'; Query OK, 0 rows affected (0.03 sec) (root:hostname)[test]> CHANGE MASTER TO MASTER_HOST='192.168.153.150', MASTER_PORT=3306, MASTER_USER='slave',MASTER_PASSWORD='slave', master_auto_position=1; Query OK, 0 rows affected, 2 warnings (0.20 sec) (root:hostname)[test]> start slave; Query OK, 0 rows affected, 1 warning (0.03 sec) CHANGE MASTER TO MASTER_HOST='192.168.1.136', MASTER_PORT=3306, MASTER_USER='dbadmin',MASTER_PASSWORD='123456', master_auto_position=1;
mysql 5.6 gids新特性
GTIDs是mysql-5.6用户比较感兴趣的新特性之一,感兴趣的原因在于,以前slave连接到master是一件有挑战的事情,但是启用了GTIDs以后,这件事情变得极其简单。
然而,使用GTIDs不是简单的使用唯一标识替换原来的binlog和偏移量,他是一种全新的复制协议,如果你没有认识到这一点,那么你很容易受伤.
复制协议对比:OLD VS NEW
老的协议相当于直接转发:slave连接一个指定的binary log文件和offset,master从这里开始发送所有的transactions。
新的协议有些不同:slave开始发送自己执行过的GTIDs给master,然后master发送所有slave丢失的transaction,并且保证所有一个事务对应的GTIDs只会发送给指定的slave一次.
在实际使用中,会有哪个不同呢?在下面这种情况,master执行了trx1,trx2,trx3,trx4这几个事务,slave执行了trx1,trx3这两个事务,某些原因导致了slave上trx2事务丢失.
在老的复制协议中,trx2将会丢失,而新的复制协议中,trx2将会被自动的执行。
关于skipping transactions
你需要知道以前的 set global sql_slave_skip_counter = N 在GTIDs协议中不在支持,代替方法是如果你要跳过GTID xxx:N,你需要插入一个空的transaction:
mysql>SET gtid_next= 'XXX:N'; mysql>BEGIN;COMMIT; mysql>SET gtid_next='AUTOMATIC';
为什么不能使用sql_slave_skip_counter?因为新的复制协议!
在一个环境中,有master,slave1,slave2.当slave2跳过了某一个trx以后.将slave2的master切换到slave1,这个时候将会出现两种情况
1、如果slave2丢失的trx存在于slave1的binlog中,那么slave2将再次执行这个trx,导致跳过sql_slave_skip_counters失效
2、如果slave2丢失的trx不存在于slave1的binlog中,那么你会得到一个复制错误。
使用sql_slave_skip_counter是非常不安全的,这也是GTIDs不支持它的原因.唯一安全的方法跳过一个transaction,就是执行一个伪造的transaction代替真实的transaction.
Errant transactions
如果你在slave本地执行的transaction,被称为Errant transactions。如果你把此slave提升为master,会发生什么?
如果使用的老的复制协议,基本上不会发生任何事情(正确的说,主从数据会存在不一致的问题.但是稍后可以修复).
如果使用新的复制协议,Errant transaction将会在failover的时候,定义为所有slave都缺失这个transaction,然后自动的让每个slave都执行.这可能会导致复制失败。
场景一:
# S1 mysql> CREATE DATABASE mydb; # M mysql> CREATE DATABASE IF NOT EXISTS mydb; # Thanks to 'IF NOT EXITS', replication doesn't break on S1. Now move S2 to S1: # S2 mysql> STOP SLAVE; CHANGE MASTER TO MASTER_HOST='S1'; START SLAVE; # This creates a conflict with existing data! mysql> SHOW SLAVE STATUS\G [...] Last_SQL_Errno: 1007 Last_SQL_Error: Error 'Can't create database 'mydb'; database exists' on query. Default database: 'mydb'. Query: 'CREATE DATABASE mydb'场景二:
# S1 mysql> CREATE DATABASE mydb; # Now, we'll remove this transaction from the binary logs # S1 mysql> FLUSH LOGS; mysql> PURGE BINARY LOGS TO 'mysql-bin.000008'; # M mysql> CREATE DATABASE IF NOT EXISTS mydb; # S2 mysql> STOP SLAVE; CHANGE MASTER TO MASTER_HOST='S1'; START SLAVE; # The missing transaction is no longer available in the master's binary logs! mysql> SHOW SLAVE STATUS\G [...] Last_IO_Errno: 1236 Last_IO_Error: Got fatal error 1236 from master when reading data from binary log: 'The slave is connecting using CHANGE MASTER TO MASTER_AUTO_POSITION = 1, but the master has purged binary logs containing GTIDs that the slave requires.'
你需要知道,如果使用GTIDs协议复制,需要尽量避免Errant transactions.如果你需要本地运行一个事务,可以使用关闭binlog的方式。使用这种方法也是非常危险的,一定要主要关闭的是session的,并且操作完,一定要打开。
mysql> SET SQL_LOG_BIN = 0; mysql> # Run local transaction
总结:
GTIDs能够让slave自动的从新连接到其他服务器复制,是mysql复制的一个伟大进步,但是同时也带来了新的维护挑战,如果你计划使用GTIDs,你需要正确的理解GTIDs协议,不然的话你可能会遇见新的或者其他意向不到的问题导致复制失败。