一、GTID【Global Transaction Identifiers】
- GTID(Global Transaction Identifiers)是全局事务标识,GTID=server_uuid+transaction_id
- server_uuid,由于GTID会传递到slave,一个GTID在一个服务器上只执行一次
- transaction_id,为当前服务器上已提交事务的一个序列号,通常从1开始自增长的序列,一个数值对应一个事务。
- transaction_id 并不能代表执行顺序
- GTID采用MASTER_AUTO_POSTION=1代替传统复制(file+pos)
- GTID中slave端的binlog是必须开启的,目的是记录执行过的GTID(Executed_Gtid_Set)。
- GTID中包涵了server_uuid,方便了replication 的failove
二、GTID限制
1. 不支持非事务引擎
- 对于GTID不支持非事务引擎如何理解:
- 不支持非事务引擎不是不能建立myisam表、对myisam表DML
- innodb中一个事务中可以是多条SQL
- myisam中,一条DML生成一个GTID号,所以不支持事务
mysql> insert into user_myisam values (3,100); -- myisam每条sql自动提交,所以myisam中不存在事务的概念Executed_Gtid_Set: 59fe7a3e-9dd6-11e7-9d6c-000c29e57c69:1-68
2. 不支持create table … select 语句复制(主库直接报错)
mysql> create table t1 select * from user_innodb;ERROR 1786 (HY000): CREATE TABLE ... SELECT is forbidden when @@GLOBAL.ENFORCE_GTID_CONSISTENCY = 1.
3. 不允许在一个SQL同时更新一个事务引擎和非事务引擎的表
mysql> begin;mysql> update user_innodb set money=100 where id=1;mysql> update user_myisam set money=100 where id=1;ERROR 1785 (HY000): When @@GLOBAL.ENFORCE_GTID_CONSISTENCY = 1, updates to non-transactional tables can only be done in either autocommitted statements or single-statement transactions, and never in the same statement as updates to transactional tables.
4. 在一个复制组中,必须要求统一开启GTID或是关闭GTID
The slave IO thread stops because the master has @@GLOBAL.GTID_MODE ON and this server has @@GLOBAL.GTID_MODE OFF。
5. 对于create temporary table 和drop temporary table语句不支持
6. 不支持sql_slave_skip_counter
6. 不支持sql_slave_skip_counter
三、GTID主从复制
2.1 GTID的工作原理
- 当一个事务在主库端执行并提交时,产生GTID,一同记录到binlog日志中 [SET @@SESSION.GTID_NEXT]。
- binlog传输到slave,并存储到slave的relaylog后,开始重做。
- 执行SET @@SESSION.GTID_NEXT,从库对比[Executed_Gtid_Set] 是否执行过。
- 如果有记录,说明该GTID的事务已经执行,slave会忽略;
- 如果没有记录,
- 在读取执行事务前会先检查其他session持有该GTID,确保不被重复执行。
- slave就会执行该GTID事务,并记录[Executed_Gtid_Set],
2.2 启动GTID的关键步骤
由最初的GTID复制拓扑(包括一个主站和一个从站)构成的启动过程中的关键步骤如下:
- 如果复制已经在运行,则通过使这两个服务器成为只读方式来同步.
- mysql> SET @@global.read_only = ON;
- 停止两个服务器。
- shell> mysqladmin -uusername -p shutdown;
- 重新启动启用GTID的两个服务器,并配置正确的选项。
- gtid_mode=ON
- enforce-gtid-consistency=true
- 指示从机使用主机作为复制数据源,并使用自动定位,然后启动从机。
- mysql> CHANGE MASTER TO> MASTER_HOST = host, MASTER_PORT = port, MASTER_USER = user, MASTER_PASSWORD = password, MASTER_AUTO_POSITION = 1;
- mysql> START SLAVE;
- 在两台服务器上再次启用读取模式,以便它们可以接受更新。
- mysql> SET @@global.read_only = OFF;
2.3 数据和binlog的复制
1、数据的复制
- 使用mysql客户端导入使用mysqldump创建的转储文件。
- 在源服务器上使用的 --master-data 选项包括二进制日志信息,
- 并 --set-gtid-purged 以AUTO(默认),或者 ON,包括有关在转储执行交易的信息。
2、binlog的复制
2.4 GTID相关的参数
1. --enforce-gtid-consistency
服务器通过允许执行只能使用GTID安全地记录的语句来强制执行GTID一致性,影响:
CREATE TABLE ... SELECT 声明
CREATE TEMPORARY TABLE或 DROP TEMPORARY TABLE交易中的语句
更新事务性和非事务性表的事务或语句。
2. --gtid-mode
在MySQL 5.7.6及更高版本中,该 gtid_mode变量是动态的,并允许基于GTID的复制在线配置。
3. --gtid-executed-compression-period
该变量的默认值为1000; 这意味着,默认情况下,在每1000个事务之后执行表mysql.gtid_executed的压缩。
4. binlog_gtid_simple_recovery
5.7.7 之后默认值为on,只从最新的最老的binlogflie中计算得到gtid_purged and gtid_executed的值。
2.5、GTID相关变量
1. gtid_executed
存储已经执行过,并且记录到 binlog 的全局事务 ID 集合。它对应的 MySQL variable 是 gtid_executed,可以用命令:
2. gtid_purgedlogged_gtids 用来判断 MySQL 有没有执行某个事务。例如,在 Master 发送 binlog 时,MySQL 5.6 能够根据 Slave 提供的 logged_gtids 记录,自动过滤 binlog 中不需要执行的事务
3. gtid_owned记录从 binlog 删除的全局事务 ID 集合。它对应的 MySQL Global variable 是:gtid_purged 。每当 MySQL 5.6 调用 purge_logs 删除 binlog 时,会顺带更新 gtid_purged 的内容。这是通过读剩下的 binlog 文件实现的
4. gtid_next正在由线程执行的全局事务 ID 集合。它对应的 MySQL variable 是:gtid_owned
- 取值:
- AUTOMATIC: Use the next automatically-generated global transaction ID.
- ANONYMOUS: Transactions do not have global identifiers, and are identified by file and position only.
- A global transaction ID in UUID:NUMBER format.
- Setting this variable has no effect if gtid_mode is OFF.
- After this variable has been set to UUID:NUMBER,当发生一个事务设置为commit或rollback,需要再次声明这个变量的值。
四、GTID跳过单个、批量事务
1、概述
使用gtid跳过事务有两种方法:
1. set gtid_next,可以跳过单个事务
2. set GTID_PURGED,可以跳过多个事务
2、跳过单个事物
1、情景:
主新建了test.t1 表,从误操作删掉了test.t1;
主往test.t1中插入一条数据,从库报错
从库报错内容:
mysql> show slave status GLast_SQL_Error: Worker 3 failed executing transaction '59fe7a3e-9dd6-11e7-9d6c-000c29e57c69:17' at master log mysql-bin.000002, end_log_pos 3255; Error executing row event: 'Table 'test.t1' doesn't existRetrieved_Gtid_Set: 59fe7a3e-9dd6-11e7-9d6c-000c29e57c69:1-17Executed_Gtid_Set: 59fe7a3e-9dd6-11e7-9d6c-000c29e57c69:1-16,29bd8c99-9e4d-11e7-a072-000c29d00b2d:1,Auto_Position: 1
得知:
从库在执行59fe7a3e-9dd6-11e7-9d6c-000c29e57c69:17 这个事务时,因为从库没有这个表而报错了。
2、解决步骤:
root用户手动重建test.t1表
主库备份# mysqldump -uroot -p123123 -h127.0.0.1 --single-transaction --set-gtid-purged=off --triggers --routines --events test t1 >/tmp/t1.sql从库恢复# cat t1.sql |mysql -uroot -p123123 test
root用户手动在59fe7a3e-9dd6-11e7-9d6c-000c29e57c69:17 这个事务上执行一个空事务
> stop slave;> SET @@SESSION.GTID_NEXT= '59fe7a3e-9dd6-11e7-9d6c-000c29e57c69:17'/*!*/;> show variables like '%gtid%_next';> BEGIN;COMMIT;> SET gtid_next = 'AUTOMATIC';> START SLAVE;
3、批量跳过
1. 情景模拟
由于数据不一致严重,跳过单个事务不能继续正常复制。
从库删掉单表,然后跳过批量sql,继续复制
2. 操作步骤
1. 主库备份表
# mysqldump -uroot -p123123 -h127.0.0.1 --single-transaction --set-gtid-purged=on --triggers --routines --events test t1 >/tmp/t1.sql
2. 查看备份文件
# cat /tmp/t1.sql |egrep SET |egrep -v "^/"SET @MYSQLDUMP_TEMP_LOG_BIN = @@SESSION.SQL_LOG_BIN;SET @@SESSION.SQL_LOG_BIN= 0;SET @@GLOBAL.GTID_PURGED='59fe7a3e-9dd6-11e7-9d6c-000c29e57c69:1-22';) ENGINE=InnoDB DEFAULT CHARSET=latin1;SET @@SESSION.SQL_LOG_BIN = @MYSQLDUMP_TEMP_LOG_BIN;
3. 从库恢复
> reset master; //清空GTID_EXECUTED -- @@GLOBAL.GTID_PURGED can only be set when @@GLOBAL.GTID_EXECUTED is empty.# mysql -uroot -p123123 test < t1.sql -- 会执行备份文件中的SET @@GLOBAL.GTID_PURGED。> show slave status GRetrieved_Gtid_Set: 59fe7a3e-9dd6-11e7-9d6c-000c29e57c69:1-22Executed_Gtid_Set: 59fe7a3e-9dd6-11e7-9d6c-000c29e57c69:1-22> start slave;
五、GTID & 备份
1、逻辑备份
1. 与GTID相关的选项:
- --set-gtid-purged=[ON | OFF | AUTO ]
如果ON,在备份文件中会有以下两句
SET @@SESSION.SQL_LOG_BIN= 0;SET @@GLOBAL.GTID_PURGED=
若OFF则不写入
若AUTO,检测到GTID,自动添加上述语句,反之不加。
主从的Executed_Gtid_Set列表应该是一致的,也就是说,从库除了除了重做binlog之外,不能在从库上生成从库的GTID。
所以,用slave备份搭建slave,应该不记录binlog(SET @@SESSION.SQL_LOG_BIN= 0,恢复过程不产生从库的GTID),使用选项:--set-gtid-purged=ON
- --dump-slave、--master-data
在GTID中,不必使用dump-slave、--master-data,因为GTID中,不再使用传统复制中的 file 和 pos
2. 备份案列:用slave搭建slave
# mysqldump -uroot -p123123 --single-transaction --routines --events --set-gtid-purged=ON --all-databases >/tmp/10_2.sql# mysql </tmp/10_2.sqlmysql> CHANGE MASTER TO MASTER_HOST = '192.168.234.130', MASTER_PORT = 3306, MASTER_USER = 'repl', MASTER_PASSWORD = 'repl', MASTER_AUTO_POSITION = 1;mysql> start slave;
2、物理备份
备份的时候,只要在备份的时候记录下Executed_Gtid_Set($gtid_dump)即可,这个可以用于重新change master;
# innobackupex --defaults-file=/export/servers/mysql/etc/my.cnf --slave-info --user=root --password=123123 --no-timestamp /tmp/in.sql# cat xtrabackup_slave_infoSET GLOBAL gtid_purged='29bd8c99-9e4d-11e7-a072-000c29d00b2d:1-5, 59fe7a3e-9dd6-11e7-9d6c-000c29e57c69:1-68';CHANGE MASTER TO MASTER_AUTO_POSITION=1> reset master;> SET @@GLOBAL.GTID_PURGED='$gtid_dump'; //上面备份文件中的值> change master to master_auto_position=1;
六、GTID & 并行复制
1. 为了兼容MySQL 5.6基于库的并行复制,5.7引入了新的变量slave-parallel-type,其可以配置的值有:
DATABASE:默认值,基于库的并行复制方式LOGICAL_CLOCK:基于组提交的并行复制方式
2. MySQL 5.7才可称为真正的并行复制
这其中最为主要的原因就是master服务器上是怎么并行执行的slave上就怎样进行并行回放,一个组提交的事务都是可以并行回放。
3. 在MySQL 5.7版本中,其设计方式是将组提交的信息存放在GTID中。如果用户没有开启GTID功能,引入了称之为Anonymous_Gtid的概念。
较之原来的二进制日志内容多了last_committed和sequence_number;
last_committed表示事务提交的时候,上次事务提交的编号,如果事务具有相同的last_committed,表示这些事务都在一组内,可以进行并行的回放。
# mysqlbinlog -vv mysql-bin.000001 |egrep last_commit#171002 11:53:31 server id 1 end_log_pos 219 CRC32 0x4a9095a9 Anonymous_GTID last_committed=0 sequence_number=1#171002 11:53:31 server id 1 end_log_pos 473 CRC32 0x786dd106 Anonymous_GTID last_committed=1 sequence_number=2