GTID主从

1.基本概念

MySQL 5.6 的新特性之一,全局事务标识符(GTID)是创建的唯一标识符,并与在源(主)服务器上提交的每个事务相关联。此标识符不但是唯一的,而且在给定复制设置中的所有服务器上都是唯一的。所有交易和所有GTID之间都有一对一的映射关系 。它由服务器ID以及事务ID组合而成。这个全局事务ID不仅仅在原始服务器上唯一,在所有存在主从关系 的mysql服务器上也是唯一的。正是因为这样一个特性使得mysql的主从复制变得更加简单,以及数据库一致性更可靠。一个GTID在一个服务器上只执行一次,避免重复执行导致数据混乱或者主从不一致。

657FDG47-4TSR-34QR-R4TZ-EG2WR435322:23

在传统的主从复制slave端,binlog是不用开启的,但是在GTID中slave端的binlog是必须开启的,目的是记录执行过的GTID(强制)。GTID用来代替classic的复制方法,不在使用binlog+pos开启复制。而是使用master_auto_postion=1的方式自动匹配GTID断点进行复制。

mysql的主从复制是十分经典的一个应用,但是主从之间总会有数据一致性(data consistency )的问题,一般情况从库会落后主库几个小时,而且在传统一主多从(mysql5.6之前)的模型中当master down掉后,我们不只是需要将一个slave提成master就可以,还要将其他slave的同步目的地从以前的master改成现在master,而且bin-log的序号和偏移量也要去查看,这是十分不方便和耗时的,但mysql5.6引入gtid之后解决了这个问题。

红色代表GTID,绿色代表传统主从:
在这里插入图片描述

2.gtid的生命周期

gtid的生命周期对于配置和维护基于gtid的复制至关重要。所以,请尽可能理解以下几个过程。

gtid在master和slave上是一直持久化保存(即使删除了日志,也会记录到Previous_GTID中)的。它在master和slave上的生命周期如下:

1.客户端发送DDL/DML给master上,master首先对此事务生成一个唯一的gtid,假如为uuid_xxx:1,然后立即执行该事务中的操作。
注意,主从复制的情况下,sync-binlog基本上都会设置为1,这表示在每次提交事务时将缓存中的binlog刷盘。所以,在事务提交前,gtid以及事务相关操作的信息都在缓存中,提交后它们才写入到binlog file中,然后才会被dump线程dump出去。
换句话说,只有提交了的事务,gtid和对应的事务操作才会记录到binlog文件中。记录的格式是先记录gtid,紧跟着再记录事务相关的操作。

2.当binlog传送到relay log中后,slave上的SQL线程首先读取该gtid,并设置变量 gtid_next 的值为该gtid,表示下一个要操作的事务是该gtid。 gtid_next 是基于会话的,不同会话的gtid_next不同。

3.随后slave检测该gtid在自己的binlog中是否存在。如果存在,则放弃此gtid事务;如果不存在,则将此gtid写入到自己的binlog中,然后立刻执行该事务,并在自己的binlog中记录该事务相关的操作。
注意,slave上replay的时候,gtid不是提交后才写到自己的binlog file的,而是判断gtid不存在后立即写入binlog file。
通过这种在执行事务前先检查并写gtid到binlog的机制,不仅可以保证当前会话在此之前没有执行过该事务,还能保证没有其他会话读取了该gtid却没有提交。因为如果其他会话读取了该gtid会立即写入到binlog(不管是否已经开始执行事务),所以当前会话总能读取到binlog中的该gtid,于是当前会话就会放弃该事务。总之,一个gtid事务是决不允许多次执行、多个会话并行执行的。

4.slave在重放relay log中的事务时,不会自己生成gtid,所以所有的slave(无论是何种方式的一主一从或一主多从复制架构)通过重放relay log中事务获取的gtid都来源于master,并永久保存在slave上。
使用xtrabackup备份的方式提供gtid复制的基准数据。其中涉及到一些gtid检查、设置的操作。通过这些操作,大概可以感受的到gtid复制的几个概念。

用一张图来说明:
在这里插入图片描述

3.基于gtid复制的好处

从上面可以看出,gtid复制的优点大致有:

