mysql主从GTID不一致问题gtid_executed,gtid_purged ,Retrieved_Gtid_Set,Executed_Gtid_Set(I)

https://www.jb51.net/article/242473.htm

centos7下mysql双主+keepalived - benjamin杨 - 博客园

请设置从库为只读read_only=1,super_read_only=1就会大概率避免下面的情况

1 概念

1.1

gtid_executed等价Executed_Gtid_Set参数,已经执行的gtid集合(gtid-sets)。

gtid_purged,已经清除的gtid集合。

Retrieved_Gtid_Set:从库已经接收到主库的事务编号(从库的IO线程已经接受到了)

Executed_Gtid_Set:已经执行的事务编号(从库的执行sql线程已经执行了的sql)

master: 

mysql> show variables like '%uuid%';
+---------------+--------------------------------------+
| Variable_name | Value                                |
+---------------+--------------------------------------+
| server_uuid   | 21395c77-16b5-11ed-b628-005056b93c30 |
+---------------+--------------------------------------+
1 row in set (0.01 sec)

slave:

mysql> show variables like '%uuid%';
+---------------+--------------------------------------+
| Variable_name | Value                                |
+---------------+--------------------------------------+
| server_uuid   | 56fc5c7d-d0d7-11ec-bbf9-005056b9e62b |
+---------------+--------------------------------------+
1 row in set (0.01 sec)

master: 

mysql>  show master status ;
+-------------------+----------+--------------+-------------------------------------------------+------------------------------------------+
| File              | Position | Binlog_Do_DB | Binlog_Ignore_DB                                | Executed_Gtid_Set                        |
+-------------------+----------+--------------+-------------------------------------------------+------------------------------------------+
| master-bin.000004 |      194 | test,test1   | mysql,performance_schema,information_schema,sys | 21395c77-16b5-11ed-b628-005056b93c30:1-8 |
+-------------------+----------+--------------+-------------------------------------------------+------------------------------------------+
1 row in set (0.00 sec)

 slave:

show slave status

 Retrieved_Gtid_Set: 21395c77-16b5-11ed-b628-005056b93c30:1-8
            Executed_Gtid_Set: 21395c77-16b5-11ed-b628-005056b93c30:1-8,
56fc5c7d-d0d7-11ec-bbf9-005056b9e62b:1-3

其中主库的Executed_Gtid_Set为 21395c77-16b5-11ed-b628-005056b93c30:1-8 

可以看见Retrieved_Gtid_Set:21395c77-16b5-11ed-b628-005056b93c30:1-8 ,Executed_Gtid_Set:21395c77-16b5-11ed-b628-005056b93c30:1-8  ,也就是说主库产生了8个事务,从库接受到了来自主库的8个事务,并且都已经执行。

其中21395c77-16b5-11ed-b628-005056b93c30是主库的server-uuid。那么我们可以解析从库的binlog再看看

[root@localhost mysql]# 
[root@localhost mysql]# mysqlbinlog -vv master-bin.000004
/*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=1*/;
/*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/;
DELIMITER /*!*/;
# at 4
#220808 11:50:46 server id 1  end_log_pos 123 CRC32 0xe8ab61ad 	Start: binlog v 4, server v 5.7.35-log created 220808 11:50:46
# Warning: this binlog is either in use or was not closed properly.
BINLOG '
FojwYg8BAAAAdwAAAHsAAAABAAQANS43LjM1LWxvZwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAEzgNAAgAEgAEBAQEEgAAXwAEGggAAAAICAgCAAAACgoKKioAEjQA
Aa1hq+g=
'/*!*/;
# at 123
#220808 11:50:46 server id 1  end_log_pos 194 CRC32 0x0e046fb9 	Previous-GTIDs
# 21395c77-16b5-11ed-b628-005056b93c30:1-8
SET @@SESSION.GTID_NEXT= 'AUTOMATIC' /* added by mysqlbinlog */ /*!*/;
DELIMITER ;
# End of log file
/*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/;
/*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=0*/;

那么对于文章开头那个诡异的gtid是怎么出来的呢?先说说已经执行的事务:

     Executed_Gtid_Set: 21395c77-16b5-11ed-b628-005056b93c30:1-8,
56fc5c7d-d0d7-11ec-bbf9-005056b9e62b:1-3

