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的清理操作。

  • 相关阅读:
    引用 struts2标签详解
    Java 中日期的计算
    在一个FORM中实现多个ACTION动作
    java.lang.OutOfMemoryError: PermGen space最好的解决方法
    Java实现和栈的应用举例
    Java的自动装箱和拆箱
    oracle11g更改字符集AL32UTF8为ZHS16GBK
    设计的臭味
    OOD设计五个原则
    推荐JQuery学习简介
  • 原文地址:https://www.cnblogs.com/feiyun8616/p/9047288.html
Copyright © 2011-2022 走看看