GTID

一、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

三、GTID主从复制

2.1 GTID的工作原理

  1. 当一个事务在主库端执行并提交时,产生GTID,一同记录到binlog日志中 [SET @@SESSION.GTID_NEXT]。
  2. binlog传输到slave,并存储到slave的relaylog后,开始重做。
  3. 执行SET @@SESSION.GTID_NEXT,从库对比[Executed_Gtid_Set] 是否执行过。
  4. 如果有记录,说明该GTID的事务已经执行,slave会忽略;
  5. 如果没有记录,
    1. 在读取执行事务前会先检查其他session持有该GTID,确保不被重复执行。
    2. slave就会执行该GTID事务,并记录[Executed_Gtid_Set],
注意:从库执行relay log ,记录binlog时,还是记录主库的GTID,不会产生新的GTID号

2.2 启动GTID的关键步骤

由最初的GTID复制拓扑(包括一个主站和一个从站)构成的启动过程中的关键步骤如下:
  1. 如果复制已经在运行,则通过使这两个服务器成为只读方式来同步.
    1. mysql> SET @@global.read_only = ON;
  2. 停止两个服务器。
    1. shell> mysqladmin -uusername -p shutdown;
  3. 重新启动启用GTID的两个服务器,并配置正确的选项。
    1. gtid_mode=ON 
    2. enforce-gtid-consistency=true
  4. 指示从机使用主机作为复制数据源,并使用自动定位,然后启动从机。
    1. mysql> CHANGE MASTER TO> MASTER_HOST = host, MASTER_PORT = port, MASTER_USER = user, MASTER_PASSWORD = password, MASTER_AUTO_POSITION = 1;
    2. mysql> START SLAVE;
  5. 在两台服务器上再次启用读取模式,以便它们可以接受更新。
    1. 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,可以用命令:
logged_gtids 用来判断 MySQL 有没有执行某个事务。例如,在 Master 发送 binlog 时,MySQL 5.6 能够根据 Slave 提供的 logged_gtids 记录,自动过滤 binlog 中不需要执行的事务
2. gtid_purged
记录从 binlog 删除的全局事务 ID 集合。它对应的 MySQL Global variable 是:gtid_purged 。
每当 MySQL 5.6 调用 purge_logs 删除 binlog 时,会顺带更新 gtid_purged 的内容。这是通过读剩下的 binlog 文件实现的
3.  gtid_owned
正在由线程执行的全局事务 ID 集合。它对应的 MySQL variable 是:gtid_owned
4. gtid_next
  • 取值:
    • 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 G
          Last_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 exist
          Retrieved_Gtid_Set: 59fe7a3e-9dd6-11e7-9d6c-000c29e57c69:1-17
          Executed_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 G
          Retrieved_Gtid_Set: 59fe7a3e-9dd6-11e7-9d6c-000c29e57c69:1-22
          Executed_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.sql 
mysql> 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_info
SET 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

     
原文地址:https://www.cnblogs.com/jesper/p/7623939.html