
前言
上次讲了主从原理:Keyring 搭建主从
这次讲一个容易被忽略的 Change master
细节吧。
先讲现象:如果主从存在延迟,这时执行 stop slave
+ change master
将清空 relay log 。存在数据不一致的风险。
开始测试,后面教怎么避免。
TEST
stop slave
有一主两从 3 台主机 30 是主
192.168.58.30(192.168.58.30:3306) (current master)
+--192.168.58.40(192.168.58.40:3306)
+--192.168.58.50(192.168.58.50:3306)
先测试 slave 1
root@localhost [(none)] 00:22:55 > show slave status\G
*************************** 1. row ***************************
Slave_IO_State: Waiting for source to send event
Master_Host: 192.168.58.30
Master_User: replica
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: mysql-bin.000002
Read_Master_Log_Pos: 9288
Relay_Log_File: mysql-relay.000005
Relay_Log_Pos: 9504
Relay_Master_Log_File: mysql-bin.000002
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: 9288
Relay_Log_Space: 9966
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: 30
Master_UUID: 541e12fa-d5f5-11ed-8994-000c29c34822
Master_Info_File: mysql.slave_master_info
SQL_Delay: 0
SQL_Remaining_Delay: NULL
Slave_SQL_Running_State: Replica 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: 541e12fa-d5f5-11ed-8994-000c29c34822:1-79
Executed_Gtid_Set: 541e12fa-d5f5-11ed-8994-000c29c34822:1-79
Auto_Position: 1
Replicate_Rewrite_DB:
Channel_Name:
Master_TLS_Version:
Master_public_key_path:
Get_master_public_key: 1
Network_Namespace:
1 row in set, 1 warning (0.00 sec)
看几个关键的指标就可以了:
Master_Host: 192.168.58.30Master_Log_File: mysql-bin.000002Read_Master_Log_Pos: 9288Relay_Log_File: mysql-relay.000005Relay_Log_Pos: 9504
先执行一下常规 stop slave
和 change master
stop slave;
change master to Master_Host='192.168.58.30';
start slave;
再看一下关键指标
root@localhost [(none)] 00:35:00 > show slave status\G
*************************** 1. row ***************************
Slave_IO_State: Waiting for source to send event
Master_Host: 192.168.58.30
······
Master_Log_File: mysql-bin.000002
Read_Master_Log_Pos: 9288
Relay_Log_File: mysql-relay.000002
Relay_Log_Pos: 420
Relay_Master_Log_File: mysql-bin.000002
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
······
Exec_Master_Log_Pos: 9288
······
1 row in set, 1 warning (0.01 sec)
Master_Log_File: mysql-bin.000002
和 Read_Master_Log_Pos: 9288
GTID 自动定位自动获取了源的 binlog
Relay_Log_File: mysql-relay.000002
和 Relay_Log_Pos: 420
relay log 与刚才不同,为什么?因为这已经是被清除过一次之后的重置后的 relay log,与动漫里面经常有的占领躯壳的灵魂一个效果,已经不是刚才的 relay log了,相当于这些数据都丢了。
stop slave io_thread
先看 relay log 文件有几个
[root@slave2 mysql_8_3306]# ll *relay*
-rw-r-----. 1 mysql mysql 16209 1月 22 00:47 mysql-relay.000003
-rw-r-----. 1 mysql mysql 9504 1月 22 00:47 mysql-relay.000004
-rw-r-----. 1 mysql mysql 76 1月 22 00:47 mysql-relay.index
再用另一台 slave 测试 stop slave io_thread;
和 stop slve sql_thread;
root@localhost [(none)] 00:42:07 > show slave status\G
*************************** 1. row ***************************
Slave_IO_State: Waiting for source to send event
Master_Host: 192.168.58.30
······
Master_Log_File: mysql-bin.000002
Read_Master_Log_Pos: 9288
Relay_Log_File: mysql-relay.000004
Relay_Log_Pos: 9504
Relay_Master_Log_File: mysql-bin.000002
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
······
Exec_Master_Log_Pos: 9288
Relay_Log_Space: 25713
······
1 row in set, 1 warning (0.00 sec)
这次只 stop 掉 iothread
stop slave io_thread;
change master to Master_Host='192.168.58.30';
start slave io_thread;
查看:
root@localhost [(none)] 00:43:46 > show slave status\G
*************************** 1. row ***************************
Slave_IO_State: Waiting for source to send event
Master_Host: 192.168.58.30
······
Master_Log_File: mysql-bin.000002
Read_Master_Log_Pos: 9288
Relay_Log_File: mysql-relay.000005
Relay_Log_Pos: 460
Relay_Master_Log_File: mysql-bin.000002
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
······
Exec_Master_Log_Pos: 9288
Relay_Log_Space: 10013
······
1 row in set, 1 warning (0.00 sec)
可以看到 Relay_Log_File: mysql-relay.000005
和 Relay_Log_Pos: 460
都变了,切了一个 log ,log 数字加了 1。
[root@slave2 mysql_8_3306]# ll *relay*
-rw-r-----. 1 mysql mysql 9553 1月 22 00:49 mysql-relay.000004
-rw-r-----. 1 mysql mysql 460 1月 22 00:49 mysql-relay.000005
-rw-r-----. 1 mysql mysql 76 1月 22 00:49 mysql-relay.index
查看文件数发现,已经被读取的 mysql-relay.000003
被清除了。
因为 mysql-relay.000003
是已经被重放过的,当 relay_log_purge
为 ON 时,重新 change master 时发现 mysql-relay.000003
是已经读取过的不再需要时就自动清除。
root@localhost [(none)] 00:52:25 > show variables like 'relay_log_purge';
+-----------------+-------+
| Variable_name | Value |
+-----------------+-------+
| relay_log_purge | ON |
+-----------------+-------+
1 row in set (0.01 sec)
我们先关闭它测试一下
set global relay_log_purge=OFF;
stop slave io_thread;
change master to Master_Host='192.168.58.30';
start slave io_thread;
查看
root@localhost [(none)] 00:52:49 > show slave status\G
*************************** 1. row ***************************
Slave_IO_State: Waiting for source to send event
Master_Host: 192.168.58.30
······
Master_Log_File: mysql-bin.000002
Read_Master_Log_Pos: 9288
Relay_Log_File: mysql-relay.000005
Relay_Log_Pos: 460
Relay_Master_Log_File: mysql-bin.000002
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
······
Exec_Master_Log_Pos: 9288
Relay_Log_Space: 26222
······
1 row in set, 1 warning (0.01 sec)
这些指标都没变化,但是 mysql-relay.000003
不再被清除:
[root@slave2 mysql_8_3306]# ll *relay*
-rw-r-----. 1 mysql mysql 16209 1月 22 00:51 mysql-relay.000003
-rw-r-----. 1 mysql mysql 9553 1月 22 00:52 mysql-relay.000004
-rw-r-----. 1 mysql mysql 460 1月 22 00:52 mysql-relay.000005
-rw-r-----. 1 mysql mysql 114 1月 22 00:52 mysql-relay.index
这里主要告诉你们清除了已经执行的是正常的。
stop sql_thread
只关 sql 线程可以操作的比较有限我这里就测一个:
stop slave sql_thread;
change master to SOURCE_DELAY=660;
start slave sql_thread;
同样没变:
Master_Log_File: mysql-bin.000002
Read_Master_Log_Pos: 9288
Relay_Log_File: mysql-relay.000005
Relay_Log_Pos: 460
Relay_Master_Log_File: mysql-bin.000002
但是执行 stop slave
就没了
stop slave;
change master to SOURCE_DELAY=660;
start slave;
Master_Log_File: mysql-bin.000002
Read_Master_Log_Pos: 9288
Relay_Log_File: mysql-relay.000002
Relay_Log_Pos: 420
Relay_Master_Log_File: mysql-bin.000002
且不受 relay_log_purge
控制,机制是这样的。
root@localhost [(none)] 01:07:06 > show variables like 'relay_log_purge';
+-----------------+-------+
| Variable_name | Value |
+-----------------+-------+
| relay_log_purge | OFF |
+-----------------+-------+
1 row in set (0.01 sec)
[root@slave2 mysql_8_3306]# ll *relay*
-rw-r-----. 1 mysql mysql 206 1月 22 01:04 mysql-relay.000001
-rw-r-----. 1 mysql mysql 420 1月 22 01:04 mysql-relay.000002
-rw-r-----. 1 mysql mysql 76 1月 22 01:04 mysql-relay.index
原理
如果指定 stop slave
+ relay
的文件位置或 pos 也不会清空,测试不再赘述。
*官网内容:
当复制 SQL 线程停止时,可以在正在运行的副本上执行使用
RELAY_LOG_FILE
、RELAY_LOG_POS
或两者的 CHANGE MASTER TO 语句。如果复制 SQL(应用程序)线程和复制 I/O(接收器)线程中至少有一个正在运行,则会保留中继日志。如果两个线程都停止,则除非指定了RELAY_LOG_FILE
或RELAY_LOG_POS
中的至少一个,否则所有中继日志文件都将被删除。
https://dev.mysql.com/doc/refman/8.0/en/change-master-to.html
”
Change master 时会清空历史 relay log 未重放日志的条件:
执行 stop slavechange master 时未指定 RELAY_LOG_FILE
或RELAY_LOG_POS
清理已重放日志受 relay_log_purge
控制。
结论
这个时候就有一个疑问了:所以,生产我们该怎么操作?
执行 stop slave io_thread;确认 Exec_Master_Log_Pos
和Read_Master_Log_Pos
一致stop slave sql_thread;
,或者有些只需要停 IO 即可就不需要这一步了。自行判断是否关闭 relay_log_purgechanage master
往期回顾
MySQL 插入生僻字/终端无法显示生僻字问题 基于 BLOB/TEXT 列上创建索引失败引起的思考 MySQL Resource Group - 使用资源组限制 SQL 使用的 CPU 数 更改账户身份验证插件注意事项 主从切换后导致 Event 停滞 and 主从故障 - Event 导致主从停滞的案例 INSERT 加什么锁 - 聊聊 INSERT 的加锁情况 MySQL 临时表空间 - 临时表空间(Temporary Tablespaces 及相关的变量 MySQL/PG 数据脱敏 - data_masking 插件和 postgresql_anonymizer 扩展初体验 MySQL/PG 对事务 DDL 的支持程度 - 从隐式提交聊到DDL事务 ONLINE DDL 收尾篇|如何有效实现 ONLINE - 关于 ONLINE DDL 的最佳实践 MySQL/PG 索引对于排序规则的依赖性 - 排序规则与索引的相关性问题,涉及到索引是否会失效 如何正确杀会话, KILL processlist_id/KILL QUERY? - 你知道如何正确杀掉活跃会话吗?
感谢阅读!关注我获取更多精彩内容。




