背景:
在某个夜黑风高的晚上,突然收到数据库服务器磁盘不够用的报警。
经排查核实, 发现是数据库的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线程:
同时,我们看一下从库当前的relay-log目录:
这时候,我在主库上执行kill,
杀死那个id为29645的binlog
dump线程。然后再观察从库的状态,发现从库自动重连了,而且重新起了一个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文件。 最后产生了那样的结果。
解决:
首先,我们得确认发生这种情况后的后果。
我在从库上查看复制状态, 发现从库已经远远落后于主库了:
如上,
光是执行的master_log已经差了几十个,这时候我们想到的可能是先关闭这个实例,
删除它的auto.cnf文件,然后再启动,这样不是就可以了吗?
—— 但是,因为堆积的relay-log已经上百万,而这些relay-log实际上还没有被执行呢!
数据库实例重新启动后, 会挨个去执行这些relay-log,
但是奈何实在太多,恐怕得太久的时间才能追上,得不偿失。
或许又会有别的思路, 比如重启更新UUID后,
重新change master到relay-log里面记录的从库执行到的二进制文件。
但是,因为时间略久, 对应的二进制文件早已经被主库给清掉了,全部转换成了从库那一大堆relay-log了。
所以只能重新做备份库了。