之前写过一篇文章介绍过基于日志点的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_file
和master_log_pos
去定位复制起点。
GTID
即Global 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数据库中的任一事务。
我个人理解,基于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的数据或者重复写入。
这一步已经在前面的文章中讲过了,这里不再赘述:
https://blog.csdn.net/pbrlovejava/article/details/87002171#36SLAVE_89
要使用GTID,一定要在主从库中都设置者三个参数:
gtid_mode=on
这个参数用于开启gtid模式
enforce_gtid_consistency=on
安全相关测试
log_slave_updates=on
这个参数作用很大,它解决了双主一从架构中的从库数据与主库数据不一致问题,当Slave的主库为Master1时,Master2和Master1互为主主热备架构,Master2更新了数据之后,Master1也更新了数据,但是此时Master1的更新记录保存在中继日志中,二进制日志中并没有记录下来,所以Slave无法读取到更新,这就造成了更新丢失问题,而且最坑的是这个参数默认是关闭的,所以在这里我们需要将其开启。
修改主库配置:
vi /etc/mysql/my.cnf
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_file
和master_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主从复制已经成功了,当然这只是基础的入门而已,还有许多线上问题需要去积累经验、勤于反思才能解决,还有许多东西可以深入地学习。