这里的21395c77-16b5-11ed-b628-005056b93c30:1-8肯定很好理解,就是已经执行主库的1-8的事务,那么56fc5c7d-d0d7-11ec-bbf9-005056b9e62b:1-3呢?这个其实也简单,有两种情况:

第一种情况:从库有数据写入( 从库插入数据 )

mysql> show slave status\G;
*************************** 1. row ***************************
               Slave_IO_State: Waiting for master to send event
                  Master_Host: 172.16.10.1
                  Master_User: root
                  Master_Port: 3306
                Connect_Retry: 60
              Master_Log_File: master-bin.000004
          Read_Master_Log_Pos: 194
               Relay_Log_File: localhost-relay-bin.000009
                Relay_Log_Pos: 409
        Relay_Master_Log_File: master-bin.000004
             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: 194
              Relay_Log_Space: 708
              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: 1
                  Master_UUID: 21395c77-16b5-11ed-b628-005056b93c30
             Master_Info_File: /var/lib/mysql/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: 21395c77-16b5-11ed-b628-005056b93c30:1-8
            Executed_Gtid_Set: 21395c77-16b5-11ed-b628-005056b93c30:1-8,
56fc5c7d-d0d7-11ec-bbf9-005056b9e62b:1-3
                Auto_Position: 1
         Replicate_Rewrite_DB: 
                 Channel_Name: 
           Master_TLS_Version: 
1 row in set (0.00 sec)

ERROR: 
No query specified



mysql> select * from jettech01;
+------+------+
| id   | name |
+------+------+
|    1 | a    |
|    2 | b    |
|    3 | c    |
|    5 | f    |
|    7 | k    |
+------+------+
5 rows in set (0.00 sec)

mysql>  insert into jettech01 value(8,'l');
Query OK, 1 row affected (0.00 sec)

mysql> select * from jettech01;
+------+------+
| id   | name |
+------+------+
|    1 | a    |
|    2 | b    |
|    3 | c    |
|    5 | f    |
|    7 | k    |
|    8 | l    |
+------+------+
6 rows in set (0.00 sec)

mysql> show slave status\G;
*************************** 1. row ***************************
               Slave_IO_State: Waiting for master to send event
                  Master_Host: 172.16.10.1
                  Master_User: root
                  Master_Port: 3306
                Connect_Retry: 60
              Master_Log_File: master-bin.000004
          Read_Master_Log_Pos: 194
               Relay_Log_File: localhost-relay-bin.000009
                Relay_Log_Pos: 409
        Relay_Master_Log_File: master-bin.000004
             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: 194
              Relay_Log_Space: 708
              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: 1
                  Master_UUID: 21395c77-16b5-11ed-b628-005056b93c30
             Master_Info_File: /var/lib/mysql/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: 21395c77-16b5-11ed-b628-005056b93c30:1-8
            Executed_Gtid_Set: 21395c77-16b5-11ed-b628-005056b93c30:1-8,
56fc5c7d-d0d7-11ec-bbf9-005056b9e62b:1-4
                Auto_Position: 1
         Replicate_Rewrite_DB: 
                 Channel_Name: 
           Master_TLS_Version: 
1 row in set (0.00 sec)

ERROR: 
No query specified

可以看见已经执行的事务有来自主库的Executed_Gtid_Set: 21395c77-16b5-11ed-b628-005056b93c30:1-8,也有从库刚自己写入的数据:56fc5c7d-d0d7-11ec-bbf9-005056b9e62b:1-4。我们可以解析binlog看看。看从库的bin-log日志。

[root@localhost mysql]# ls -al localhost-relay-bin.* slave36-bin.*
-rw-r-----. 1 mysql mysql  299 5月  11 11:50 localhost-relay-bin.000008
-rw-r-----. 1 mysql mysql  409 5月  11 11:50 localhost-relay-bin.000009
-rw-r-----. 1 mysql mysql   58 5月  11 11:50 localhost-relay-bin.index
-rw-r-----. 1 mysql mysql  177 5月  11 11:06 slave36-bin.000001
-rw-r-----. 1 mysql mysql  177 5月  11 11:06 slave36-bin.000002
-rw-r-----. 1 mysql mysql 2941 5月  11 14:41 slave36-bin.000003
-rw-r-----. 1 mysql mysql   63 5月  11 11:06 slave36-bin.index

localhost-relay-bin.000009:从库执行主库同步过来的bin-log

