//
线上的一次GTID搭建MySQL主从操作
//
先对环境做个介绍:
主库的IP是XX.XX.XXX.161
从库的IP是XX.XX.XXX.171
复制的模式是GTID模式
复制用户是repluser
端口是4308
关于GTID的概念,之前已经介绍过很多次了,这里不再赘述,有兴趣的可以看看文章分类一栏中关于GTID的介绍,我们只看看下面这三个参数的含义:
gtid_purged:这个是当前已经丢弃的gtid的值
gtid_executed:这个是当前已经执行过的gtid的值
gtid_nexe:下一个要执行的gtid的值
今天我们主要来看这个案例。我们的目的很明确,就是修改复制用户,首先在从库上查看复制用户:
mysql--dba_admin@127.0.0.1:(none) 10:27:26>>show slave status\G
*************************** 1. row ***************************
Slave_IO_State: Waiting for master to send event
Master_Host: XX.XX.XXX.161
Master_User: repluser
Master_Port: 4308
Connect_Retry: 60
Master_Log_File: mysqlbin.000003
Read_Master_Log_Pos: 113372207
Relay_Log_File: slave-relay-bin.000008
Relay_Log_Pos: 46431
Relay_Master_Log_File: mysqlbin.000003
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
可以看到,复制的用户是repluser,我们需要将它改为dba_repl,所做的操作如下:
1、首先我们执行stop slave命令,断开主从之间的复制关系。此时记录从库收到的gtid的值和已经执行的gtid的值。
Master_SSL_Crlpath:
Retrieved_Gtid_Set: d9f94d88-463a-11e9-b424-005056b72c2a:19-360195
Executed_Gtid_Set: 6f4936a0-463b-11e9-a324-005056b7ed6e:1-26,
d9f94d88-463a-11e9-b424-005056b72c2a:143504-360195
Auto_Position: 0
Replicate_Rewrite_DB:
Channel_Name:
Master_TLS_Version:
可以看到这里从库的execute的gtid的值有两个,分别是:
6f4936a0-463b-11e9-a324-005056b7ed6e:1-26,
d9f94d88-463a-11e9-b424-005056b72c2a:143504-360195
也就是说,从库执行过的事务的gtid有存在于两个服务器上,很明显,之前从库上面进行过一些操作,这里提醒大家,如果不想在从库上出现多个gtid,需要在从库上设置read_only的选项。
再来看看retrieved_gtid_set的值,这个值是从库上当前收到的gtid的值,是:
d9f94d88-463a-11e9-b424-005056b72c2a:19-360195
2、然后我们把从库的gtid_purged的值设置成为已经执行过的gtid_executed值,告诉从库,这些gtid的事务已经执行完了。也就是
d9f94d88-463a-11e9-b424-005056b72c2a:143504-360195
使用的操作过程如下:
mysql--dba_admin@127.0.0.1 >>reset slave all;
Query OK, 0 rows affected (0.00 sec)
mysql--dba_admin@127.0.0.1 >>set global gtid_purged='d9f94d88-463a-11e9-b424-005056b72c2a:143504-360195';
ERROR 1840 (HY000): @@GLOBAL.GTID_PURGED can only be set when @@GLOBAL.GTID_EXECUTED is empty.
可以看到,当我们直接进行修改的时候,提示我们需要将从库的gtid_executed的值置为空,才能进行重置,这里我们使用reset master的语句将gtid_executed置为空,如下:
mysql--dba_admin@127.0.0.1 >>reset master;
Query OK, 0 rows affected (0.02 sec)
mysql--dba_admin@127.0.0.1 >>set global gtid_purged='d9f94d88-463a-11e9-b424-005056b72c2a:143504-360195';
Query OK, 0 rows affected (0.00 sec)
可以看到,我们reset master之后,可以对gtid_purged进行设置了。
3、有了上一步的基础之后,从库已经了解了事务号在
143504-360195之间的事务已经被执行完了,所以从库在执行事务的时候会自动跳过这个区间的。此时我们开启主从复制:
mysql--dba_admin@127.0.0.1 >>change master to master_host='XX.XX.XXX.161',
-> master_user='dba_repl',
-> master_password='XXXXXXXX',
-> master_port=4308,
-> master_auto_position=1;
Query OK, 0 rows affected, 1 warning (0.01 sec)
mysql--dba_admin@127.0.0.1 >>start slave;
Query OK, 0 rows affected (0.00 sec)
查看复制关系,可以看到报了这样一个错误:
Relay_Master_Log_File: mysqlbin.000002
Slave_IO_Running: Yes
Slave_SQL_Running: No
Replicate_Do_DB:
Last_Error: Coordinator stopped because there were error(s)
in the worker(s). The most recent failure being: Worker 0
failed executing transaction 'd9f94d88-463a-11e9-b424-005056b72c2a:1'
at master log mysqlbin.000002, end_log_pos 734. See error log and/or
performance_schema.replication_applier_status_by_worker table for
more details about this failure or others, if any.
我们可以观察到IO线程是正常的,而SQL线程是错误的,报错是'd9f94d88-463a-11e9-b424-005056b72c2a:1'事务无法被从库顺利执行。
此时我们查看从库上的gtid相关的参数的值:
Master_SSL_Crlpath:
Retrieved_Gtid_Set: d9f94d88-463a-11e9-b424-005056b72c2a:1-143503:360196-360321
Executed_Gtid_Set: d9f94d88-463a-11e9-b424-005056b72c2a:143504-360195
Auto_Position: 1
Replicate_Rewrite_DB:
可以看到,从库收到的gtid的值变为了:
d9f94d88-463a-11e9-b424-005056b72c2a:
1-143503:360196-360321
而之前是:
d9f94d88-463a-11e9-b424-005056b72c2a:
19-360195
很明显,目前这个值是不对的,我们想要的是收到的gtid的值是从360195开始的事务id,但是从库却收到了编号为1的事务id,也就是说,多收到了gtid编号为1-143503的事务id,这是我们不想要的。
4、手动设置一下从库的gtid_next的值,让它强行从
d9f94d88-463a-11e9-b424-005056b72c2a:360196开始,看看效果:
mysql--dba_admin@127.0.0.1 >>set session gtid_next='d9f94d88-463a-11e9-b424-005056b72c2a:360196';
Query OK, 0 rows affected (0.00 sec)
mysql--dba_admin@127.0.0.1 >>start slave;
Query OK, 0 rows affected (0.01 sec)
mysql--dba_admin@127.0.0.1 >>show slave status\G
*************************** 1. row ***************************
Slave_IO_State: Waiting for master to send event
Master_Host: XX.XX.XXX.161
Master_User: dba_repl
Master_Port: 4308
Connect_Retry: 60
Master_Log_File: mysqlbin.000003
Read_Master_Log_Pos: 113446772
Relay_Log_File: slave-relay-bin.000002
Relay_Log_Pos: 365
Relay_Master_Log_File: mysqlbin.000002
Slave_IO_Running: Yes
Slave_SQL_Running: No
可以看到,这样是不可取的,并没有解决问题。
5、查看从库上的表mysql.gtid_executed,可以看到如下的结果:
mysql--dba_admin@127.0.0.1 >>select *from mysql.gtid_executed;
+--------------------------------------+----------------+--------------+
| source_uuid | interval_start | interval_end |
+--------------------------------------+----------------+--------------+
| d9f94d88-463a-11e9-b424-005056b72c2a | 143504 | 360195 |
+--------------------------------------+----------------+--------------+
1 row in set (0.00 sec)
从这里可以看出,我们只是告诉了从库,143504~360195之间的事务从库已经处理过了,从库并不知道143504之前的事务是否已经执行过,所以将之前的事务也给同步过来了,如果我们将gtid_purged的值改为1-360195,告诉从库1~360195的事务都已经执行完了,这个时候我们看看会有什么效果。
mysql--dba_admin@127.0.0.1 >>set global gtid_purged='d9f94d88-463a-11e9-b424-005056b72c2a:1-360195';
Query OK, 0 rows affected (0.00 sec)
mysql--dba_admin@127.0.0.1 >>change master to master_host='XX.XXX.XXX.161',
-> master_user='dba_repl',
-> master_password='XXXXXXX',
-> master_port=4308,
-> master_auto_position=1;
Query OK, 0 rows affected, 1 warning (0.02 sec)
mysql--dba_admin@127.0.0.1 >>start slave;show slave status\G
Query OK, 0 rows affected (0.01 sec)
*************************** 1. row ***************************
Slave_IO_State: Checking master version
Master_Host: XX.XX.XXX.161
Master_User: dba_repl
Master_Port: 4308
Connect_Retry: 60
Master_Log_File:
Read_Master_Log_Pos: 4
Relay_Log_File: slave-relay-bin.000001
Relay_Log_Pos: 4
Relay_Master_Log_File:
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
可以看到,主从复制关系已经搭建好了,也就是说,从库需要知道当前已经执行过那些gtid的值,然后将1开始,到当前编号的值都设置为gtid_purged,然后再去搭建主从复制关系,这样的话,从库才可以从正确的gtid开始,去重新复制主库上的操作。
总结一下:
在使用GTID搭建主从复制的时候,需要给从库设置正确的gtid_purged的值,然后使用auto_position=1的方法去搭建主从复制。
如果你是使用备份的方法搭建,需要在备份文件中找到备份的那个时间点的gtid_purged值。
如果你是将已有的复制关系更改为gtid的方式,则你需要stop slave之后,抓到当前已经执行完成的gtid的值,作为从库的gtid_purged值,然后再开启复制关系。
还有一种情况,如果你使用gtid无法第一时间搭建成功主从复制,也就是没有出现双yes的情况,而这个时候从库已经落后主库很多了,那么可以考虑先用偏移量的方式先保证从库追上主库,然后再切换到gtid。