2019-07-15 MySQL GTID复制实践

1. MySQL GTID复制

1.1 GTID复制简介

GTID(global transaction identifier)是一个在主数据库上对每个已经提交到数据库的事务的唯一编号,这个标识不仅在主数据库上是唯一的,而且在整个复制架构中的所有数据库中都是唯一的。
一个GTID由一对坐标表示,用冒号(:)分隔:

GTID = source_id : transaction_id

在上面的定义中,每一个GTID均代表一个数据库的事务,等号右边的source_id表示执行事务的源服务器主库的uuid(也就是server_uuid),而transaction_id是一个从1开始的自增的序列号,表示在这个主库上执行的第n个事务。只要保证每台数据库的server_uuid全局唯一,以及每台数据库生成的transaction_id自身唯一,就能保证GTID的全局唯一性。
GTID是事务在数据库中提交时创建分配的唯一标识符,所有事务均与GTID一一映射。下面是一个GTID的具体形式:

2E11FA47-61CA-11E1-9E33-C70AA9429562:28

什么是server_uuid?
MySQL5.6用128位的server_uuid代替了原本32位的server_id的大部分功能。原因很简单,server_id依赖于my.cnf的手工配置,有可能会产生冲突,而自动产生128位uuid的算法可以保证所有的MySQL uuid都不会产生冲突。
在进行首次启动时,MySQL会自动生成一个server_uuid,并且保存到数据库目录下的auto.cnf文件里,这个文件目前存在的唯一目的就是保存server_uuid。在MySQL再次启动时其会读取auto.cnf文件,继续使用上次生成的server_uuid。

1.2 基于GTID复制技术的优缺点及工作原理

1. GTID复制的工作原理简介

GTID复制的工作原理具体如下:
1)当主数据库进行数据更新时,会在事务前产生GTID号,一同记录到binlog日志中。
2)从数据库端的I/O线程将变更的binlog数据,写入到本地的中继日志(relay log)中。
3)从数据库端的SQL线程从中继日志中获取GTID号,然后对比本地的Binlog查看其是否有记录。如果有记录,则说明该GTID的事务已经执行,此时从数据库会忽略。
4)如果没有记录,则从数据库就会从中继日志中获取数据并执行该GTID的事务,并记录到binlog中。
根据GTID号可以知道事务最初是在哪个数据库上提交的,GTID的存在方便了主从复制的宕机切换(failover)。

2. 传统主从复制的宕机切换
主从复制的宕机切换操作过程

由上图可以看到,在MySQL的GTID功能出现以前,主从复制的宕机切换操作过程。
若A服务器宕机,则需要将业务切换到B服务器上。同时,我们又需要使得C服务器与B服务器重新保持复制。这种情况的操作过程命令很简单,即在C服务器上执行“CHANGE MASTER TO MASTER_HOST='xxx',MASTER_LOG_FILE='xxx',MASTER_LOG_POS=nnn”。
问题在于同一个事务在每台数据库服务器上所在的binlog名字和位置点可能都不一样,那么怎样才能找到C当前同步的停止位置点呢,对应B的master_log_file和master_log_pos是什么的时候就变成了难题,这可能是官方推出GTID复制的原因。
其实,master.info文件记录了master_log_file和master_log_pos的位置,可以通过读master.info文件来找到真正的位置点,因此,在没有GTID功能以前,我们也是很快就能够搞定切换的。更进一步的,我们可以通过第三方工具,例如MHA等MySQL集群管理工具来实现主从复制主库宕机的切换以及从库和新主库复制的问题。
不过MySQL在5.6的GTID功能出现以后,对于上述问题的解决似乎变得更简单一些了。由于同一事务的GTID在所有节点上的值都是一致的,那么根据C服务器,当前停止点的GTID就能唯一定位到B上的GTID。而由于MASTER_AUTO_POSITION功能的出现,管理员不需要知道GTID的具体值,直接使用“CHANGE MASTER TO MASTER_HOST='xxx',”MASTER_AUTO_POSITION命令就可以直接完成宕机切换的工作了。

1.3 GTID的优缺点

1. GTID复制的优点
  • 根据GTID可以知道事务最初是在哪个数据库上提交的
  • GTID对于宕机切换有一定的方便性