slave36-bin.000003:从库自己的bin-log日志 

[root@localhost mysql]# mysqlbinlog -vv slave36-bin.000003 --include-gtids="56fc5c7d-d0d7-11ec-bbf9-005056b9e62b:1-4"

#220511 14:41:38 server id 2  end_log_pos 2741 CRC32 0x161748e6 	GTID	last_committed=11	sequence_number=12	rbr_only=yes
/*!50718 SET TRANSACTION ISOLATION LEVEL READ COMMITTED*//*!*/;
SET @@SESSION.GTID_NEXT= '56fc5c7d-d0d7-11ec-bbf9-005056b9e62b:4'/*!*/;
# at 2741
#220511 14:41:38 server id 2  end_log_pos 2813 CRC32 0xa2271211 	Query	thread_id=3	exec_time=0	error_code=0
SET TIMESTAMP=1652251298/*!*/;
BEGIN
/*!*/;
# at 2813
#220511 14:41:38 server id 2  end_log_pos 2868 CRC32 0xd00023ca 	Table_map: `test`.`jettech01` mapped to number 108
# at 2868
#220511 14:41:38 server id 2  end_log_pos 2910 CRC32 0x7a951c9a 	Write_rows: table id 108 flags: STMT_END_F

BINLOG '
olp7YhMCAAAANwAAADQLAAAAAGwAAAAAAAEABHRlc3QACWpldHRlY2gwMQACA/4C/gEDyiMA0A==
olp7Yh4CAAAAKgAAAF4LAAAAAGwAAAAAAAEAAgAC//wIAAAAAWyaHJV6
'/*!*/;
### INSERT INTO `test`.`jettech01`
### SET
###   @1=8 /* INT meta=0 nullable=1 is_null=0 */
###   @2='l' /* STRING(1) meta=65025 nullable=1 is_null=0 */
# at 2910
#220511 14:41:38 server id 2  end_log_pos 2941 CRC32 0x6fd47737 	Xid = 396
COMMIT/*!*/;
SET @@SESSION.GTID_NEXT= 'AUTOMATIC' /* added by mysqlbinlog */ /*!*/;
DELIMITER ;
# End of log file
/*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/;
/*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=0*/;
[root@localhost mysql]# ^C

从binlog中可以清楚的看到是从库进行了写入。下面说第二组情况

第二种情况:主从切换(我这里使用MHA切换主从)

           Retrieved_Gtid_Set: 56fc5c7d-d0d7-11ec-bbf9-005056b9e62b:1-4
            Executed_Gtid_Set: 21395c77-16b5-11ed-b628-005056b93c30:1-8,
56fc5c7d-d0d7-11ec-bbf9-005056b9e62b:1-4

可以看到在切换以后主库的server-id是2。这里的意思是接收到主库56fc5c7d-d0d7-11ec-bbf9-005056b9e62b:1-4,并且已经执行这个事务,那么这个事务其实就是之前在从库写入的那条数据。对于21395c77-16b5-11ed-b628-005056b93c30:1-8个是之前作为主库执行。如果此时在主库再插入1条数据,那么又会变化如下

           Retrieved_Gtid_Set: 56fc5c7d-d0d7-11ec-bbf9-005056b9e62b:1-5
            Executed_Gtid_Set: 21395c77-16b5-11ed-b628-005056b93c30:1-8,
56fc5c7d-d0d7-11ec-bbf9-005056b9e62b:1-5

