zoukankan      html  css  js  c++  java
  • gtid

    gtid知识:

    一、gtid持久化介质

    01 、mysql.gtid_executed表:

    work@master (mysql) > show create table gtid_executedG;
    *************************** 1. row ***************************
           Table: gtid_executed
    Create Table: CREATE TABLE `gtid_executed` (
      `source_uuid` char(36) NOT NULL COMMENT 'uuid of the source where the transaction was originally executed.',
      `interval_start` bigint(20) NOT NULL COMMENT 'First number of interval.',
      `interval_end` bigint(20) NOT NULL COMMENT 'Last number of interval.',
      PRIMARY KEY (`source_uuid`,`interval_start`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 STATS_PERSISTENT=0
    1 row in set (0.07 sec)
    
    ERROR: 
    No query specified
    
    Mon May 11 16:56:12 2020

     02、binlog中的gtid_event

    #  at  120
    #151222  9:07:58 server id 1026872634  end_log_pos 247 CRC32 0xedf993a8     Previous-GTIDs
    # b3485508-883f-11e5-85fb-e41f136aba3e:1-14,
    # b694c8b2-883f-11e5-85fb-e41f136aba3e:1-10115960:12000000-12000005
    #  at  247
    #151222  9:08:03 server id 1026872625  end_log_pos 295 CRC32 0xc3d3d8ee     GTID [ commit =yes]
    SET  @@SESSION.GTID_NEXT=  'b694c8b2-883f-11e5-85fb-e41f136aba3e:10115961' /*!*/;
    #  at  295
    #151222  9:08:03 server id 1026872625  end_log_pos 370 CRC32 0x0a32d229     Query   thread_id=18    exec_time=1 error_code=0
    BEGIN
    /*!*/;
    #  at  370
    #151222  9:08:03 server id 1026872625  end_log_pos 480 CRC32 0x3c0e094f     Query   thread_id=18    exec_time=1 error_code=0
    use `db`/*!*/;
    SET  TIMESTAMP =1450746483/*!*/;
    update  tb  set  val = val + 1  where  id = 1
    /*!*/;
    #  at  480
    #151222  9:08:03 server id 1026872625  end_log_pos 511 CRC32 0x5772f16b     Xid = 6813913
    COMMIT /*!*/;
    #  at  511
    #151222  9:10:19 server id 1026872625  end_log_pos 559 CRC32 0x3ac30191     GTID [ commit =yes]
    SET  @@SESSION.GTID_NEXT=  'b694c8b2-883f-11e5-85fb-e41f136aba3e:10115962' /*!*/;
    #  at  559
    #151222  9:10:19 server id 1026872625  end_log_pos 634 CRC32 0x83a74912     Query   thread_id=18    exec_time=0 error_code=0
    SET  TIMESTAMP =1450746619/*!*/;
    BEGIN
    /*!*/;
    #  at  634
    #151222  9:10:19 server id 1026872625  end_log_pos 744 CRC32 0x581f6031     Query   thread_id=18    exec_time=0 error_code=0
    SET  TIMESTAMP =1450746619/*!*/;
    update  tb  set  val = val + 1  where  id = 1
    /*!*/;
    #  at  744
    #151222  9:10:19 server id 1026872625  end_log_pos 775 CRC32 0x793f8e34     Xid = 6813916
    COMMIT /*!*/;

     二、gtid相关变量和表

    01、mysql.gtid_executed表

               含义:数据库已经执行了哪些Gtid事物,存储在表中。只有从库在binlog或log_slave_updates至少一个关闭时,才会实时更新的

    1. 执行 reset master 时,则删除该表所有记录。
    
    2. 执行 set global gitd_purged='' 时,则插入对应的记录到mysql.gtid_executed表,且同时更新gtid_executed为和gtid_purged相同的值,即始终保持gtid_purged是gtid_executed的子集。
    
    3. 主库:若binlog关闭,则不更新;若binlog打开,则binlog发生rotate切换时,会更新该表数据。
    
    4. 从库:若binlog或log_slave_updates至少一个关闭,则实时更新;若binlog和log_slave_updates都开启,则binlog发生rotate切换时,会更新该表数据。

    02、gtid_executed变量

              含义:数据库已经执行了哪些Gtid事物,存储在内存中。

             show slave status中的Executed_Gtid_Set也取自这里。

             gtid_executed为空有两种情况:一是执行reset master;二是之前没有启动过基于GTID的复制。

    1. 执行 reset master 时,则该变量设置为空。
    
    2. 执行 set global gitd_purged='' 时,则插入对应的记录到mysql.gtid_executed表,且同时更新gtid_executed为和gtid_purged相同的值,即始终保持gtid_purged是gtid_executed的子集。
    
    3. mysql启动时,通过读取mysql.gtid_executed表的数据来初始化gtid_executed变量。
    
    4. 只有当主库在关闭binlog的时候,不会更新gtid_executed变量;其余情况,都会实时更新gtid_executed变量。

    03、gitd_purged变量

               含义:全局变量。用于记录已经被清除了的binlog事务集合,gitd_purged变量是gtid_executed变量的子集。

               只有gtid_executed为空时,才能手动设置gitd_purged变量。

           

    1. 执行 reset master 时,则该变量设置为空。
    
    2. 执行 set global gitd_purged='XXX' 时,则插入对应的记录到mysql.gtid_executed表,且同时更新gtid_executed为和gtid_purged相同的值,即始终保持gtid_purged是gtid_executed的子集。
        
       用来来提示Mysql,哪些Gtid事务我已经执行过了。用于搭建从库时,使用极多。通常是先在从库执行:reset master;然后再在从库执行:set global gitd_purged='XXX',
     
       注意,这里的XXX需要结合该从库Retrieved_Gtid_Set和Executed_Gtid_Set的并集,还要加上主库的Executed_Gtid_Set中存在的,但不是该主库产生的gtid,且该从库没有的gtid。
    
       但是这样有个隐患,就是主库上有其他机器执行过的gtid而得到的数据,但是该从库却没有真正存在这些数据,而你在该从库上却设置为这些gtid事务是自己purge掉了,其实自己压根没有这些数据,这样就导致从库的数据少于主库,即丢掉了数据。
    
    3. mysql启动时,通过读取mysql.gtid_executed表的数据来初始化gtid_executed变量。
    
    4. 主库:若binlog关闭,则不更新gitd_purged变量;若binlog打开,则binlog被清理时,会更新gitd_purged变量。
    
    5. 从库:若binlog或log_slave_updates至少一个关闭,则实时更新gitd_purged变量;若binlog和log_slave_updates都开启,则binlog被清理时,会更新gitd_purged变量。
    
    
    ########################################################################################################################################################################################
    
    手动删除binlog:
    
       show binary logs;
    
       purge binary logs to 'mysql-bin.000046';
    
       purge binary logs before '2020-10-10 10:10:10';
    
    自动删除binlog:
    
       expire_logs_days时间到了,执行binlog删除

              跳过gtid事务:

    1)停止复制:
    stop slave;
    2)重置master:
    reset master;
    3)设置gtid_purged变量:

    set global gtid_purged='XXX';
    4)开启复制:
    start slave;
    3,使用空事务处理故障
    情况1:
    主键重复
    
    #  Last_Error: Could not execute Write_rows event on table test.a; Duplicate entry '500' for key 'PRIMARY', Error_code: 1062; handler error HA_ERR_FOUND_DUPP_KEY; the event's master log mysql.000005, end_log_pos 651107
    # 方法1:
    # 注入空事务
    
          Last_IO_Error_Timestamp: 
         Last_SQL_Error_Timestamp: 
                   Master_SSL_Crl: 
               Master_SSL_Crlpath: 
               Retrieved_Gtid_Set: 7abe211e-fb4f-11e7-b16e-000c29ba88ca:66253-68381:69091-70362
                Executed_Gtid_Set: 7abe211e-fb4f-11e7-b16e-000c29ba88ca:1-70362,
    9a455b69-fb4f-11e7-b993-000c29e8a43c:1
    ##########################
    ##########################
    
    (root@Slave)[tempdb]>stop slave sql_thread;
    
    (root@Slave)[tempdb]>set gtid_next='7abe211e-fb4f-11e7-b16e-000c29ba88ca:70363';
    
    (root@Slave)[tempdb]>begin;commit;
    
    (root@Slave)[tempdb]>set gtid_next='AUTOMATIC';
    
    (root@Slave)[tempdb]>start slave sql_thread;
    
    (root@Slave)[tempdb]>show slave status G

     

    04、Executed_Gtid_Set

               含义:

    1. 在主库中,执行 show master status命令,所得Executed_Gtid_Set,就是和全局变量gitd_executed相同值,任何时候,两者完全相同值。
    
    2. 在从库中,执行 show slave  status命令,所得Executed_Gtid_Set,就是和全局变量gitd_executed相同值,任何时候,两者完全相同值。

    05、Retrieved_Gtid_Set

                含义:仅在从库中才有,在主库中不存在。

    06、Previous-GTIDs

    1. Previous_gtid_log_event在每个binlog 头部都会有每次binlog rotate的时候存储在binlog头部,Previous-GTIDs在binlog中只会存储在这台机器上执行过的所有binlog,不包括手动设置gtid_purged值。

    换句话说,如果你手动set global gtid_purged
    =xx; 那么xx是不会记录在Previous_gtid_log_event中的。

    07、gtid_next变量

              跳过gtid事务:

     (1) 停止slave进程:
    mysql
    > stop slave; (2) 设置事务号,事务号从Retrieved_Gtid_Set获取: 在session里设置gtid_next,即跳过这个GTID mysql> SET @@sission.gtid_next= '8f9e146f-0a18-11e7-810a-0050568833c8:4'
    (3)设置空事物 mysql> begin; commit;
    4)恢复事物号 mysql> set session gtid_next= automatic; (5) 启动slave进程 mysql> start slave;

    08、gtid_owned

    08、gtid_mode

    09、enforce_gtid_consistency

    10、gtid_executed_compression_period

    1、gtid配置

     MySQL通过全局变量gtid_mode控制开启/关闭GTID模式。但是gtid_mode是只读的,可添加到配置文件中,然后重启mysqld来开启GTID模式。相关配置项如下:
    gtid-mode                = ON
    enforce_gtid_consistency = 1
    log-slave-updates        = 1
    log-bin                  = mysql-bin
    log-bin-index            = mysql-bin.index

    2、查看配置

    > show  global  variables  like  'gtid_%'G;
    *************************** 1. row ***************************
    Variable_name: gtid_executed
            Value: 5a1a41db-9f15-11e9-a991-e4434b210720:1-2,
    5aa95098-9f15-11e9-98f3-e4434b5a47f8:1-429,
    5bcba8f5-9f15-11e9-9b14-e4434b210748:1-6319147104,
    5d2b585f-9f15-11e9-a58d-e4434b2106e8:1-1373519,
    62cdce4f-9f15-11e9-9f0d-e4434b21b430:1-2,
    66b80dbd-c979-11e9-8582-246e96c58570:1,
    85e1f282-f3a7-11e9-a222-e4434b2106e8:1-24
    *************************** 2. row ***************************
    Variable_name: gtid_executed_compression_period
            Value: 1000
    *************************** 3. row ***************************
    Variable_name: gtid_mode
            Value: ON
    *************************** 4. row ***************************
    Variable_name: gtid_owned
            Value:
    *************************** 5. row ***************************
    Variable_name: gtid_purged
            Value: 5a1a41db-9f15-11e9-a991-e4434b210720:1-2,
    5aa95098-9f15-11e9-98f3-e4434b5a47f8:1-429,
    5bcba8f5-9f15-11e9-9b14-e4434b210748:1-6047460531:6047460533,
    5d2b585f-9f15-11e9-a58d-e4434b2106e8:1-1373519,
    62cdce4f-9f15-11e9-9f0d-e4434b21b430:1-2,
    66b80dbd-c979-11e9-8582-246e96c58570:1,
    85e1f282-f3a7-11e9-a222-e4434b2106e8:1-22
    5 rows in set (0.00 sec)
    
    ERROR:
    No query specified
    
    Sun Dec  8 16:57:49 2019

    这里有4个变量,其中gtid_mode已经介绍过了,其他3个变量的含义如下

            gtid_executed:这既是一个Global级别的变量,又是一个Session级别的变量,是只读变量。Global级别的gtid_executed表示当前实例已经执行过的GTID集合。Session级别的gtid_executed一般情况下是空的。

            gtid_owned:这既是一个Global级别的变量,又是一个Session级别的变量,是只读变量。Global级别的gtid_owned表示当前实例正在执行中的GTID,以及对应的线程id。Session级别的gtid_owned一般情况下是空的。

            gtid_purged:这是一个Global级别的变量,可动态修改。我们知道binlog可以被purge掉,gtid_purged表示当前实例中已经被purge掉的GTID集合,很明显gtid_purged是gtid_executed的子集。但是gtid_purged也不是可以随意修改的,必须在@@global.gtid_executed是空的情况下,才可以动态设置gtid_purged。

     

    binlog文件中的gtid

    #  at  120
    #151222  9:07:58 server id 1026872634  end_log_pos 247 CRC32 0xedf993a8     Previous-GTIDs
    # b3485508-883f-11e5-85fb-e41f136aba3e:1-14,
    # b694c8b2-883f-11e5-85fb-e41f136aba3e:1-10115960:12000000-12000005
    #  at  247
    #151222  9:08:03 server id 1026872625  end_log_pos 295 CRC32 0xc3d3d8ee     GTID [ commit =yes]
    SET  @@SESSION.GTID_NEXT=  'b694c8b2-883f-11e5-85fb-e41f136aba3e:10115961' /*!*/;
    #  at  295
    #151222  9:08:03 server id 1026872625  end_log_pos 370 CRC32 0x0a32d229     Query   thread_id=18    exec_time=1 error_code=0
    BEGIN
    /*!*/;
    #  at  370
    #151222  9:08:03 server id 1026872625  end_log_pos 480 CRC32 0x3c0e094f     Query   thread_id=18    exec_time=1 error_code=0
    use `db`/*!*/;
    SET  TIMESTAMP =1450746483/*!*/;
    update  tb  set  val = val + 1  where  id = 1
    /*!*/;
    #  at  480
    #151222  9:08:03 server id 1026872625  end_log_pos 511 CRC32 0x5772f16b     Xid = 6813913
    COMMIT /*!*/;
    #  at  511
    #151222  9:10:19 server id 1026872625  end_log_pos 559 CRC32 0x3ac30191     GTID [ commit =yes]
    SET  @@SESSION.GTID_NEXT=  'b694c8b2-883f-11e5-85fb-e41f136aba3e:10115962' /*!*/;
    #  at  559
    #151222  9:10:19 server id 1026872625  end_log_pos 634 CRC32 0x83a74912     Query   thread_id=18    exec_time=0 error_code=0
    SET  TIMESTAMP =1450746619/*!*/;
    BEGIN
    /*!*/;
    #  at  634
    #151222  9:10:19 server id 1026872625  end_log_pos 744 CRC32 0x581f6031     Query   thread_id=18    exec_time=0 error_code=0
    SET  TIMESTAMP =1450746619/*!*/;
    update  tb  set  val = val + 1  where  id = 1
    /*!*/;
    #  at  744
    #151222  9:10:19 server id 1026872625  end_log_pos 775 CRC32 0x793f8e34     Xid = 6813916
    COMMIT /*!*/;

    这段Binlog从文件120偏移处(Format_description_log_event之后的第一个Binlog Event)开始截取。可以看到,第一个Binlog Event的类型为:Previous-GTIDs,它存在于每个binlog文件中。当开启GTID时,每个binlog文件都有且只有一个Previous-GTIDs,位置都是在Format_description_log_event之后的第一个Binlog Event处。它的含义是在当前Binlog文件之前执行过的GTID集合,可以充当索引用,使用这个Binlog Event,可以便于快速判断GTID是否位于当前binlog文件中。

     下面看看gtid_purged和gtid_executed是如何构造的。MySQL在启动时打开最老的binlog文件,读取其中的Previous-GTIDs,那么就是@@global.gtid_purged。MySQL在启动时打开最新的binlog文件,读取其中的Previous-GTIDs,构造一个gtid_set,然后再遍历这个最新的binlog文件,把遇到的每个gtid都添加到gtid_set中,当文件遍历完成时,这个gtid_set就是@@global.gtid_executed。

            前面说过只有在@@global.gtid_executed为空的情况下,才可以动态设置@@global.gtid_purged。因此可以通过RESET MASTER的方式来清空@@global.gtid_executed。这一点,类似Ares中的命令:set binlog_group_id=XXX, master_server_id=YYY with reset;(是会删除binlog的) 通过解析上面的binlog文件,我们也可以看到,每个事务之前,都有一个GTID_log_event,用来指定GTID的值。总体来看,一个MySQL binlog的格式大致如下:

     

     我们知道,在未开启GTID模式的情况下,从库用(File_name和File_pos)二元组标识执行到的位置。START SLAVE时,从库会先向主库发送一个BINLOG_DUMP命令,在BINLOG_DUMP命令中指定File_name和File_pos,主库就从这个位置开始发送binlog。

             在开启GTID模式的情况下,如果指定MASTER_AUTO_POSITION=1。START SLAVE时,从库会计算Retrieved_Gtid_Set和Executed_Gtid_Set的并集(通过SHOW SLAVE STATUS可以查看),然后把这个GTID并集发送给主库。主库会使用从库请求的GTID集合和自己的gtid_executed比较,把从库GTID集合里缺失的事务全都发送给从库。如果从库缺失的GTID,已经被主库pruge了呢?从库报1236错误,IO线程中断。

            主库发送的二进制的事件:主库Executed_Gtid_Set对从库(Retrieved_Gtid_Set U Executed_Gtid_Set)的补集

           

    Retrieved_Gtid_Set:从库已经接收到主库的事务编号
    Executed_Gtid_Set:已经执行的事务编号

            考虑下面这种情况,有个集群已经在使用GTID模式同步,想给集群增加一台从库,新做完一台从库,数据和主库一致,但是没有binlog,也就是说新从库的@@global.gtid_executed是空的。但是CHANGE MASTER时可以通过File_name和File_pos找到正确的同步点,然后START SLAVE,一切正常。过了一会儿,觉得还可以通过MASTER_AUTO_POSITION = 1的方式重新CHANGE MASTER,然后再START SLAVE。这种情况下,主库一看从库GTID里少了那么多binlog,然后把全部缺失的binglog再给从库发送一遍,那么悲剧就发生了。

            为了解决这个问题,新做完从库以后,应该在从库上执行reset master; set global gtid_purged = 'xxxxx',把缺失的GTID集合设置为purged,然后就可以直接使用MASTER_AUTO_POSITION=1自动找点儿了

            由此可见,开启GTID以后,Binlog和数据文件一样重要,不仅要求主从数据一致,还要求主从Binlog中GTID集合一致。

     

     

     

     

     

     

     

  • 相关阅读:
    ES6——Promise
    ES6——generator-yield
    ES6——generator
    JQuery——关于CDN(内容分发网络)
    关于JSON使用要注意的地方
    第7课
    第6课
    第5课
    第4课
    第3课
  • 原文地址:https://www.cnblogs.com/igoodful/p/12006315.html
Copyright © 2011-2022 走看看