2. GTID复制的缺点
  • GTID模式实例和非GTID模式实例之间是不能进行复制的,不能混用,要么都是GTID,要么都不是。
  • 在同一事物中更新事务表与非事务表将导致多个GTIDs分配给同一事务。官方指出,GTID包含如下三个限制,当enforce-gtid-consistency=ON时,以下三类SQL语句是不支持的:“CREATE TABLE ... SELECT statements” “CREATE TEMPORARY TABLE”和“DROP TEMPORARY TABLE statements inside transactions”
  • 同时更新传统事务表和非传统事务表时,有一个例外,如果所有非事务表都是临时表时,非事务的DML被允许在同一事务中或在同一语句中作为传统的DML。

1.4 MySQL GTID复制的应用及实践

1. 环境准备

可以直接使用MySQL半同步复制的环境,修改一下配置文件

2. GTID复制主从库配置文件对比说明
GTID复制主从库配置文件对比说明

说明:除了server-id之外,其他完全一致。配置完毕后,重启所有的MySQL服务。

3. GTID复制特殊配置参数说明
GTID复制特殊配置参数说明
4. 配置MySQL GTID主从复制

1)建立用于从库复制的帐号及对应权限:

mysql> grant replication slave on *.* to 'rep'@'192.168.150.%' identified by 'oldboy123';
Query OK, 0 rows affected (0.00 sec)
mysql> flush privileges;
Query OK, 0 rows affected (0.00 sec)

2)导出主库的数据:

mysqldump -A -B -x --set-gtid-purged=OFF|gzip > /opt/bak1_$(date +%F).sql.gz

3)将主库导出的MySQL数据迁移到从库:

[root@db01 ~]# scp -rp /opt/bak1_$(date +%F).sql.gz root@192.168.150.131:/opt

4)把从主库mysqldump导出的数据恢复到从库

[root@db02 ~]# cd /opt/
[root@db02 opt]# gzip -d bak1_$(date +%F).sql.gz
[root@db02 opt]# mysql < bak1_2019-07-15.sql

5)登录从库(131)配置复制参数

CHANGE MASTER TO
MASTER_HOST='192.168.150.130',
MASTER_PORT=3306,
MASTER_USER='rep',
MASTER_PASSWORD='oldboy123',
MASTER_AUTO_POSITION=1;    ---GTID复制的参数

6)启动从库同步开关并测试主从复制

mysql> start slave;
Query OK, 0 rows affected (0.00 sec)

mysql> show slave status\G
*************************** 1. row ***************************
               Slave_IO_State: Waiting for master to send event
                  Master_Host: 192.168.150.130
                  Master_User: rep
                  Master_Port: 3306
                Connect_Retry: 60
              Master_Log_File: db01-bin.000003
          Read_Master_Log_Pos: 658
               Relay_Log_File: db02-relay-bin.000002
                Relay_Log_Pos: 405
        Relay_Master_Log_File: db01-bin.000003
             Slave_IO_Running: Yes    ---为Yes就对了
            Slave_SQL_Running: Yes    ---为Yes就对了
---省略若干---
          Exec_Master_Log_Pos: 658
              Relay_Log_Space: 608
              Until_Condition: None
---省略若干---
                  Master_UUID: 61dca574-88f8-11e9-a004-000c299a6102
             Master_Info_File: /application/mysql-5.6.44/data/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
---省略若干---
            Executed_Gtid_Set: 61dca574-88f8-11e9-a004-000c299a6102:1-3,
653f1eca-88f8-11e9-a004-000c29b56ed1:1-129
                Auto_Position: 1
1 row in set (0.00 sec)

7)测试主从复制结果。在主库写入数据,然后观察从库的数据状况:

[root@db01 ~]# mysql -e "create database alex_python1;"

[root@db02 ~]# mysql -e "show databases like 'alex%';"
+------------------+
| Database (alex%) |
+------------------+
| alex_python      |
| alex_python1     |
+------------------+

根据测试可以判断,从库(192.168.150.131)和主库(192.168.150.130)是同步的,到此,GTID主从复制的基本实践就完成了。

5.5 GTID如何跳过事务冲突

这个功能主要是跳过事务,代替前面的传统复制错误时使用的“set global sql_slave_skip_counter = 1”。
由于在这里GTID必须是连续的,因此正常情况下,同一个服务器产生的GTID是不会存在孔雀的,所以不能简单地skip掉一个事务,只能通过注入空事务的方法替换掉一个实际操作的事务:

