问题描述
本问题来自一位群友,他遇到的情况我简单归纳一下:
- 实例A是主库,B是延迟从库(设置了延迟7200秒)。
- 当A挂掉后(已无法连接,或无法启动),希望用B提升成主库。
- 但是在B上执行
change master to MASTER_DELAY=0
后,B上已经保存的7200秒的relay文件也会被清除掉,并尝试再次从A获取binlog,这样会造成7200秒的数据丢失,未能达成目的。
TA想问:在这样的场景下,还有办法让B库尽快跑完这7200秒延迟数据吗,或者正确的办法是什么呢?
方法3,正确理解MASTER_DELAY,一键搞定
前面铺垫了那么多,看起来想要让延迟从库快速恢复好像有点麻烦的样子。
事实上,只要正确理解,一键命令就搞定了。
当主库发生故障宕机后,binlog其实已经都复制到从库并写入成relay log了。当然了,为避免误操作,建议先备份relay log。
接下来的操作很重要,看准了,一定不要做错:
# 只关闭SQL_THREAD,而不是直接关闭整个SLAVE服务
[root@GreatSQL](none)> STOP SLAVE SQL_THREAD;# 修改MASTER_DELAY,使之不再延迟
[root@GreatSQL](none)> CHANGE MASTER TO MASTER_DELAY=0;# 再次启动SQL_THREAD
[root@GreatSQL](none)> START SLAVE SQL_THREAD;
主库虽然宕机了,但从库上只有IO_THREAD会报告连接错误,SQL_THREAD还是可以正常工作的。
上述操作的关键点在于,修改 MASTER_DELAY 时并没有先停掉 IO_THREAD,否则会清空所有的relay log,尝试去主库再次拉取。
再次启动 SQL_THREAD 之后,从库就会继续应用relay log,待到全部应用完毕后,完成必要的数据校验,即可提成成为新的主库,对外提供服务了。
看,真的挺简单的吧。
现在来验证下:完全停掉SLAVE服务后修改MASTER_DELAY值,再启动SLAVE服务,此时会清空重置relay log。
# 主库宕机后,查看SLAVE状态
[root@GreatSQL](none)> SHOW SLAVE STATUS\G
...
Master_Log_File: binlog.000017
Read_Master_Log_Pos: 471
Relay_Log_File: relay-bin.000002
Relay_Log_Pos: 321
Relay_Master_Log_File: binlog.000017
Slave_IO_Running: Connecting
Slave_SQL_Running: Yes
...
Exec_Master_Log_Pos: 196
...
Seconds_Behind_Master: 69
...
SQL_Delay: 7200
SQL_Remaining_Delay: 7132
Slave_SQL_Running_State: Waiting until MASTER_DELAY secondsafter master executed event
...# 查看relay log状态
[root@greatsql]# ls -la relay-bin.*
-rw-r----- 1 mysql mysql 213 Jun 13 15:11 relay-bin.000001
-rw-r----- 1 mysql mysql 596 Jun 13 15:11 relay-bin.000002
-rw-r----- 1 mysql mysql 58 Jun 13 15:11 relay-bin.index# 关闭SLAVE服务,修改MASTER_DELAY,再启动SLAVE服务
[root@GreatSQL](none)> STOP SLAVE; CHANGE MASTER TO MASTER_DELAY=0; START SLAVE;# 再次查看relay log,发现被清空重置了
[root@greatsql]# ls -la relay-bin.*
-rw-r----- 1 mysql mysql 156 Jun 13 15:18 relay-bin.000001
-rw-r----- 1 mysql mysql 29 Jun 13 15:18 relay-bin.index
所以,请记住了,当延迟从库要修改延迟设置时,只需重启SQL_THREAD,千万别图省事重启整个SLAVE服务,这样relay log就不会被清空重置了,也就能实现快速恢复并提升为主库。为以防万一,也请务必备份好relay log。
因为relay log是由 IO_THREAD 负责的,所以只要 IO_THREAD 不重启,就不会清空重置