mysql的uuid说明

MySQL GTID全面总结

01 gtid简介

      gtid,全称global transaction identifiers,也称之为全局事务id。mysql-5.6.2开始支持,mysql-5.6.10后完善,gtid 分成两部分,一部分是服务的uuid,uuid保存在mysql数据目录的auto.cnf文件中,
这是一个非常重要的文件,不能删除,这一部分是不会变的。下面是一个uuid的值举例:

  • ?
  • 1
  • 2
  • 3
  • [root@dev01 mysql]# cat auto.cnf 
  • [auto]
  • server-uuid=ac1ebad0-ef76-11e7-872b-080027a03bb6
  •     另外一部分就是事务id了,随着事务的增加,值依次递增。也就是说,gtid实际上是由uuid+tid组成的。其中uuid是一个mysql实例的唯一标识。tid代表了该实例上已经提交的事务数量。如下所示为一个gtid的例子:

  • ?
  • 1
  • 3db33b36-0e51-409f-a61d-c99756e90155:1-14
  • 02 gtid工作原理

    1、master更新数据时,会在事务前产生gtid,一同记录到binlog日志中。
    2、slave端的i/o 线程将变更的binlog,写入到本地的relay log中。
    3、sql线程从relay log中获取gtid,然后对比slave端的binlog是否有记录。
    4、如果有记录,说明该gtid的事务已经执行,slave会忽略。
    5、如果没有记录,slave就会从relay log中执行该gtid的事务,并记录到binlog。
    6、在解析过程中会判断是否有主键,如果没有就用二级索引,如果没有就用全部扫描。

    03 gtid的优缺点

    优点:

    1.一个事务对应一个唯一gtid,一个gtid在一个服务器上只会执行一次
    2.gtid是用来代替传统复制的方法,gtid复制与普通复制模式的最大不同就是不需要指定二进制文件名和位置
    3.减少手工干预和降低服务故障时间,当主机挂了之后通过软件从众多的备机中提升一台备机为主机

    缺点:

    1.不支持非事务引擎
    2.不支持create table ... select 语句复制(主库直接报错)
    原理:( 会生成两个sql,一个是ddl创建表sql,一个是insert into 插入数据的sql。
    由于ddl会导致自动提交,所以这个sql至少需要两个gtid,但是gtid模式下,只能给这个sql生成一个gtid )
    3.不允许一个sql同时更新一个事务引擎表和非事务引擎表
    4.开启gtid需要重启(5.7除外)
    5.对于create temporary table 和 drop temporary table语句不支持
    6.不支持sql_slave_skip_counter

    04 测试环境搭建

     节点:
    server1   192.168.197.128  3306   master
    server2   192.168.197.137  3306   slave
    server3   192.168.197.136  3306   slave

    开启gtid需要启用这三个参数:

    gtid_mode = on

    enforce_gtid_consistency = 1

    log_slave_updates   = 1

    搭建测试环境的步骤如下:

    1.在主节点上创建复制用户,开启主节点的gtid选项;

  • ?
  • 1
  • 2
  • mysql> grant replication slave on *.* to 'repluser'@'%' identified by '123456';
  • query ok, 0 rows affected, 1 warning (0.00 sec)
  • 2.从节点上进行change master to操作,搭建主从,如下:

  • ?
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • mysql> change master to
  •     -> master_host='192.168.197.128',
  •     -> master_user='repluser',
  •     -> master_password='123456',
  •     -> master_port=3306,
  •     -> master_auto_position=1;
  • query ok, 0 rows affected, 2 warnings (0.01 sec)
  • 3.搭建成功后,在主节点197.128上查看从节点是否加入:

  • ?
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • mysql> show slave hosts;
  • +-----------+------+------+-----------+--------------------------------------+
  • | server_id | host | port | master_id | slave_uuid              |
  • +-----------+------+------+-----------+--------------------------------------+
  • |     3 |   | 3306 |     | 969488f5-c486-11e8-adb7-000c29bf2c97 |
  • |     2 |   | 3306 |     | bb874065-c485-11e8-8b52-000c2934472e |
  • +-----------+------+------+-----------+--------------------------------------+
  •  rows in set (. sec)
  • 查看连接:

  • ?
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • mysql> show processlist;
  • +----+----------+------------------+------+------------------+------+---------------------------------------------------------------+------------------+
  • | id | user   | host       | db  | command     | time | state                             | info       |
  • +----+----------+------------------+------+------------------+------+---------------------------------------------------------------+------------------+
  • |  | root   | localhost    | null | query      |  0 | starting                           | show processlist |
  • | 3 | repluser | work_nat_4:60051 | null | binlog dump gtid | | master has sent all binlog to slave; waiting for more updates | null       |
  • |  | repluser | work_nat_5: | null | binlog dump gtid | 5970 | master has sent all binlog to slave; waiting for more updates | null       |
  • +----+----------+------------------+------+------------------+------+---------------------------------------------------------------+------------------+
  •  rows in set (. sec)
  • 4.三台测试环境的uuid分别是:

  • ?
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 197.128
  • mysql> select @@server_uuid;
  • +--------------------------------------+
  • | @@server_uuid            |
  • +--------------------------------------+
  • | bd0d-8691-11e8-afd6-4c3e51db5828 |
  • +--------------------------------------+
  •  row in set (0.00 sec)
  •  
  • 197.137
  • mysql> select @@server_uuid;
  • +--------------------------------------+
  • | @@server_uuid            |
  • +--------------------------------------+
  • | bb874065-c485-11e8-8b52-000c2934472e |
  • +--------------------------------------+
  •  row in set (0.00 sec)
  •  
  • 197.136
  • mysql> select @@server_uuid;
  • +--------------------------------------+
  • | @@server_uuid            |
  • +--------------------------------------+
  • | f5-c486-11e8-adb7-000c29bf2c97 |
  • +--------------------------------------+
  •  row in set (0.00 sec)
  • 05 开始测试

    测试环境主要分为以下几个方面:

    a.测试复制的故障转移

    b.复制错误跳过

    1 测试复制的故障转移

    先来看看测试复制的故障转移:

    (1)首先将server 3的复制过程停掉

  • ?
  • 1
  • 2
  • mysql> stop slave;
  • query ok, 0 rows affected (0.01 sec)
  • (2)在server 1上创建一些数据

  • ?
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • mysql> create table yyy.a(id int);
  • query ok, 0 rows affected (0.03 sec)
  •  
  • mysql> create table yyy.b(id int);
  • query ok, 0 rows affected (0.02 sec)
  •  
  • mysql> create table yyy.c(id int);
  • query ok, 0 rows affected (0.02 sec)
  • (3)在另外两台上面查看数据结果:

  • ?
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • server
  • mysql> show tables from yyy;
  • +---------------+
  • | tables_in_yyy |
  • +---------------+
  • | a       |
  • | b       |
  • | c       |
  • +---------------+
  •  rows in set (0.00 sec)
  •  
  • server
  • mysql> show tables from yyy;
  • empty set (0.00 sec)
  • (4)此时可以发现,server 2 的数据相比较server 3,它的数据比较新,此时停止server 1,模拟主服务器宕机:

  • ?
  • 1
  • 2
  • [root@work_nat_1 init.d]# service mysqld stop
  • shutting down mysql............              [ ok ]
  • (5)此时我们发现其他两个节点已经不能访问server 1了

  • ?
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • mysql> show slave status\g
  • *************************** 1. row ***************************
  •         slave_io_state: reconnecting after a failed master event read
  •          master_host: 192.168.197.128
  •          master_user: repluser
  •          master_port: 3306
  •         connect_retry: 60
  •        master_log_file: mysql-bin.000006
  •      read_master_log_pos: 1364
  •         relay_log_file: mysql-relay-bin.000004
  •         relay_log_pos: 1569
  •     relay_master_log_file: mysql-bin.000006
  •        slave_io_running: connecting
  •       slave_sql_running: yes
  •      exec_master_log_pos: 1364
  •        relay_log_space: 2337
  •         master_ssl_key:
  •     seconds_behind_master: null
  • master_ssl_verify_server_cert: no
  •         last_io_errno: 2003
  •         last_io_error: error reconnecting to master 'repluser@192.168.197.128:3306' - retry-time: 60 retries: 1
  •         last_sql_errno: 0
  • (6)我们需要设置server 2为server 3的主库,因为server 2的数据比较新。此时如果采用以前的办法,需要计算之前主库的log_pos和当前要设置成主库的log_pos,很有可能出错。所以出现了一些高可用性的工具如mha,mmm等解决问题。

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

  • ?
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • mysql> change master to
  •   -> master_host='192.168.197.137',
  •   -> master_user='repluser',
  •   -> master_password='123456',
  •   -> master_port=,
  •   -> master_auto_position=;
  • query ok, rows affected, warnings (0.01 sec)
  • (7)此时查看server 3上的数据,可以发现,数据已经同步过来了;

    2 复制错误跳过

        上面的测试中,最终的结果是server 2是主节点,server 3是从节点,下面我们来验证复制错误跳过的办法。

    (1)首先我们在从节点上执行一个drop的语句,让两边的数据不一致,如下:

  • ?
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • mysql> show databases;
  • +--------------------+
  • | database      |
  • +--------------------+
  • | information_schema |
  • | dbas        |
  • | customer      |
  • | inc_db       |
  • | mysql       |
  • | performance_schema |
  • | sys        |
  • | testdb       |
  • | yeyz        |
  • | yyy        |
  • +--------------------+
  •  rows in set (. sec)
  •  
  • mysql> drop database yyy;
  • query ok, rows affected (. sec)
  •  
  • mysql> show databases;
  • +--------------------+
  • | database      |
  • +--------------------+
  • | information_schema |
  • | dbas        |
  • | customer      |
  • | inc_db       |
  • | mysql       |
  • | performance_schema |
  • | sys        |
  • | testdb       |
  • | yeyz        |
  • +--------------------+
  •  rows in set (. sec)
  • (2)然后我们在server 2上执行drop database yyy的操作,如下:

  • ?
  • 1
  • 2
  • mysql> drop database yyy;
  • query ok, 3 rows affected (0.02 sec)
  • (3)此时我们看到server 3上已经出现了主从不同步的错误警告,因为它上面并没有yyy的数据库(前一步已经删除),错误情况如下;

  • ?
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • mysql> show slave status\g
  • *************************** . row ***************************
  •         slave_io_state: waiting for master to send event
  •          master_host: 192.168.197.137
  •          master_user: repluser
  •          master_port:
  •         connect_retry:
  •        master_log_file: mysql-bin.
  •      read_master_log_pos:
  •         relay_log_file: mysql-relay-bin.
  •         relay_log_pos:
  •     relay_master_log_file: mysql-bin.
  •        slave_io_running: yes
  •       slave_sql_running: no
  •           last_errno:
  •           last_error: error 'can't drop database 'yyy'; database doesn't exist' on query. default database: 'yyy'. query: 'drop database yyy'
  •          skip_counter:
  •      exec_master_log_pos:
  •        relay_log_space:
  •         last_sql_error: error 'can't drop database 'yyy'; database doesn't exist' on query. default database: 'yyy'. query: 'drop database yyy'
  •  replicate_ignore_server_ids:
  •        master_server_id:
  •          master_uuid: bb874065-c485-e8-b52-c2934472e
  •        master_info_file: mysql.slave_master_info
  •       retrieved_gtid_set: bd0d--e8-afd6-c3e51db5828:-,
  • bb874065-c485-e8-b52-c2934472e:
  •       executed_gtid_set: db33b36-e51-f-a61d-c99756e90155:-,
  • bd0d--e8-afd6-c3e51db5828:-,
  • f5-c486-e8-adb7-c29bf2c97:
  •         auto_position:
  •      replicate_rewrite_db:
  •          channel_name:
  •       master_tls_version:
  •  row in set (0.00 sec)
  • (4)当我们使用传统的方法来跳过这个错误的时候,会提示出gtid模式下不被允许,如下:

  • ?
  • 1
  • 2
  • mysql> set global sql_slave_skip_counter=;
  • error (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
  • 那么这种方式下应该如何跳过这个错误呢?

    (5)因为我们是通过gtid来进行复制的,也需要跳过这个事务从而继续复制,这个事务可以到主上的binlog里面查看:因为不知道找哪个gtid上出错,所以也不知道如何跳过哪个gtid。但是我们可以在show slave status里的信息里找到在执行master里的pos:2012,也就是上述第(3)步第18行代码。现在我们拿着这个pos:2012去server 2的日志里面找,可以发现如下信息:

  • ?
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • # at 2012
  • #190305 20:59:07 server id 2 end_log_pos 2073 gtid  last_committed=9    sequence_number=10   rbr_only=no
  • set @@session.gtid_next= 'bb874065-c485-11e8-8b52-000c2934472e:1'/*!*/;
  • # at 2073
  • #190305 20:59:07 server id 2 end_log_pos 2158 query  thread_id=3   exec_time=0   error_code=0
  • set timestamp=/*!*/;
  • drop database yyy
  • /*!*/;
  • (6)我们可以看到gtid_next的值是

    ,然后我们通过下面的方法来重新恢复主从复制:

  • ?
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 标签:

    猜您喜欢