stop slave;
set gtid_next='xxx:N';
begin;commit;
set gtid_next='AUTOMAIC';
start slave;

这里的“xxx:N”就是你的slave sql thread报错的GTID号,也即你想要跳过的GTID号。
案例如下:模拟在从库中先建立数据库inca,在主库中继续创建inca,制造冲突。
从库建立数据库inca:

[root@db02 ~]# mysql -e "create database inca;"

主库建立数据库inca:

[root@db01 ~]# mysql -e "create database inca;"

从库:

[root@db02 ~]# mysql -e "show slave status\G"
*************************** 1. row ***************************
               Slave_IO_State: Waiting for master to send event
                  Master_Host: 192.168.150.130
                  Master_User: rep
                  Master_Port: 3306
                Connect_Retry: 60
              Master_Log_File: db01-bin.000003
          Read_Master_Log_Pos: 966
               Relay_Log_File: db02-relay-bin.000002
                Relay_Log_Pos: 571
        Relay_Master_Log_File: db01-bin.000003
             Slave_IO_Running: Yes
            Slave_SQL_Running: No
---省略若干---
               Last_SQL_Errno: 1007
               Last_SQL_Error: Error 'Can't create database 'inca'; database exists' on query. Default database: 'inca'. Query: 'create database inca'
  Replicate_Ignore_Server_Ids: 
             Master_Server_Id: 1
                  Master_UUID: 61dca574-88f8-11e9-a004-000c299a6102
             Master_Info_File: /application/mysql-5.6.44/data/master.info
                    SQL_Delay: 0
          SQL_Remaining_Delay: NULL
      Slave_SQL_Running_State: 
           Master_Retry_Count: 86400
                  Master_Bind: 
      Last_IO_Error_Timestamp: 
     Last_SQL_Error_Timestamp: 190715 03:43:48
               Master_SSL_Crl: 
           Master_SSL_Crlpath: 
           Retrieved_Gtid_Set: 61dca574-88f8-11e9-a004-000c299a6102:4-5
            Executed_Gtid_Set: 61dca574-88f8-11e9-a004-000c299a6102:1-4,
653f1eca-88f8-11e9-a004-000c29b56ed1:1-130
                Auto_Position: 1

故障解决实战:

mysql> stop slave;
Query OK, 0 rows affected (0.00 sec)
mysql> set gtid_next='61dca574-88f8-11e9-a004-000c299a6102:5';    ---这是上文“Retrieved_Gtid_Set”里的最大事务号
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.00 sec)
mysql> set gtid_next='AUTOMATIC';
Query OK, 0 rows affected (0.00 sec)
mysql> start slave;
Query OK, 0 rows affected (0.01 sec)
mysql> show slave status\G
*************************** 1. row ***************************
               Slave_IO_State: Waiting for master to send event
                  Master_Host: 192.168.150.130
                  Master_User: rep
                  Master_Port: 3306
                Connect_Retry: 60
              Master_Log_File: db01-bin.000003
          Read_Master_Log_Pos: 966
               Relay_Log_File: db02-relay-bin.000003
                Relay_Log_Pos: 445
        Relay_Master_Log_File: db01-bin.000003
             Slave_IO_Running: Yes    ---两个Yes说明修复成功
            Slave_SQL_Running: Yes
---省略若干---
                  Master_UUID: 61dca574-88f8-11e9-a004-000c299a6102
             Master_Info_File: /application/mysql-5.6.44/data/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: 61dca574-88f8-11e9-a004-000c299a6102:4-5
            Executed_Gtid_Set: 61dca574-88f8-11e9-a004-000c299a6102:1-5,
653f1eca-88f8-11e9-a004-000c29b56ed1:1-130
                Auto_Position: 1
1 row in set (0.00 sec)
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,056评论 5 474
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,842评论 2 378
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 148,938评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,296评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,292评论 5 363
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,413评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,824评论 3 393
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,493评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,686评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,502评论 2 318
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,553评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,281评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,820评论 3 305
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,873评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,109评论 1 258
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,699评论 2 348
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,257评论 2 341

推荐阅读更多精彩内容