zoukankan      html  css  js  c++  java
  • 转 GTID复制的搭建和问题处理

    ########sample 1: 了解mysqldump 和 mysqlbackup  和 gtid_executed 和 gtid_purged

    https://www.linuxidc.com/Linux/2017-05/144177.htm

    首先看一下什么是GTID:
    GTID(Global Transaction ID)是对于一个已提交事务的编号,并且是一个全局唯一的编号。
    GTID实际上是由UUID+TID组成的。其中UUID是一个MySQL实例的唯一标识。TID代表了该实例上已经提交的事务数量,并且随着事务提交单调递增。根据GTID可以知道事务最初是在哪个实例上提交的,而且方便故障切换。
     
    接下来就看一下怎么在GTID模式下快速的添加一个slave:
    我们知道在没有GTID复制以前,MySQL的复制是基于binary log和position来做的,之前的复制我们要执行下面的change语句:
    CHANGE MASTER TO MASTER_HOST='',MASTER_PORT=3306,MASTER_USER='repl',MASTER_PASSWORD='*****',MASTER_LOG_FILE='mysqlbinlog.000003',MASTER_LOG_POS=99721204;

    而我们在GTID就可以执行以下的change语句:

    CHANGE MASTER TO  MASTER_HOST='****', MASTER_USER='repl',  MASTER_PASSWORD='******',  MASTER_PORT=3306,  master_auto_position=1;

    我们可以看到,基本上来说指定复制的时候原来的binary log方式需要指定MASTER_LOG_FILE和MASTER_LOG_POS,而GTID复制却不需要知道这些参数。

    下面看一下怎么在GTID的模式下创建主从复制:
    从上面可以看得到,在GTID的模式下我们不再需要知道MASTER_LOG_FILE和MASTER_LOG_POS两个参数,相比之下我们只需要指定master就可以了,这对于创建复制来说简单的多了。在GTID的模式下我们需要知道以下两个全局变量:
    root@perconatest09:23:44>show global variables like 'GTID_%'G
    *************************** 1. row ***************************
    Variable_name: gtid_executed
    Value: 5031589f-3551-11e7-89a0-00505693235d:1-12,
    806ede0c-357e-11e7-9719-00505693235d:1-11,
    a38c33ee-34b7-11e7-ae1d-005056931959: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: 5031589f-3551-11e7-89a0-00505693235d:1-12,
    806ede0c-357e-11e7-9719-00505693235d:1-11,
    a38c33ee-34b7-11e7-ae1d-005056931959:1-12 
    我们主要需要看到的就是gtid_executed和gtid_purged两个参数,
    gtid_executed:这个是已经执行过的所有的事物的GTID的一个系列串,也就是binary log里面已经落盘的事物的序列号。这个参数是只读的,不能够进行设置。
    gtid_purged:这个序列是指我们在binary log删除的事物的GTID的序列号。我们可以手动进行设置,方便我们做一些管理。
    这两个参数理解以后,接下来我们看一下怎样去添加一个GTID复制的从库:
    (1):从主库做一个全备份,而且要记录主库备份时间点的gtid_executed
    (2):从库进行恢复,而且将从库的gtid_purged设置为我们第一步获取的master的gtid_executed
    (3):执行CHANGE MASTER 语句。
    我们使用mysqldump就可以将主库进行备份,并且将备份还原到一台新的机器作为从库。在执行之前先在主库看一下参数:
    root@perconatest09:23:58>show global variables like 'GTID_e%'G
    *************************** 1. row ***************************
    Variable_name: gtid_executed
    Value: 5031589f-3551-11e7-89a0-00505693235d:1-12,
    806ede0c-357e-11e7-9719-00505693235d:1-11,
    a38c33ee-34b7-11e7-ae1d-005056931959:1-24
    2 rows in set (0.01 sec)
    root@perconatest09:41:33>show global variables like 'GTID_p%'G
    *************************** 1. row ***************************
    Variable_name: gtid_purged
    Value: 5031589f-3551-11e7-89a0-00505693235d:1-12,
    806ede0c-357e-11e7-9719-00505693235d:1-11,
    a38c33ee-34b7-11e7-ae1d-005056931959:1-12
    1 row in set (0.01 sec)

    然后在主库进行备份:

    mysqldump --all-databases --single-transaction --triggers --routines --host=127.0.0.1 --port=18675 --user=root--p > /home/sa/backup.sql

    我们可以看一下备份文件:

    [root@localhost sa]# head -30 backup.sql

    我们能够看到有以下的参数:

    SET @@GLOBAL.GTID_PURGED='5031589f-3551-11e7-89a0-00505693235d:1-12,
    806ede0c-357e-11e7-9719-00505693235d:1-11,
    a38c33ee-34b7-11e7-ae1d-005056931959:1-24';

    也就是说当我们进行恢复的时候,是会自动设置GTID_PURGED的,而这个值刚好就是master的gtid_executed,所以我们从库恢复以后基本上就不需要在做指定了。

    进入从库恢复数据:
    source backup.sql;
    我们知道已经不需要在指定GTID_PURGE的值了,要是不确定还可以确认一下:
    show global variables like 'gtid_executed';
    show global variables like 'gtid_purged';

    后面直接指定复制就好了:

    CHANGE MASTER TO MASTER_HOST="***", MASTER_USER="root", MASTER_PASSWORD="*****", MASTER_PORT=3306, MASTER_AUTO_POSITION = 1;

    将*替换为你需要指定的主库的相关信息就OK了。

    GTID主从复制的模式下如果出现错误,我们该怎么恢复呢?
    假如我们的主库的日志已经purged,执行了reset等操作,我们从库会有如下报错:
    Last_IO_Error: Got fatal error 1236 from master when reading data from binary log: 'The slave is connecting using CHANGE MASTER TO MASTER_AUTO_POSITION = 1, but the master has purged binary logs containing GTIDs that the slave requires.'

    提示我们找不到日志,主从复制就会停掉,下面我们看一下处理方式:

    (1)主库执行以下操作:
     
    root@perconatest09:41:38>show global variables like 'GTID_EXECUTED';
    +---------------+---------------------------------------------------------------------------------------------------------------------------------+
    | Variable_name | Value |
    +---------------+---------------------------------------------------------------------------------------------------------------------------------+
    | gtid_executed | 5031589f-3551-11e7-89a0-00505693235d:1-12,
    806ede0c-357e-11e7-9719-00505693235d:1-11,
    a38c33ee-34b7-11e7-ae1d-005056931959:1-24 |
    +---------------+---------------------------------------------------------------------------------------------------------------------------------+
    1 row in set (0.01 sec) 
    (2)从库
    root@(none)03:04:49>set global GTID_PURGED='5031589f-3551-11e7-89a0-00505693235d:1-12,806ede0c-357e-11e7-9719-00505693235d:1-11,a38c33ee-34b7-11e7-ae1d-005056931959:1-24';

    注意,在指定前首先要确认这个值是空的,不然我们要做以下操作:

    root@(none)03:04:49>reset master;
    root@(none)03:04:49>set global GTID_PURGED='5031589f-3551-11e7-89a0-00505693235d:1-12,806ede0c-357e-11e7-9719-00505693235d:1-11,a38c33ee-34b7-11e7-ae1d-005056931959:1-24';
    root@(none)03:04:49>start slave;
    root@(none)03:04:49>show slave statusG

    这样修复就完成了,但是我们最好还是用checksum校验一下主从数据的一致性。

    报错信息:
    Got fatal error 1236 from master when reading data from binary log: ‘The slave is connecting using CHANGE MASTER TO MASTER_AUTO_POSITION = 1, but the master has purged binary logs containing GTIDs that the slave requires
    (贴个错误信息为了增加浏览量)
    当然上面的方法并不能保证数据的完全一致性,我们还要去校验使用 pt-table-checksum and pt-table-sync,但是这样效率不一定是最高的,最好的方式还是通过前面介绍的,做全备份,然后恢复,再指定master,这才是最靠谱的。

    本文永久更新链接地址http://www.linuxidc.com/Linux/2017-05/144177.htm

    ###########ref

    https://blog.csdn.net/weixin_40410849/article/details/78342496

    https://www.cnblogs.com/zhoujinyi/p/4717951.html

    背景:

          MySQL5.6在5.5的基础上增加了一些改进,本文章先对其中一个一个比较大的改进"GTID"进行说明。

    概念:

          GTID即全局事务ID(global transaction identifier),GTID实际上是由UUID+TID组成的。其中UUID是一个MySQL实例的唯一标识。TID代表了该实例上已经提交的事务数量,并且随着事务提交单调递增,所以GTID能够保证每个MySQL实例事务的执行(不会重复执行同一个事务,并且会补全没有执行的事务)。下面是一个GTID的具体形式:

    4e659069-3cd8-11e5-9a49-001c4270714e:1-77

    更具体的说明见官方说明

    GTID意义:

          引入GTID的意义是什么?

          1)因为清楚了GTID的格式,所以通过UUID可以知道这个事务在哪个实例上提交的。

          2)通过GTID可以极方便的进行复制结构上的故障转移,新主设置。很好的解决了下面这个图(图来自高性能MySQL第10章)的问题。

    上面图的意思是:Server1(Master)崩溃,根据从上show slave status获得Master_log_File/Read_Master_Log_Pos的值,Server2(Slave)已经跟上了主,Server3(Slave)没有跟上主。这时要是把Server2提升为主,Server3变成Server2的从。这时在Server3上执行change的时候需要做一些计算,这里就不做说明了,具体的说明见高性能MySQL第10章,相对来说是比较麻烦的。

    这个问题在5.6的GTID出现后,就显得非常的简单。由于同一事务的GTID在所有节点上的值一致,那么根据Server3当前停止点的GTID就能定位到Server2上的GTID。甚至由于MASTER_AUTO_POSITION功能的出现,我们都不需要知道GTID的具体值,直接使用CHANGE MASTER TO MASTER_HOST='xxx', MASTER_AUTO_POSITION命令就可以直接完成failover的工作。

    原理:

          从服务器连接到主服务器之后,把自己执行过的GTID(Executed_Gtid_Set)<SQL线程> 、获取到的GTID(Retrieved_Gtid_Set)<IO线程>发给主服务器,主服务器把从服务器缺少的GTID及对应的transactions发过去补全即可。当主服务器挂掉的时候,找出同步最成功的那台从服务器,直接把它提升为主即可。如果硬要指定某一台不是最新的从服务器提升为主, 先change到同步最成功的那台从服务器, 等把GTID全部补全了,就可以把它提升为主了。

    测试:

    1)复制环境的搭建:具体的复制搭建的步骤可以在网上搜索

    因为支持GTID,所以5.6多了几个参数:

    复制代码
    mysql> show variables like '%gtid%';
    +---------------------------------+-----------+
    | Variable_name                   | Value     |
    +---------------------------------+-----------+
    | binlog_gtid_simple_recovery     | OFF       |
    | enforce_gtid_consistency        | OFF       |
    | gtid_deployment_step            | OFF       |
    | gtid_executed                   |           |
    | gtid_mode                       | OFF       |
    | gtid_next                       | AUTOMATIC |
    | gtid_owned                      |           |
    | gtid_purged                     |           |
    | simplified_binlog_gtid_recovery | OFF       |
    +---------------------------------+-----------+
    复制代码

    主从环境的搭建和5.5没有什么区别,唯一需要注意的是:开启GTID需要启用这三个参数:

    #GTID
    gtid_mode = on
    enforce_gtid_consistency = 1
    log_slave_updates   = 1

    任意一个参数不开启则都会报错:

    2015-08-09 02:33:57 6512 [ERROR] --gtid-mode=ON or UPGRADE_STEP_1 or UPGRADE_STEP_2 requires --log-bin and --log-slave-updates
    2015-08-09 02:33:57 6512 [ERROR] Aborting
    
    2015-08-09 02:39:58 9860 [ERROR] --gtid-mode=ON or UPGRADE_STEP_1 requires --enforce-gtid-consistency
    2015-08-09 02:39:58 9860 [ERROR] Aborting

    具体的方法可以参考官方文档

    三个实例开启之后(3306、3307、3308),执行change的时候也要注意:

    各个实例的uuid:

    复制代码
    3306:
    mysql> select @@server_uuid;
    +--------------------------------------+
    | @@server_uuid                        |
    +--------------------------------------+
    | 4e659069-3cd8-11e5-9a49-001c4270714e |
    +--------------------------------------+
    
    3307:
    mysql> select @@server_uuid;
    +--------------------------------------+
    | @@server_uuid                        |
    +--------------------------------------+
    | 041d0e65-3cde-11e5-9a6e-001c4270714e |
    +--------------------------------------+
    
    3308:
    mysql> select @@server_uuid;
    +--------------------------------------+
    | @@server_uuid                        |
    +--------------------------------------+
    | 081ccacf-3ce4-11e5-9a95-001c4270714e |
    +--------------------------------------+
    复制代码

    使用5.6之前的主从change:

    mysql> change master to master_host='127.0.0.1',master_user='rep',master_password='rep',master_log_file='mysql-bin3306.000001',master_log_pos=151,/*master_auto_position=1*/;

    报错:

    ERROR 1776 (HY000): Parameters MASTER_LOG_FILE, MASTER_LOG_POS, RELAY_LOG_FILE and RELAY_LOG_POS cannot be set when MASTER_AUTO_POSITION is active.

    当使用 MASTER_AUTO_POSITION 参数的时候,MASTER_LOG_FILE,MASTER_LOG_POS参数不能使用。

    使用5.6之后的主从change:

    mysql> change master to master_host='127.0.0.1',master_user='rep',master_password='rep',master_port=3306,master_auto_position=1;

    在执行上面的命令的时候会报错2个warnings,主要的原因是复制账号安全的问题,相关的信息可以看这里

    从总体上看来,由于要支持GTID,所以不需要手工确定主服务器的MASTER_LOG_FILE及MASTER_LOG_POS。要是不需要GTID则需要指定FILE和POS。在2个从上执行上面命令,到此主从环境搭建完成。GTID的主从完成之后可以通过show processlist查看:

    复制代码
    mysql> show processlistG;
    *************************** 1. row ***************************
               Id: 38
             User: rep
             Host: localhost:52321
               db: NULL
          Command: Binlog Dump GTID   #通过GTID复制
             Time: 48
            State: Master has sent all binlog to slave; waiting for binlog to be updated
             Info: NULL
        Rows_sent: 0
    Rows_examined: 0
    复制代码

    2)测试复制的故障转移

    server1(3306)挂了,服务器起不来了。需要把其中的一个从设置为主,另一个设置为其的从库:

    server2(3307):

                  Master_Log_File: mysql-bin3306.000002
              Read_Master_Log_Pos: 4156773
              Exec_Master_Log_Pos: 4156773

    server3(3308):

                  Master_Log_File: mysql-bin3306.000001
              Read_Master_Log_Pos: 83795320
              Exec_Master_Log_Pos: 83795320

    相比之下server2完成的事务要比server3更接近或则等于server1,现在需要把server3设置为server2的从库。

    在MySQL5.6之前,这里的计算会很麻烦,要计算之前主库的log_pos和当前要设置成主库的log_pos,很有可能出错。所以出现了一些高可用性的工具如MHA,MMM等解决问题。

    在MySQL5.6之后,很简单的解决了这个难题。因为同一事务的GTID在所有节点上的值一致,那么根据server3当前停止点的GTID就能定位到server2上的GTID,所以直接在server3上执行change即可:

    复制代码
    mysql> stop slave;
    Query OK, 0 rows affected (0.02 sec)

    #千万不要执行 reset master,否则会从最先的GTID上开始执行。 mysql> change master to master_host='127.0.0.1',master_user='rep',master_password='rep',master_port=3307,master_auto_position=1; #指定到另一个比较接近主的从上。 Query OK, 0 rows affected, 2 warnings (0.02 sec) mysql> start slave; #成功的切换到新主 Query OK, 0 rows affected (0.03 sec)
    复制代码

    主从结构已经变更,server2是Master,server3是Slave。因为不需要计算pos的值,所以通过GTID很简单的解决了这个问题。

    3)跳过复制错误:gtid_next、gtid_purged

     从服务器跳过一个错误的事务:

    复制代码
    mysql> show slave statusG;
    *************************** 1. row ***************************
                   Slave_IO_State: Waiting for master to send event
                      Master_Host: 127.0.0.1
                      Master_User: rep
                      Master_Port: 3306
                    Connect_Retry: 60
                  Master_Log_File: mysql-bin3306.000001
              Read_Master_Log_Pos: 38260944
                   Relay_Log_File: mysqld-relay-bin3307.000002
                    Relay_Log_Pos: 369
            Relay_Master_Log_File: mysql-bin3306.000001
                 Slave_IO_Running: Yes
                Slave_SQL_Running: No
                  Replicate_Do_DB: 
              Replicate_Ignore_DB: 
               Replicate_Do_Table: 
           Replicate_Ignore_Table: 
          Replicate_Wild_Do_Table: 
      Replicate_Wild_Ignore_Table: 
                       Last_Errno: 1008
                       Last_Error: Error 'Can't drop database 'mablevi'; database doesn't exist' on query. Default database: 'mablevi'. Query: 'drop database mablevi'
                     Skip_Counter: 0
              Exec_Master_Log_Pos: 151
                  Relay_Log_Space: 38261371
                  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: NULL
    Master_SSL_Verify_Server_Cert: No
                    Last_IO_Errno: 0
                    Last_IO_Error: 
                   Last_SQL_Errno: 1008
                   Last_SQL_Error: Error 'Can't drop database 'mablevi'; database doesn't exist' on query. Default database: 'mablevi'. Query: 'drop database mablevi'
      Replicate_Ignore_Server_Ids: 
                 Master_Server_Id: 1
                      Master_UUID: 4e659069-3cd8-11e5-9a49-001c4270714e
                 Master_Info_File: mysql.slave_master_info
                        SQL_Delay: 0  #通过在change的时候指定,如:change master to master_delay=600,延迟10分钟同步。
              SQL_Remaining_Delay: NULL
          Slave_SQL_Running_State: 
               Master_Retry_Count: 86400
                      Master_Bind: 
          Last_IO_Error_Timestamp: 
         Last_SQL_Error_Timestamp: 150810 23:38:39
                   Master_SSL_Crl: 
               Master_SSL_Crlpath: 
               Retrieved_Gtid_Set: 4e659069-3cd8-11e5-9a49-001c4270714e:1-48
                Executed_Gtid_Set: 
                    Auto_Position: 1
    复制代码

    在MySQL5.6之前,只需要执行:

    mysql> set global sql_slave_skip_counter=1; 

    跳过一个错误的事务,就可以继续进行复制了。但在MySQL5.6之后则不行:

    mysql> set global sql_slave_skip_counter=1;
    ERROR 1858 (HY000): sql_slave_skip_counter can not be set when the server is running with @@GLOBAL.GTID_MODE = ON. Instead, for each transaction that you want to skip, generate an empty transaction with the same GTID as the transaction

    分析:因为是通过GTID来进行复制的,也需要跳过这个事务从而继续复制,这个事务可以到主上的binlog里面查看:因为不知道找哪个GTID上出错,所以也不知道如何跳过哪个GTID。但在show slave status里的信息里可以找到在执行Master里的POS:151

    Exec_Master_Log_Pos: 151

    的时候报错,所以通过mysqlbinlog找到了GTID:

    # at 151
    #150810 22:57:45 server id 1  end_log_pos 199 CRC32 0x5e14d88f     GTID [commit=yes]
    SET @@SESSION.GTID_NEXT= '4e659069-3cd8-11e5-9a49-001c4270714e:1'/*!*/;

    找到这个GTID之后执行:必须按照下面顺序执行

    复制代码
    mysql> stop slave;
    Query OK, 0 rows affected (0.01 sec)
    
    mysql> set session gtid_next='4e659069-3cd8-11e5-9a49-001c4270714e:1';  #在session里设置gtid_next,即跳过这个GTID
    Query OK, 0 rows affected (0.01 sec)
    
    mysql> begin;      #开启一个事务
    Query OK, 0 rows affected (0.00 sec)
    
    mysql> commit;
    Query OK, 0 rows affected (0.01 sec)
    
    mysql> SET SESSION GTID_NEXT = AUTOMATIC;   #把gtid_next设置回来
    Query OK, 0 rows affected (0.00 sec)
    
    mysql> start slave;  #开启复制
    Query OK, 0 rows affected (0.01 sec)
    复制代码

    查看复制状态:

    复制代码
    mysql> show slave statusG;
    *************************** 1. row ***************************
                   Slave_IO_State: Waiting for master to send event
                      Master_Host: 127.0.0.1
                      Master_User: rep
                      Master_Port: 3306
                    Connect_Retry: 60
                  Master_Log_File: mysql-bin3306.000001
              Read_Master_Log_Pos: 38260944
                   Relay_Log_File: mysqld-relay-bin3307.000003
                    Relay_Log_Pos: 716
            Relay_Master_Log_File: mysql-bin3306.000001
                 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: 38260944
                  Relay_Log_Space: 38261936
                  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: 4e659069-3cd8-11e5-9a49-001c4270714e
                 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 the slave I/O thread to update it
               Master_Retry_Count: 86400
                      Master_Bind: 
          Last_IO_Error_Timestamp: 
         Last_SQL_Error_Timestamp: 
                   Master_SSL_Crl: 
               Master_SSL_Crlpath: 
               Retrieved_Gtid_Set: 4e659069-3cd8-11e5-9a49-001c4270714e:1-48
                Executed_Gtid_Set: 4e659069-3cd8-11e5-9a49-001c4270714e:1-48
                    Auto_Position: 1
    复制代码

    在此成功跳过了错误,同步继续。可以通过这个办法来处理复制失败的问题,这里还有个例子,有兴趣的可以看一下(从服务器中跳过一条语句/事务):

    复制代码
    mysql > stop slave;
    Query OK, 0 ROWS affected (0.05 sec)
    mysql > CHANGE master TO MASTER_DELAY=600;
    Query OK, 0 ROWS affected (0.27 sec)
    mysql > START slave;
    Query OK, 0 ROWS affected, 1 warning (0.06 sec)
    
    master 原本是正常的, 然后意外地执行了 truncate table:
    
    mysql > INSERT INTO t SET title='c';
    Query OK, 1 ROW affected (0.03 sec)
    mysql > INSERT INTO t SET title='d';
    Query OK, 1 ROW affected (0.05 sec)
    
    mysql > SHOW master STATUS G
    *************************** 1. ROW ***************************
                 File: black-bin.000001
             POSITION: 2817
         Binlog_Do_DB: 
     Binlog_Ignore_DB: 
    Executed_Gtid_Set: 0c005b76-d3c7-11e2-a27d-274c063b18c4:1-10
    1 ROW IN SET (0.00 sec)
    
    mysql > TRUNCATE TABLE t;
    Query OK, 0 ROWS affected (0.15 sec)
    
    mysql > SHOW master STATUS G
    *************************** 1. ROW ***************************
                 File: black-bin.000001
             POSITION: 2948
         Binlog_Do_DB: 
     Binlog_Ignore_DB: 
    Executed_Gtid_Set: 0c005b76-d3c7-11e2-a27d-274c063b18c4:1-11
    1 ROW IN SET (0.00 sec)
    
    slave有延迟, 虽然已经获取到了gtid及对应的events, 但是并未执行:
    
    mysql > SHOW slave STATUS G
    *************************** 1. ROW ***************************
                   Slave_IO_State: Waiting FOR master TO send event
    .......
    .......
                        SQL_Delay: 600
              SQL_Remaining_Delay: 565
          Slave_SQL_Running_State: Waiting until MASTER_DELAY seconds after master executed event
               Master_Retry_Count: 86400
                      Master_Bind: 
          Last_IO_Error_Timestamp: 
         Last_SQL_Error_Timestamp: 
                   Master_SSL_Crl: 
               Master_SSL_Crlpath: 
               Retrieved_Gtid_Set: 0c005b76-d3c7-11e2-a27d-274c063b18c4:9-11
                Executed_Gtid_Set: 0c005b76-d3c7-11e2-a27d-274c063b18c4:1-8
                    Auto_Position: 1
    1 ROW IN SET (0.00 sec)
    
    要想办法在slave中跳过 GTID:0c005b76-d3c7-11e2-a27d-274c063b18c4:11, 也就是那条truncate table语句 。
    办法就是设置GTID_NEXT,然后提交一个空的事务。
    
    mysql > stop slave;
    Query OK, 0 ROWS affected (0.03 sec)
    mysql > SET session gtid_next='0c005b76-d3c7-11e2-a27d-274c063b18c4:11';
    Query OK, 0 ROWS affected (0.00 sec)
    mysql > BEGIN; commit;
    Query OK, 0 ROWS affected (0.00 sec)
    Query OK, 0 ROWS affected (0.01 sec)
    
    mysql >SET SESSION GTID_NEXT = AUTOMATIC;
    Query OK, 0 ROWS affected (0.00 sec)
    mysql > START slave;
    Query OK, 0 ROWS affected, 1 warning (0.07 sec)
    
    查看复制状态
    mysql > SHOW slave STATUS G
    *************************** 1. ROW ***************************
                   Slave_IO_State: Waiting FOR master TO send event
    .......
    .......
                Retrieved_Gtid_Set: 0c005b76-d3c7-11e2-a27d-274c063b18c4:9-11
                Executed_Gtid_Set: 0c005b76-d3c7-11e2-a27d-274c063b18c4:1-11
                    Auto_Position: 1
    1 ROW IN SET (0.00 sec)
    
    mysql > SELECT * FROM t;
    +----+-------+
    | id | title |
    +----+-------+
    |  1 | a     |
    |  2 | b     |
    |  3 | c     |
    |  4 | d     |
    +----+-------+
    4 ROWS IN SET (0.00 sec)
    
    成功跳过 truncate table, 当然此时主从的数据已经不一致了。
    复制代码

    注意:通过GTID的复制都是没有指定MASTER_LOG_FILE和MASTER_LOG_POS的,所以通过GTID复制都是从最先开始的事务开始,除非在自己的binlog里面有执行过之前的记录,才会继续后面的执行。

     要是事务日志被purge,再进行change:

    复制代码
    mysql> show master logs;   
    +----------------------+-----------+
    | Log_name             | File_size |
    +----------------------+-----------+
    | mysql-bin3306.000001 |  38260944 |
    +----------------------+-----------+
    1 row in set (0.00 sec)
    
    mysql> flush logs;
    Query OK, 0 rows affected (0.03 sec)
    
    mysql> show tables;
    +---------------+
    | Tables_in_mmm |
    +---------------+
    | patent_family |
    | t1            |
    | t2            |
    +---------------+
    3 rows in set (0.01 sec)
    
    mysql> create table t3(id int)engine = tokudb;
    Query OK, 0 rows affected (0.02 sec)
    
    mysql> insert into t3 values(3),(4);
    Query OK, 2 rows affected (0.05 sec)
    Records: 2  Duplicates: 0  Warnings: 0
    
    mysql> flush logs;
    Query OK, 0 rows affected (0.02 sec)
    
    mysql> create table ttt(id int)engine = tokudb;
    Query OK, 0 rows affected (0.02 sec)
    
    mysql> insert into ttt values(1),(2),(3),(4),(5);
    Query OK, 5 rows affected (0.03 sec)
    Records: 5  Duplicates: 0  Warnings: 0
    
    mysql> show master logs;
    +----------------------+-----------+
    | Log_name             | File_size |
    +----------------------+-----------+
    | mysql-bin3306.000001 |  38260995 |
    | mysql-bin3306.000002 |       656 |
    | mysql-bin3306.000003 |       619 |
    +----------------------+-----------+
    3 rows in set (0.00 sec)
    
    mysql> purge binary logs to 'mysql-bin3306.000003';  #日志被purge
    Query OK, 0 rows affected (0.02 sec)
    
    mysql> show master logs;   #日志被purge之后等下的binlog 
    +----------------------+-----------+
    | Log_name             | File_size |
    +----------------------+-----------+
    | mysql-bin3306.000003 |       619 |
    +----------------------+--------
    
    3308登陆之后执行:
    
    mysql> change master to master_host='127.0.0.1',master_user='rep',master_password='rep',master_port=3306,master_auto_position=1;
    Query OK, 0 rows affected, 2 warnings (0.04 sec)
    
    mysql> start slave;
    Query OK, 0 rows affected (0.02 sec)
    
    mysql> show slave statusG;
    *************************** 1. row ***************************
                   Slave_IO_State: 
                      Master_Host: 127.0.0.1
                      Master_User: rep
                      Master_Port: 3306
                    Connect_Retry: 60
                  Master_Log_File: 
              Read_Master_Log_Pos: 4
                   Relay_Log_File: mysqld-relay-bin3308.000001
                    Relay_Log_Pos: 4
            Relay_Master_Log_File: 
                 Slave_IO_Running: No
                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: 0
                  Relay_Log_Space: 151
                  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: 1236
                    Last_IO_Error: Got fatal error 1236 from master when reading data from binary log: 'The slave is connecting using CHANGE MASTER TO MASTER_AUTO_POSITION = 1, but the master has purged binary logs containing GTIDs that the slave requires.'
                   Last_SQL_Errno: 0
                   Last_SQL_Error: 
      Replicate_Ignore_Server_Ids: 
                 Master_Server_Id: 1
                      Master_UUID: 4e659069-3cd8-11e5-9a49-001c4270714e
                 Master_Info_File: /var/lib/mysql3/master.info
                        SQL_Delay: 0
              SQL_Remaining_Delay: NULL
          Slave_SQL_Running_State: Slave has read all relay log; waiting for the slave I/O thread to update it
               Master_Retry_Count: 86400
                      Master_Bind: 
          Last_IO_Error_Timestamp: 150811 00:02:50
         Last_SQL_Error_Timestamp: 
                   Master_SSL_Crl: 
               Master_SSL_Crlpath: 
               Retrieved_Gtid_Set: 
                Executed_Gtid_Set: 
                    Auto_Position: 1
    复制代码

    报错:

                    Last_IO_Errno: 1236
                    Last_IO_Error: Got fatal error 1236 from master when reading data from binary log: 'The slave is connecting using CHANGE MASTER TO MASTER_AUTO_POSITION = 1, but the master has purged binary logs containing GTIDs that the slave requires.'

    这里需要解决的是:Slave如何跳过purge的部分,而不是在最先开始的事务执行。

    复制代码
    在主上执行,查看被purge的GTID:
    mysql> show global variables like 'gtid_purged';
    +---------------+-------------------------------------------+
    | Variable_name | Value                                     |
    +---------------+-------------------------------------------+
    | gtid_purged   | 4e659069-3cd8-11e5-9a49-001c4270714e:1-50 |
    +---------------+-------------------------------------------+
    1 row in set (0.00 sec)
    
    在从上执行,跳过这个GTID:
    mysql> stop slave;
    Query OK, 0 rows affected (0.00 sec)
    
    mysql> set global gtid_purged = '4e659069-3cd8-11e5-9a49-001c4270714e:1-50';
    Query OK, 0 rows affected (0.02 sec)
    
    mysql> reset master;
    Query OK, 0 rows affected (0.04 sec)
    
    mysql> start slave;
    Query OK, 0 rows affected (0.01 sec)
    
    
    要是出现:
    ERROR 1840 (HY000): @@GLOBAL.GTID_PURGED can only be set when @@GLOBAL.GTID_EXECUTED is empty.
    则需要执行:
    reset master;
    复制代码

    到这从的同步就正常了。 

     View Code

    ③ 通过另一个从库恢复从库数据

    比如一台从库误操作,数据丢失了,可以通过另一个从库来进行恢复:

    复制代码
    slave2(3308):
    mysql> use mmm
    Database changed
    mysql> show tables;
    +---------------+
    | Tables_in_mmm |
    +---------------+
    | patent_family |
    | t             |
    | tt            |
    +---------------+
    3 rows in set (0.00 sec)
    
    mysql> truncate table tt;  #误操作,把记录删除了
    Query OK, 0 rows affected (0.02 sec)
    
    mysql> show slave statusG;
    *************************** 1. row ***************************
                   Slave_IO_State: Waiting for master to send event
                      Master_Host: 127.0.0.1
                      Master_User: rep
                      Master_Port: 3306
                    Connect_Retry: 60
                  Master_Log_File: mysql-bin3306.000001
              Read_Master_Log_Pos: 38260553
                   Relay_Log_File: mysqld-relay-bin3308.000002
                    Relay_Log_Pos: 38260771
            Relay_Master_Log_File: mysql-bin3306.000001
                 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: 38260553
                  Relay_Log_Space: 38260980
                  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: 4e659069-3cd8-11e5-9a49-001c4270714e
                 Master_Info_File: /var/lib/mysql3/master.info
                        SQL_Delay: 0  #延迟同步
              SQL_Remaining_Delay: NULL
          Slave_SQL_Running_State: Slave has read all relay log; waiting for the slave I/O thread to update it
               Master_Retry_Count: 86400
                      Master_Bind: 
          Last_IO_Error_Timestamp: 
         Last_SQL_Error_Timestamp: 
                   Master_SSL_Crl: 
               Master_SSL_Crlpath: 
               Retrieved_Gtid_Set: 4e659069-3cd8-11e5-9a49-001c4270714e:1-46
                Executed_Gtid_Set: 081ccacf-3ce4-11e5-9a95-001c4270714e:1,  #多出了一个GTID(本身实例执行的事务)
    4e659069-3cd8-11e5-9a49-001c4270714e:1-46
                    Auto_Position: 1
    
    数据被误删除之后,最好停止复制:stop slave;
    
    恢复数据从slave1(3307)上备份数据,并还原到slave2(3308)中。
    备份:
    mysqldump  -uzjy -p123456 -h127.0.0.1 -P3307 --default-character-set=utf8 --set-gtid-purged=ON -B mmm > mmm1.sql
    
    
    在还原到slave2的时候需要在slave2上执行:reset master; 不然会报错:
    ERROR 1840 (HY000) at line 24: @@GLOBAL.GTID_PURGED can only be set when @@GLOBAL.GTID_EXECUTED is empty.
    
    还原:
    root@zjy:~# mysql -uzjy -p123456 -h127.0.0.1 -P3308 --default-character-set=utf8 < mmm.sql 
    
    开启同步:
    mysql> start slave;
    Query OK, 0 rows affected, 1 warning (0.03 sec)
    
    这时候你会发现误删除的数据已经被还原,并且复制也正常。因为根据GTID的原理,通过slave1的备份直接可以和Master进行同步。
    复制代码

    这里备份注意的一点是:在备份开启GTID的实例里,需要指定 --set-gtid-purged参数,否则会报warning:

    Warning: A partial dump from a server that has GTIDs will by default include the GTIDs of all transactions, even those that changed suppressed parts of the database. If you don't want to restore GTIDs, pass --set-gtid-purged=OFF. To make a complete dump, pass --all-databases --triggers --routines --events

    备份文件里面会出现:

    SET @@GLOBAL.GTID_PURGED='4e659069-3cd8-11e5-9a49-001c4270714e:1-483';

    还原的时候会要求先在实例上reset master,不然会报错:

    Warning: Using a password on the command line interface can be insecure.
    ERROR 1840 (HY000) at line 24: @@GLOBAL.GTID_PURGED can only be set when @@GLOBAL.GTID_EXECUTED is empty.

    指定--set-gtid-purged=ON参数,出现GTID_PURGED,直接还原的时候执行,从库不需要其他操作就可以直接change到主。关于GTID更多的信息可以到官方文档里查看。 

    总结:

          GTID就是全局事务ID(global transaction identifier ),最初由google实现,官方MySQL在5.6才加入该功能。要是主从结构只有一台Master和一台Slave对于GTID来说就没有优势了,而对于2台主以上的结构优势异常明显,可以在数据不丢失的情况下切换新主。
          使用GTID需要注意的是:在构建主从复制之前,在一台将成为主的实例上进行一些操作(如数据清理等),通过GTID复制,这些在主从成立之前的操作也会被复制到从服务器上,引起复制失败。即:通过GTID复制都是从最先开始的事务日志开始,即使这些操作在复制之前执行。比如在server1上执行一些drop、delete的清理操作,接着在server2上执行change的操作,会使得server2也进行server1的清理操作。

  • 相关阅读:
    2. Add Two Numbers
    1. Two Sum
    22. Generate Parentheses (backTracking)
    21. Merge Two Sorted Lists
    20. Valid Parentheses (Stack)
    19. Remove Nth Node From End of List
    18. 4Sum (通用算法 nSum)
    17. Letter Combinations of a Phone Number (backtracking)
    LeetCode SQL: Combine Two Tables
    LeetCode SQL:Employees Earning More Than Their Managers
  • 原文地址:https://www.cnblogs.com/feiyun8616/p/9047288.html
Copyright © 2011-2022 走看看