Archive for 十月 2010

主备备的两个备机转为双master时出现的诡异slave lag问题

有三台MySQL服务器,a,b和c,复制关系为 a -> b -> c。a,b,c的server_id分别为1,2,3
因为需要切换为 a b <-> c,也就是说,a单独出来,b和c作为双master结构时。
这种切换会经常出现在需要搭建备机把数据备份出来,然后把a独立出来的case中。

昨天,我就做了这样的切换,结果发现出现莫名奇妙的slave lag。
Seconds_Behind_Master一下子为0,一下子变成几千秒。
使用mysqlbinlog查看,binlog日志里面也有很多时间在几小时以前的event数据。
为了验证复制是否正常,我特别测试了一下,在b建一个表,并插入时间数据,到c上一看,表已经复制过来了,时间数据也是正确。
询问了一下同事,他说应该是MySQL的bug,在这种切换的情况下很容易触发这个bug,可以采用stop slave;change master; start slave;的方法来修复。但是实际的数据其实完全没有影响,复制还是正常的。

于是我按照这个办法:
stop slave io_thread;
stop slave;
show slave status\G
(这里先停io_thread是为了SQL thread和IO thread都执行到了同一个位置,change master 的时候没有风险)
stop slave;change master to … ; start slave;
(change master到show slave status的Master_Log_File:和Exec_Master_Log_Pos:位置,也就是说,其实根本没有改变复制的位置)

结果slave lag依然故我。这个问题就比较郁闷了。时间已经过了午夜,脑袋也转不动了,想过不管它了,反正复制没有问题。但是问题没有解决总觉得什么东西卡在喉咙一样。各种资料,各种变量都参考了一遍,最后,基本不太意识的输入:
show master logs;
show binlog events in ‘mysql-bin.000680’ from 34385301;
想看看最新产生的event,结果就发现不对的地方了。
这个最新产生的event有很多,并且server_id是1,1是a的server_id啊,应用访问的是b啊,怎么会在b上面产生a的server_id列,MySQL哪里出问题了?

仔细一想,明白了,事情是这样的:
a -> b -> c,a的event1(server_id为1)复制到b,也会复制到c,这个是正常的。
然后搭建c -> b的复制关系时,b需要断开a的连接,切换主库到c,在 change master 的位置在event1出现之前,那么event1肯定会被重新复制到b去,event1的server_id是1,那么b判断,这个event1不是我提交的,需要在本地执行,并且把它记录到了自己的binlog中;
由于b和c是双master结构,event1又复制到了c,c同样判断它不是我提交的,那么我需要在本地执行,并且记录到本地binlog中。
这样event1就在b和c之间循环往复,时间保持不变,MySQL的slave lag也就一下子是0,一下子是几千秒了。

这里,还需要说明一点,在环型复制里面,event之所以能够在环内只循环一次,而不是重复做,是因为提交的那个节点会发现这个event的server_id是自己的server_id,也就是说是自己提交的。那么,它就不会把这个event再应用一次,自然也不会记录到binlog。这个循环就结束了。除非你闲着没事做,设置了replicate-same-server-id参数。

那么解决问题怎么办列,很简单,把没有应用访问的c的server_id设置成a的server_id:
set global server_id=1;
看看时间差不多了,server_id为1的event都被干掉以后:
set global server_id=3;
然后再设置回来。
还好,MySQL 5.0和5.1的server_id都是动态的。

may your success.