在MySQL5.5和MySQL5.6中,处理主从复制断开的问题时,经常会用到sql_slave_skip_counter这个参数,一般是将这个参数设置为1,跳过当前的event即可。其实这样的操作是危险的。
我们知道,mysql中搭建主从复制后,主库的binlog是按照一个一个的组来分的,每个组的binlog以begin开始,以commit结束。为了描述方便,用下面的例子来进行描述:
主库上
begin;
event1;
event2;
event3;
commit;
从库上:
begin;
event1;
event2;-------该步骤失败,复制断开
event3;-------未进行
commit;------未进行
如上,当从库上在event2上复制断开的时候,我们会设置参数sql_slave_skip_counter来解决问题,这里有两种情况:
如果参数sql_slave_skip_counter=1,则此时这个组中的所有事件都会被算作不计数的时间,也就是说,这个1不是指一个event,而是指1个事务,只有遇到commit的时候,才会把这个参数的值改为0。
如果参数sql_slave_skip_counter大于1,那么这个组中的事件就会被认为是一个一个时间,处理一个事件,就会减去1,当减到1的时候,如果这个事务还没有结束,那么就跟第一种情况一样,如果事务已经结束了,但是参数的值还没有减为0,那么下一个事务组会继续重新处理。
对于commit语句,无论如何都会讲参数sql_slave_skip_counter的值减1,对于事务组内部一般的语句,如果sql_slave_skip_counter=1,则不会减1,如果sql_slave_skip_counter>1,则会减1,跟上面的描述保持一致。
当我们发现主从复制中断了,看上去中断的位置是出错的事件,但实际上那个只是执行错误的位置,由于事务会回滚,所以真正的binlog停止的位置是这个组开始的位置,此时设置sql_slave_skip_counter=1,则会跳过一个完整的事务。
根据上面的原理,我们不难看出,当我们设置sql_slave_skip_counter参数的值大于1的时候,这其实是一个危险操作,因为它可能跳过的事务个数是不确定的。当参数设置为1的时候,实际上跳过的是事务的所有event,用上面的例子看,就是跳过了event1~event3,而不仅仅是出错的event2。
还有一点需要注意,如果我们开启了gtid,则不可以使用这个参数来跳过事务了。在我们使用这个参数跳过事务的时候,要提前分析是不是可以直接跳过,跳过之后是否需要处理数据丢失的问题,最好在跳过之前,记录一下相关binlog的位置,恢复主从复制之后,看看从该binlog位置开始的第一个事务,是否需要手动补充数据,这样才能保证主从库数据的一致性。
最后在提醒一句,使用该参数跳过主从复制问题的时候,一般针对log等日志库进行跳过尚可,如果是数据强一致性的场景,还是要慎用sql_slave_skip_counter大于1的值。