下面说说文章开头提到的gtid不连续的问题,类似21395c77-16b5-11ed-b628-005056b93c30:37-45,这个是由于binlog被清理以后导致的,我们可以测试一下。然后查看gtid_purged变量。
binlog不可能永远驻留在服务上,需要定期进行清理(通过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的子集。

slave,从库:

mysql> show master logs;
+--------------------+-----------+
| Log_name           | File_size |
+--------------------+-----------+
| slave36-bin.000001 |       177 |
| slave36-bin.000002 |       177 |
| slave36-bin.000003 |      2941 |
+--------------------+-----------+
3 rows in set (0.00 sec)

mysql> flush logs;
Query OK, 0 rows affected (0.00 sec)

mysql> show master logs;
+--------------------+-----------+
| Log_name           | File_size |
+--------------------+-----------+
| slave36-bin.000001 |       177 |
| slave36-bin.000002 |       177 |
| slave36-bin.000003 |      2990 |
| slave36-bin.000004 |       234 |
+--------------------+-----------+
4 rows in set (0.00 sec)

mysql> PURGE BINARY LOGS TO 'slave36-bin.000004';
Query OK, 0 rows affected (0.00 sec)

mysql> show master logs;
+--------------------+-----------+
| Log_name           | File_size |
+--------------------+-----------+
| slave36-bin.000004 |       234 |
+--------------------+-----------+
1 row in set (0.00 sec)

然后只要从库有重新启动,才会读取。MySQL服务器启动时,通过读binlog文件,初始化gtid_executed和gtid_purged,使它们的值能和上次MySQL运行时一致。

gtid_executed被设置为最新的binlog文件中Previous_gtids_log_event和所有Gtid_log_event的并集。
gtid_purged为最老的binlog文件中Previous_gtids_log_event。

没启动前:

           Retrieved_Gtid_Set: 21395c77-16b5-11ed-b628-005056b93c30:1-8
            Executed_Gtid_Set: 21395c77-16b5-11ed-b628-005056b93c30:1-8,
56fc5c7d-d0d7-11ec-bbf9-005056b9e62b:1-4

重启以后并且插入数据:

           Retrieved_Gtid_Set: 21395c77-16b5-11ed-b628-005056b93c30:1-8
            Executed_Gtid_Set: 21395c77-16b5-11ed-b628-005056b93c30:1-8,
56fc5c7d-d0d7-11ec-bbf9-005056b9e62b:1-5
mysql> show variables like 'gtid_purged';
+---------------+------------------------------------------------------------------------------------+
| Variable_name | Value                                                                              |
+---------------+------------------------------------------------------------------------------------+
| gtid_purged   | 21395c77-16b5-11ed-b628-005056b93c30:1-8,
56fc5c7d-d0d7-11ec-bbf9-005056b9e62b:1-4 |
+---------------+------------------------------------------------------------------------------------+
1 row in set (0.01 sec)

到这里相信聪明的你一定看懂了。最后顺道说说gtid跳过复制错误的方法,对于跳过一个错误,找到无法执行事务的编号,比如是21395c77-16b5-11ed-b628-005056b93c30:1-8,那么操作如下:

stop slave;
set gtid_next='21395c77-16b5-11ed-b628-005056b93c30:1-8';
begin;
commit;
set gtid_next='AUTOMATIC';
start slave;

上面方法只能跳过一个事务,那么对于一批如何跳过?在主库执行show master status,看主库执行到了哪里,比如:21395c77-16b5-11ed-b628-005056b93c30:1-33,那么操作如下:

stop slave;
reset master;
set global gtid_purged=' 21395c77-16b5-11ed-b628-005056b93c30:1-33';
start slave;

gtid_executed:
如何查看已经执行过的GTID?

系统表 mysql.gtid_executed 存放了所有执行过的GTID(在活动的binlog中的除外),但是由于不包含活动的binlog当中的GTID,因此需要查看精确值时,可以查看 global variable gtid_executed 的值,这个变量的值是准确的(或者 show master status )。

同一个GTID的事务不会在一个Server上执行两次,可以保证数据一致性。

GTID SET
GTID SET是指多个GTID的集合,示例如下:
2174B383-5441-11E8-B90A-C80AA9429562:1-3, 24DA167-0C0C-11E8-8442-00059A3C7B00:1-19

gtid_executed 和 gtid_purged 这两个系统变量 都是 GTID SET


gtid_purged:
这个一个 GTID SET,包含了所有已经提交过的,但是不在 binlog 当中的 GTID ,它是 gtid_executed 的子集。以下几种 GTID 都会添加到 gtid_purged 当中:

1. 未开启binlog的从库上提交过的GTID
2. 已经被 "purge" 掉的 binlog 当中的 GTID 。(当发出 purge binary log 命令之后,如果被 purge的binlog中包含有GTID,那么查看 gtid_purged 变量值的时候,就会看到该变量值发生了变化)
3. 使用 'set global gtid_purged= "xxxx" ' 添加的 GTID
什么时候需要设置 gtid_purged 变量?
人为设置 gtid_purged 的目地是为了告诉服务器,即使它们不在 binlog 中,这些 GTID 已经 被应用过了,不能/不需要再重做。一个必须人为设置 gtid_purged 的场景见文章

总结

relay_log_recover=0

  • slave会扫描最后一个relay log文件,Retrieved_Gtid_Set显示的是当前扫描所得的GTID;io线程会通过扫描所得的最后一个GTID+1(如果Retrieved_Gtid_Set>=Executed_Gtid_Set)为依据来拉取,如果Retrieved_Gtid_Set

relay_log_recover=1

  • slave中把所有relay log清除,io线程通过Executed_Gtid_Set后的+1个事务开始拉取并生成新的relay log文件;SQL线程在清除relay log时把Relay_Log_File、Relay_Log_Pos设为空,所以SQL线程从新的relay log文件的第一个事务开始应用

1.2  产生:

当一个事务提交时,就会分配一个GTID(前提是事务有写入到binlog),GTID单调递增且连续。

1.3 GTID格式:

GTID = source_id:transaction_id
其中 source_id 一般指 source 的  server_uuid , 示例:3E11FA47-71CA-11E1-9E33-C80AA9429562:2

  • mysql.gtid_executed表:GTID持久化的介质,MySQL启动阶段会读取这个表来获取gtid_executed变量的值。
  • gtid_executed变量(show global variables):MySQL数据库已经执行了哪些GTID事务,处于内存中。show slave status中的executed_gtid_set也取自这里。
    mysql> show global variables like '%gtid%';
    +----------------------------------+------------------------------------------+
    | Variable_name                    | Value                                    |
    +----------------------------------+------------------------------------------+
    | binlog_gtid_simple_recovery      | ON                                       |
    | enforce_gtid_consistency         | ON                                       |
    | gtid_executed                    | 21395c77-16b5-11ed-b628-005056b93c30:1-8 |
    | gtid_executed_compression_period | 1000                                     |
    | gtid_mode                        | ON                                       |
    | gtid_owned                       |                                          |
    | gtid_purged                      |                                          |
    | session_track_gtids              | OFF                                      |
    +----------------------------------+------------------------------------------+
    8 rows in set (0.01 sec)
    mysql>  show master status ;
    +-------------------+----------+--------------+-------------------------------------------------+------------------------------------------+
    | File              | Position | Binlog_Do_DB | Binlog_Ignore_DB                                | Executed_Gtid_Set                        |
    +-------------------+----------+--------------+-------------------------------------------------+------------------------------------------+
    | master-bin.000004 |      194 | test,test1   | mysql,performance_schema,information_schema,sys | 21395c77-16b5-11ed-b628-005056b93c30:1-8 |
    +-------------------+----------+--------------+-------------------------------------------------+------------------------------------------+
    1 row in set (0.00 sec)

  • gtid_purged变量(show global variables):由于BINLOG文件的删除(如purge binary logfiles或者超过expire_logs_days设置)已经丢失的GTID事务,同时在搭建备库的我们使用set global gtid_purged变量来提示MySQL哪些GTID事务我已经执行过了

这也是我们DBA通常能够观察到的几种GTID,有了前文的描述我们知道其中mysql.gtid_executed表是一种GTID持久化的介质,而gtid_executed变量和gtid_purged变量则对应了,gtid_state中的executed_gtidslost_gtids内存数据。他们分别表示MySQL数据库执行了哪些GTID事务,有哪些GTID事务由于BINLOG文件的删除已经丢失了。

其次我们先来达成一个共识gtid_executed变量一定是实时更新的不管主库和从库。我们的讨论分为主库,从库和通用从源码的角度进行详细讨论。并且约定都是打开GTID的情况下。最后给出最终总结。

1.4 gtid_executed,全局参数,GTID集合包含所有在该服务器上执行过的事务编号和使用set gtid_purged语句设置过的事务编号,使用SHOW MASTER STATUS和SHOW SLAVE STATUS命令得到的Executed_Gtid_Set列值就取自于全局参数gitd_executed。
 
gtid_purged,全局参数,GTID集合包含从binlog中purged掉的事务ID,该集合是全局参数gtid_executed的子集。

2 参数更新机制

2.1 master: 当复制主库关闭binlog时:
1. 事务提交不会生成GTID,mysql.gtid_executed表/gtid_executed变量/gtid_purged变量均不更新。

2.2 当复制主库开启binlog时:
1. 事务提交需要生成Binlog,GTID在Binlog的ordered_commit flush阶段生成。
2. 表mysql.gtid_executed在实例重启或flush log或binlog文件写满等造成binlog发生切换是保存上一个binlog执行过的全部gtid,属于非实时更新。
3. 全局变量gtid_executed在事务commit阶段更新,属于实时更新。
4. 全局变量gtid_purged在执行purge binary log命令或binlog超过保持期进行清理binlog时更新,属于非实时更新。

2.3 当复制从库关闭binlog或关闭log_slave_update时:slave

1. 在从库上应用主库binlog时不会生成新的GTID,也不会写入复制从库的binlog文件。
2. 表mysql.gtid_executed在应用主库binlog事务时更新,并与事务一起提交,属于实时更新。
3. 全局变量gtid_executed在主库binlog事务commit阶段更新,属于实时更新。
4. 全局变量gtid_purged在主库binlog事务commit阶段更新,属于实时更新。

2.4 当复制从库开启binlog或开启log_slave_update时:
1. 在从库上应用主库binlog时不会生成新的GTID,但会写入复制从库的binlog文件。
2. 表mysql.gtid_executed在实例重启或flush log或binlog文件写满等造成binlog发生切换是保存上一个binlog执行过的全部gtid,属于非实时更新。
3. 全局变量gtid_executed在事务commit阶段更新,属于实时更新。
4. 全局变量gtid_purged在执行purge binary log命令或binlog超过保持期进行清理binlog时更新,属于非实时更新。

3 参数重置机制

在某些场景下,需要修改全局变量gtid_purged和gtid_executed的值,执行对全局变量gtid_purged进行赋值时,会报以下错误:
ERROR 1840 (HY000): @@GLOBAL.GTID_PURGED can only be set when @@GLOBAL.GTID_EXECUTED is empty.

设置@@GLOBAL.GTID_EXECUTED需要通过RESET MASTER命令,该命令会清空当前服务器上的Binlog文件,并将@@GLOBAL.GTID_EXECUTED和@@GLOBAL.GTID_PURGED的值重置为空,重新初始化binlog文件序号,重新初始化GTID的事务ID起始值.

4 参数恢复机制

参数binlog_gtid_simple_recovery用于控制在实例重启时,如何计算全局变量gtid_executed和gtid_purged。在MySQL 5.7.7及之后版本中该参数默认为True。

binlog_gtid_simple_recovery=FALSE

• To initialize gtid_executed, binary log files are iterated from the newest file, stopping at the first binary log that has any Previous_gtids_log_event. All GTIDs from Previous_gtids_log_event and Gtid_log_events are read from this binary log file. This GTID set is stored internally and called gtids_in_binlog. The value of gtid_executed is computed as the union of this set and the GTIDs stored in the mysql.gtid_executed table.
This process could take a long time if you had a large number of binary log files without GTID events, for example created when gtid_mode=OFF.
• To initialize gtid_purged, binary log files are iterated from the oldest to the newest, stopping at the first binary log that contains either a Previous_gtids_log_event that is non-empty (that has at least one GTID) or that has at least one Gtid_log_event. From this binary log it reads Previous_gtids_log_event. This GTID set is subtracted from gtids_in_binlog and the result stored in the internal variable gtids_in_binlog_not_purged. The value of gtid_purged is initialized to the value of gtid_executed, minus gtids_in_binlog_not_purged.

binlog_gtid_simple_recovery=TRUE
which is the default in MySQL 5.7.7 and later, the server iterates only the oldest and the newest binary log files and the values of gtid_purged and gtid_executed are computed based only on Previous_gtids_log_event or Gtid_log_event found in these files. This ensures only two binary log files are iterated during server restart or when binary logs are being purged.

在实例重启后,全局变量gtid_executed和gtid_purged的值取决于:

1、从binlog文件头读取Previous_gtids_log_event获取该binlog之前的gtid_set

2、从binlog文件的所有事件中获取该binlog中包含的gtid_set
3、从mysql.gtid_executed表获取到执行过的gtid_set
通过上面三个集合算出当前实例执行过的gtid_set和当前BINLOG中包含的gtid_set。

4 mysql.gtid_executed表更新机制

在MySQL 5.6版本中,开启GTID模式必须打开参数log_slave_updates,即从库必须在记录一份binlog,以保证在从库重启后,可以通过扫描最后一个二进制日志获得当前从库执行过的GTID集合。
在MySQL 5.7.5版本中引入mysql.gtid_executed表来存放gtid信息,因此在GTID模式下不要求开启log_slave_update参数。
 
在MySQL 5.7版本中,对mysql.gtid_executed表的更新策略分为:

1、主库服务器,未开启log_bin参数,则不对mysql.gtid_executed表进行更新。
2、主库服务器,开启log_bin参数,当二进制文件进行rotation时或者关闭实例时对mysql.gtid_executed进行更新。
3、从库服务器,未开启log_bin参数或未开启log_slave_updates参数,在用户事务执行时对mysql.gtid_executed进行更新,并与用户事务一起进行提交。
4、从库服务器,开启log_bin参数和开启log_slave_updates参数,当二进制文件进行rotation时或者关闭实例时对mysql.gtid_executed进行更新。

当主库开启log_bin参数或从库开启log_slave_update参数时,执行或应用事务所生成的binlog会写入磁盘,当二进制文件进行rotation时或者关闭实例时对mysql.gtid_executed进行更新,表mysql.gtid_executed中不能提供完整的GTID集合数据,需以参数gtid_executed为准,如果实例异常重启,最近的GTID集合数据没有更新到mysql.gtid_executed表中,当实例恢复时,通过扫描最后一个binlog文件来获得最新的GTID集合数据。

当从库未开启log_bin参数或未开启log_slave_updates参数时,应用主库所传递过来的事务不会产生新的binlog,在执行事务开始便可以获取到该事务的GTID,因此可以随着事务一起提交,类似于MySQL 5.6版本中随事务一起更新mysql.slave_master_info表一样。

当执行RESET MASTER时,表mysql.gtid_executed会被清空。


5 mysql.gtid_executed表压缩

当从库未开启log_slave_updates参数时,由于每个事务都会向mysql.gtid_executed表写入记录,为防止mysql.gtid_executed表数据量暴增,MySQL 5.7引入参数gtid_executed_compression_period来控制每执行N个事务后,对mysql.gtid_executed表进行一次压缩,将多个连续的gtid值合并为gtid集合。如果gtid_executed_compression_period被设置为0,则不会进行压缩。
当主库开启log_bin参数或从库开启log_slave_update参数时,参数gtid_executed_compression_period并不会被使用,只有当二进制文件进行Rotation时才会进行GTID压缩。MySQL Replication--全局参数gtid_executed和gtid_purged - TeyGao - 博客园

==================================

1.

#从库通过show slave status\G找到冲突的GTID号(如上图)
stop slave sql_thread;
SET gtid_next = '冲突的GTID号';
#SET gtid_next = '00017261-1111-1111-1111-111111111111:858';
之后的变化为Executed_Gtid_Set: 00017261-1111-1111-1111-111111111111:1-858,
BEGIN;COMMIT;
SET gtid_next = 'AUTOMATIC';
start slave sql_thread;
#最后从库再次执行  show slave status\G  进行验证。

2.gtid_next与GLOBAL GTID_PURGED:小知识分享

相同点:
都是改变Executed_Gtid_Set的值。(表示为从库已经执行完毕的事务gtid信息)
不同点:
gtid_next是一个具体的gtid号(影响范围小)

GLOBAL GTID_PURGED是一段gtid号,并且需要Executed_Gtid_Set为空,也就是需要执行reset master
(影响范围大,比如说新建一个增量的从库,就可以告诉从库执行那些relaylog,有这个场景但没实践过)
#配合以下语句使用
show variables like '%gtid_purged%';#查看从库执行过的信息
(reset master之后为空,从库的binlog也会重建)
#SET GLOBAL GTID_PURGED='1111:1-850'
#手动让从库认为1111:845已经执行

3.恢复报错:

ERROR 1840 (HY000) at line 24: @@GLOBAL.GTID_PURGED can only be set when @@GLOBAL.GTID_EXECUTED is empty

当前GTID_EXECUTED参数已经有值,而从集群倒出来的dump文件中包含了SET @@GLOBAL.GTID_PURGED的操作

4.解决方法

方法三:vim all_db.sql (记录下图的set信息,然后删除set值,重新恢复单库)
(注意备份文件的大小,越大打开的越慢)

方法二:reset master
这个操作可以将当前库的GTID_EXECUTED值置空

方法一:--set-gtid-purged=off
在dump导出时,添加--set-gtid-purged=off参数,避免将gtid信息导出
mysqldump -uroot -p --set-gtid-purged=off -d test> test.sql

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值