1.保证同一个事务在某slave上绝对只执行一次,没有执行过的gtid事务总是会被执行。
2.不用像传统复制那样保证binlog的坐标准确,因为根本不需要binlog以及坐标。
3.故障转移到新的master的时候很方便,简化了很多任务。
4.很容易判断master和slave的数据是否一致。只要master上提交的事务在slave上也提交了,那么一定是一致的。
当然,MySQL提供了选项可以控制跳过某些gtid事务,防止slave第一次启动复制时执行master上的所有事务而导致耗时过久。

虽然对于row-based和statement-based的格式都能进行gtid复制,但建议采用row-based格式。

4.GTID的工作原理:

1、当一个事务在主库端执行并提交时,产生GTID,一同记录到binlog日志中。
2、binlog传输到slave,并存储到slave的relaylog后,读取这个GTID的这个值设置gtid_next变量,即告诉Slave,下一个要执行的GTID值。
3、sql线程从relay log中获取GTID,然后对比slave端的binlog是否有该GTID。
4、如果有记录,说明该GTID的事务已经执行,slave会忽略。
5、如果没有记录,slave就会执行该GTID事务,并记录该GTID到自身的binlog,在读取执行事务前会先检查其他session持有该GTID,确保不被重复执行。
6、在解析过程中会判断是否有主键,如果有就用二级索引,如果没有就用全部扫描。

5.GTID主从演示

5.1 环境说明

主机ip
master192.168.234.11
slave192.168.234.22

5.2配置

//修改 master 配置文件
[root@master ~]# vim /etc/my.cnf
log-bin=/var/lib/mysql/mysql-bin //这里目录属主和组必须是mysql
binlog_format=row 
sync-binlog=1 
server-id=101 
master_info_repository=table 
relay_log_info_repository=table 
enforce_gtid_consistency=on //gtid复制需要加上的必须项
gtid_mode=on //gtid复制需要加上的必须项
//修改配置文件后重启 MySQL
[root@master ~]# service mysqld restart
//修改 slave 配置文件
[root@slave ~]# vim /etc/my.cnf 

log-bin=/var/lib/mysql/slave-bin //5.6必须加,5.7可加可不加
binlog_format=row 
relay-log=/var/lib/mysql/relay-bin 
sync-binlog=1 
server-id=182 
master_info_repository=table 
relay_log_info_repository=table 
enforce_gtid_consistency=on   //gtid复制需要加上的必须项
gtid_mode=on   //gtid复制需要加上的必须项
//修改配置文件后重启 MySQL
[root@slave ~]# service mysqld restart
//master 上创建复制用户
mysql> create user 'wyz'@'192.168.234.%' identified by 'wyz123!';
Query OK, 0 rows affected (0.00 sec)

mysql> grant replication slave on *.* to 'wyz'@'192.168.234.%';
Query OK, 0 rows affected (0.00 sec)

mysql> flush privileges;
Query OK, 0 rows affected (0.00 sec)
//因为master上的binlog日志没有删除过,所以在slave上直接change master to 配置连接参数。
mysql> CHANGE MASTER TO MASTER_HOST='192.168.234.11',MASTER_PORT=3306,MASTER_AUTO_POSITION=1;
Query OK, 0 rows affected (0.03 sec)

/启动slave上的两个复制线程
mysql> START SLAVE USER='wyz' PASSWORD='wyz123!';
Query OK, 0 rows affected, 1 warning (0.00 sec)

5.3验证

//查看io 线程和 sql 线程是否正常。
mysql> show processlist;
+----+-------------+-----------+------+---------+------+--------------------------------------------------------+------------------+
| Id | User        | Host      | db   | Command | Time | State                                                  | Info             |
+----+-------------+-----------+------+---------+------+--------------------------------------------------------+------------------+
|  2 | root        | localhost | NULL | Query   |    0 | starting                                               | show processlist |
|  3 | system user |           | NULL | Connect |   29 | Waiting for master to send event                       | NULL             |
|  4 | system user |           | NULL | Connect |  168 | Slave has read all relay log; waiting for more updates | NULL             |
+----+-------------+-----------+------+---------+------+--------------------------------------------------------+------------------+
//在master上添加数据:
//创建myisam类型的数值辅助表和插入数据
mysql>CREATE TABLE num_isam (n INT NOT NULL PRIMARY KEY) ENGINE = MYISAM ;
mysql>DROP PROCEDURE IF EXISTS proc_num1;
DELIMITER $$
mysql>CREATE PROCEDURE proc_num1 (num INT) 
BEGIN
    DECLARE rn INT DEFAULT 1 ;
    TRUNCATE TABLE backuptest.num_isam ;
    INSERT INTO backuptest.num_isam VALUES(1) ;
    dd: WHILE rn * 2 < num DO 
        BEGIN
            INSERT INTO backuptest.num_isam 
            SELECT rn + n FROM backuptest.num_isam;
            SET rn = rn * 2 ;
        END ;
    END WHILE dd;
    INSERT INTO backuptest.num_isam 
    SELECT n + rn 
    FROM backuptest.num_isam 
    WHERE n + rn <= num;
