背景:

在某个夜黑风高的晚上,突然收到数据库服务器磁盘不够用的报警。

经排查核实, 发现是数据库的relay-log文件堆积十分严重,占用了大量的磁盘空间。

# cat
/data0/logs/mysql3901/yq110-relay-bin.index | wc
-l
1677608
//竟然有将近百万以上的relay-log文件

于是顺藤摸瓜,在查看错误日志的时候发现一些异常:

[Note]

Slave: received end packet from server due to dump thread being
killed on master. Dump threads are killed for example during master
shutdown, explicitly by a user, or when the master receives a
binlog send request from a duplicate server UUID
<195181fb-e5a3-11e5-a6f2-782bcb1ff318>
: Error

如上,显示master在发送binlog的时候发现了重复的UUID, 于是他一怒之下kill掉了那个dump

threads!

但是对于slave来说, 链接断开以后, 他会尝试重连, 一旦重连成功,

就会产生一个新的relay-log文件。 下面我们来验证一下:

首先我们看主库上存在一个从库的binlog

dump线程:

mysql relay_log mysql relay_log_pos越来越大_mysql relay log时间

同时,我们看一下从库当前的relay-log目录:

mysql relay_log mysql relay_log_pos越来越大_mysql relay log时间

这时候,我在主库上执行kill,

杀死那个id为29645的binlog

dump线程。然后再观察从库的状态,发现从库自动重连了,而且重新起了一个relay-log文件:

mysql relay_log mysql relay_log_pos越来越大_mysql relay log时间

然后我发现,原来我的这个从库和另外一个从库的UUID是一样的。 而在5.6中新添加了auto.cnf文件,

里面存放的就是每个数据库实例的UUID文件,当我们启动一个数据库实例的时候, 如果这个auto.cnf是存在的。

那么就用它作为我当前实例的UUID, 而如果不存在,则重新生成一个新的文件。具体可以参考官方文档:

https://dev.mysql.com/doc/refman/5.6/en/replication-options.html

然后,

我就怀疑应该是我在重做备份的时候,将从库的数据目录拉取过来以后。并没有删除它原来的auto.cnf文件。导致这两个实例的UUID冲突了。然后主库不断的kill它的binlog

dump线程, 它自己不断的新生成relay-log文件。 最后产生了那样的结果。

解决:

首先,我们得确认发生这种情况后的后果。

我在从库上查看复制状态, 发现从库已经远远落后于主库了:

mysql relay_log mysql relay_log_pos越来越大_mysql relay log时间

如上,

光是执行的master_log已经差了几十个,这时候我们想到的可能是先关闭这个实例,

删除它的auto.cnf文件,然后再启动,这样不是就可以了吗?

——   但是,因为堆积的relay-log已经上百万,而这些relay-log实际上还没有被执行呢!

数据库实例重新启动后, 会挨个去执行这些relay-log,

但是奈何实在太多,恐怕得太久的时间才能追上,得不偿失。

或许又会有别的思路, 比如重启更新UUID后,

重新change master到relay-log里面记录的从库执行到的二进制文件。

但是,因为时间略久, 对应的二进制文件早已经被主库给清掉了,全部转换成了从库那一大堆relay-log了。

所以只能重新做备份库了。