binlog2sql/example/FixOldMasterExtraData.md

3.1 KiB
Raw Blame History

MySQL主从切换后如何进行数据修复

目前的MySQL高可用方案多是基于replication实现。MySQL replication默认是异步复制它有个重要缺陷主从延迟。当出现主从延迟时如果master出现宕机且无法将全部数据发送至slave则slave将丢失这部分数据。半同步复制和同步复制能避免主从延迟发生但会使得性能大大下降以至于诸多采用mysql存储的高性能系统仍旧采用异步复制。本文对主从切换后的数据不一致提供了一种新的解决办法。

主从切换后的状态

如下图所示切换完成后old master(10.1.1.1:3306)有一部分binlog(unreplicated binlog)未同步到new master(10.1.1.2:3306)new master已经有新数据进入。此时主从数据已经不一致。

常见办法

将old master指向new master开启同步。执行命令如下

> CHANGE MASTER TO MASTER_HOST='10.1.1.2', MASTER_PORT=3306,  MASTER_USER='xxx', MASTER_PASSWORD=xxx;
> CHANGE MASTER TO master_log_file='mysql-bin.000001',master_log_pos= 2448; 
> start slave;

此时一般会报错duplicate entry for key 'primary'。DBA们往往会选择以下几种方式来处理

  1. 粗暴跳过所有错误,直到复制不再报错。

    缺点:主从数据不一致,留下安全隐患。

  2. 根据报错信息逐次修old master数据。如报duplicate entry for key 'primary' for table a where id=12345, 则将old master 表a id=12345的数据删除再继续开启同步。

    缺点手工修复起来繁琐unreplicated binlog部分事务丢失如果unreplicated binlog较多的话主从数据很大概率还是会不一致。

  3. 将old master回滚至mysql-bin.00040 120再开启同步。同步正常。

    缺点unreplicated binlog丢失。

新办法

步骤

  1. 提取old master未同步的数据并对其中的insert语句去除主键为了防止步骤3中出现主键冲突
  2. 将old master回滚至mysql-bin.00040 120开启同步。同步正常
  3. 在new master重新导入改造后的sql

我们使用了纯Python开发的工具binlog2sql来操作,执行命令如下

$ python binlog2sql.py --no-primary-key -h10.1.1.1 -P3306 -uadmin -p'admin' --start-file='mysql-bin.000040' --start-pos=125466 --end-file='mysql-bin.000041' > oldMaster.sql

$ python binlog2sql.py --flashback -h10.1.1.1 -P3306 -uadmin -p'admin' --start-file='mysql-bin.mysql-bin.000040' --start-pos=125466 --end-file='mysql-bin.000041' | mysql -h10.1.1.1 -P3306 -uadmin -p'admin'

$ mysql -h10.1.1.2 -P3306 -uadmin -p'admin' < oldMaster.sql

优点

数据丢失最少,操作简单快捷。

限制

如果表的主键id是有业务含义的则务必与业务方确认可行后再操作。

###参考资料 [1] 易固武, MySQL数据库的高可用性分析

[2] danfengcao, binlog2sql: Parse MySQL binlog to SQL you want