搭建基于GTID的MySQL主从复制

版权声明:需要引用、发表的朋友请与本人联系 https://blog.csdn.net/pbrlovejava/article/details/88046025

一、为什么需要GTID

之前写过一篇文章介绍过基于日志点的MySQL的主从复制:https://blog.csdn.net/pbrlovejava/article/details/87002171#36SLAVE_89,
在使用的过程中发现有一些问题,最常见的问题在使用主主热备+主从复制+读写分离架构的过程中(读写分离可参考以前写的文章:https://blog.csdn.net/pbrlovejava/article/details/87886197
)会出现一种问题:

在这里插入图片描述

即Master1宕机后,若短时间无法恢复,此时的做法是停止Slave的IO线程,并且将Master2锁表只读,让其不要有新数据进来,然后需要更改Amoeba将Master2提升为主库,这些操作可以很快完成,但是接下来就遇到问题了:

我们需要去查看日志,判断Slave读取到Master1的哪些数据了,并且需要分析Master2日志,找出我们还需要同步的偏移量,这是个很复杂的过程,总是会存在数据的漏失。 那么应该如何解决这个问题呢?是否可以在故障切换时,无需在Slave中指定Master的同步位置,或者可以自动判断需要从哪里开始同步呢?

至此,为什么需要GTID的原因已经告诉大家了,GTID的出现很好地解决了主从切换时的日志定位问题,使我们无需再通过master_log_filemaster_log_pos去定位复制起点。

二、GTID是什么

2.1、GTID的组成

GTIDGlobal Transaction ID,全局事务ID,它是MySQL5.6版本出现的一种由特定标识组成的字符串,它长这个样子:

a7df186b-38de-11e9-9452-0242ac110007:1-42

GTID可以通过show master status查看,它由两部分组成,第一部分是MySQL服务器ID,可通过以下命令查看

mysql> show variables like 'server_uuid';
+---------------+--------------------------------------+
| Variable_name | Value                                |
+---------------+--------------------------------------+
| server_uuid   | a7df186b-38de-11e9-9452-0242ac110007 |
+---------------+--------------------------------------+
1 row in set (0.01 sec)

这个uuid是全球唯一的,即百年内不会过期和重复,所以可以确定一台唯一的MySQL服务器,一般将其存储在mysql数据目录的auto.cnf文件中。

而组成GTID的第二部分被称为事务ID,它随事务的产生而递增,即每条事务会对应一个事务ID,那么,GTID的性质显而易见:它能标识全球范围内任一台MySQL数据库中的任一事务。

2.2、基于GTID的主从复制原理

在这里插入图片描述

我个人理解,基于GTID的MySQL复制流程为:

1、Master写入记录前生成一个GTID
2、Master将GTID和数据一起写入二进制日志中
3、Master刷新日志数据到磁盘中
4、Slave读取Master的二进制日志中的GTID
5、Slave判断该GTID是否已经写入中继日志,如果写入了则说明该GTID代表的数据已经存在,跳过该条数据不将其重复录入到中继日志中
6、Slave继续往下读取Master二进制日志,直到读取到Slave中继日志中不存在的GTID即开始将其写入Slave中继日志,SQL线程启动,开始刷新数据到Slave磁盘中
7、复制过程结束

这样就可以避免Slave中漏写Master的数据或者重复写入。

三、开始配置

3.1、准备Docker的MySQL服务

这一步已经在前面的文章中讲过了,这里不再赘述:
https://blog.csdn.net/pbrlovejava/article/details/87002171#36SLAVE_89

3.2、三个重要参数

要使用GTID,一定要在主从库中都设置者三个参数:

  • gtid_mode=on
    这个参数用于开启gtid模式

  • enforce_gtid_consistency=on
    安全相关测试

  • log_slave_updates=on
    这个参数作用很大,它解决了双主一从架构中的从库数据与主库数据不一致问题,当Slave的主库为Master1时,Master2和Master1互为主主热备架构,Master2更新了数据之后,Master1也更新了数据,但是此时Master1的更新记录保存在中继日志中,二进制日志中并没有记录下来,所以Slave无法读取到更新,这就造成了更新丢失问题,而且最坑的是这个参数默认是关闭的,所以在这里我们需要将其开启。

3.3、主库配置

修改主库配置:

vi /etc/mysql/my.cnf

在这里插入图片描述

3.4、从库配置

在这里插入图片描述

3.5、在主库中创建用于主从复制的账号

mysql> grant replication slave,replication client on *.* to 'slave'@'%' identified by '123';
Query OK, 0 rows affected, 1 warning (0.01 sec)

mysql> flush privileges;
Query OK, 0 rows affected (0.00 sec)

四、开启主从复制

登陆从库,开启主从复制,此时已经不需要指定master_log_filemaster_log_pos了,而是通过参数master_auto_position=1去指定自动找到GTID进行复制。

mysql> change master to
    -> master_host='172.17.0.7',
    -> master_port=3306,
    -> master_user='slave',
    -> master_password='123',
    -> master_auto_position=1;
Query OK, 0 rows affected, 2 warnings (0.06 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: 172.17.0.7
                 Master_User: slave
                 Master_Port: 3306
               Connect_Retry: 60
             Master_Log_File: mysql5.000001
         Read_Master_Log_Pos: 47823
              Relay_Log_File: mysql5.000002
               Relay_Log_Pos: 48030
       Relay_Master_Log_File: mysql5.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: 47823
             Relay_Log_Space: 48228
             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: 201
                 Master_UUID: a7df186b-38de-11e9-9452-0242ac110007
            Master_Info_File: /var/lib/mysql/master.info
                   SQL_Delay: 0
         SQL_Remaining_Delay: NULL
     Slave_SQL_Running_State: Slave has read all relay log; waiting for more updates
          Master_Retry_Count: 86400
                 Master_Bind: 
     Last_IO_Error_Timestamp: 
    Last_SQL_Error_Timestamp: 
              Master_SSL_Crl: 
          Master_SSL_Crlpath: 
          Retrieved_Gtid_Set: a7df186b-38de-11e9-9452-0242ac110007:1-44
           Executed_Gtid_Set: a7df186b-38de-11e9-9452-0242ac110007:1-44,
dfdeb837-3b3a-11e9-a07f-0242ac110008:1-5
               Auto_Position: 1
        Replicate_Rewrite_DB: 
                Channel_Name: 
          Master_TLS_Version: 
1 row in set (0.00 sec)

至此,基于GTID的MySQL主从复制已经成功了,当然这只是基础的入门而已,还有许多线上问题需要去积累经验、勤于反思才能解决,还有许多东西可以深入地学习。

猜你喜欢

转载自blog.csdn.net/pbrlovejava/article/details/88046025