END ;
$$
DELIMITER ;

# 创建innodb类型的数值辅助表和插入数据的存储过程
mysql>CREATE TABLE num_innodb (n INT NOT NULL PRIMARY KEY) ENGINE = INNODB ;
mysql>DROP PROCEDURE IF EXISTS proc_num2;
DELIMITER $$
mysql>CREATE PROCEDURE proc_num2 (num INT) 
BEGIN
    DECLARE rn INT DEFAULT 1 ;
    TRUNCATE TABLE backuptest.num_innodb ;
    INSERT INTO backuptest.num_innodb VALUES(1) ;
    dd: WHILE rn * 2 < num DO 
        BEGIN
            INSERT INTO backuptest.num_innodb 
            SELECT rn + n FROM backuptest.num_innodb;
            SET rn = rn * 2 ;
        END ;
    END WHILE dd;
    INSERT INTO backuptest.num_innodb 
    SELECT n + rn 
    FROM backuptest.num_innodb 
    WHERE n + rn <= num ;
END ;
$$
DELIMITER ;

# 分别向两个数值辅助表中插入100W条数据
mysql>CALL proc_num1 (1000000) ;
mysql>CALL proc_num2 (1000000) ;
//在 slave 上查看 slave 的状态,以下是同步结束后的状态信息:
mysql> show slave status\G
*************************** 1. row ***************************
               Slave_IO_State: Waiting for master to send event
                  Master_Host: 192.168.234.11
                  Master_User: wyz
                  Master_Port: 3306
                Connect_Retry: 60
              Master_Log_File: mysql-bin.000002
          Read_Master_Log_Pos: 10057531
               Relay_Log_File: relay-bin.000001
                Relay_Log_Pos: 10058590
        Relay_Master_Log_File: mysql-bin.000002
             Slave_IO_Running: Yes
            Slave_SQL_Running: Yes
              Replicate_Do_DB: 
          Replicate_Ignore_DB: 
           Replicate_Do_Table: 
       Replicate_Ignore_Table: 
      Replicate_Wild_Do_Table: 
  Replicate_Wild_Ignore_Table: 
                   Last_Errno: 0
                   Last_Error: 
                 Skip_Counter: 0
          Exec_Master_Log_Pos: 10057531
              Relay_Log_Space: 10057648
              Until_Condition: None
               Until_Log_File: 
                Until_Log_Pos: 0
           Master_SSL_Allowed: No
           Master_SSL_CA_File: 
           Master_SSL_CA_Path: 
              Master_SSL_Cert: 
            Master_SSL_Cipher: 
               Master_SSL_Key: 
        Seconds_Behind_Master: 0
Master_SSL_Verify_Server_Cert: No
                Last_IO_Errno: 0
                Last_IO_Error: 
               Last_SQL_Errno: 0
               Last_SQL_Error: 
  Replicate_Ignore_Server_Ids: 
             Master_Server_Id: 101
                  Master_UUID: reta842t-5846-fe82-ge87-egz2784tjgo
             Master_Info_File: mysql.slave_master_info
                    SQL_Delay: 0
          SQL_Remaining_Delay: NULL
      Slave_SQL_Running_State: Slave has read all relay log; waiting for more updates
           Master_Retry_Count: 86400
                  Master_Bind: 
      Last_IO_Error_Timestamp: 
     Last_SQL_Error_Timestamp: 
               Master_SSL_Crl: 
           Master_SSL_Crlpath: 
           Retrieved_Gtid_Set: reta842t-5846-fe82-ge87-egz2784tjgo5:1-55
            Executed_Gtid_Set: reta842t-5846-fe82-ge87-egz2784tjgo5:1-55
                Auto_Position: 1
         Replicate_Rewrite_DB: 
                 Channel_Name: 
           Master_TLS_Version: 
1 row in set (0.00 sec)
```c


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值