mysql主从复制架构下,主库负责处理写请求,从库同步主库数据并处理读请求,是很多业务系统的常用数据库方案。但在实际运行过程中,由于网络延迟、写入逻辑不规范、复制模式选择不当等原因,很容易出现主从数据不一致甚至数据冲突的问题,需要针对性处理。

mysql主从复制中数据冲突的常见原因
数据冲突的产生通常和复制机制、业务操作、环境配置有关,常见原因主要有以下几类:
- 双向写入导致冲突:如果业务层同时向主库和从库写入数据,或者主从架构配置错误导致从库也可写,就会出现同一条数据被不同节点修改的情况,引发冲突。
- 复制延迟引发冲突:主库写入数据后,从库同步存在延迟,此时业务读取从库旧数据后基于旧数据做更新操作,再写回主库,就会出现数据覆盖冲突。
- 自增主键冲突:如果主从库的自增主键步长、起始值配置不合理,或者主从切换后新主库的自增ID和旧主库已同步到从库的ID重复,就会出现主键冲突。
- 非确定性函数导致冲突:主库执行包含UUID、NOW等函数的SQL时,从库重放该SQL如果得到不同的结果,就会出现数据不一致甚至冲突。
mysql主从复制数据冲突的解决方法
1. 规范写入逻辑避免冲突
首先要保证所有写请求都只发送到主库,从库仅承担读请求,避免双向写入。如果业务需要多节点写入,建议采用分库分表或者多主复制架构,而不是普通的主从复制架构。同时尽量避免在从库执行写操作,除非是专门的维护场景。
可以通过以下配置禁止从库写入,在从库的配置文件my.cnf中添加:
[mysqld] # 从库设置为只读,普通用户无法写入,超级用户仍可在维护时写入 read_only=1 # 如果希望超级用户也无法写入,可开启该配置,仅用于特殊场景 # super_read_only=1
2. 优化复制配置减少延迟
复制延迟是引发冲突的重要原因,可以通过优化复制配置降低延迟。首先选择合理的复制模式,如果是数据一致性要求高的场景,建议使用半同步复制,保证主库写入的事务至少同步到一个从库后再返回成功,减少数据丢失和冲突概率。
开启半同步复制的配置示例如下,主库配置:
-- 安装半同步复制插件 INSTALL PLUGIN rpl_semi_sync_master SONAME 'semisync_master.so'; -- 开启半同步复制 SET GLOBAL rpl_semi_sync_master_enabled = 1; -- 设置主库等待从库ACK的超时时间,单位毫秒 SET GLOBAL rpl_semi_sync_master_timeout = 10000;
从库配置:
-- 安装半同步复制插件 INSTALL PLUGIN rpl_semi_sync_slave SONAME 'semisync_slave.so'; -- 开启半同步复制 SET GLOBAL rpl_semi_sync_slave_enabled = 1; -- 重启从库IO线程使配置生效 STOP SLAVE IO_THREAD; START SLAVE IO_THREAD;
3. 处理自增主键冲突
自增主键冲突可以通过合理设置自增参数避免。如果是双主架构,需要设置不同的自增起始值和步长,比如主库A设置自增起始值为1,步长为2,主库B设置自增起始值为2,步长为2,这样两者的自增ID不会重复。普通主从架构下,从库的自增参数不需要额外设置,主库切换时需要注意新主库的自增ID要大于旧主库已分配的最大ID。
双主架构自增参数配置示例:
-- 主库A配置 [mysqld] auto_increment_increment=2 auto_increment_offset=1 -- 主库B配置 [mysqld] auto_increment_increment=2 auto_increment_offset=2
4. 冲突发生后的修复方法
如果已经出现数据冲突,首先需要停止从库的复制线程,避免冲突扩大。然后对比主从库的数据差异,定位冲突的具体数据行。如果是少量数据冲突,可以手动将主库的冲突数据同步到从库,或者将从库的错误数据修正后重新开启复制。
手动修复数据后重启从库复制的示例:
-- 停止从库复制 STOP SLAVE; -- 跳过冲突的事务,需要确认冲突事务的编号,以下为示例 SET GLOBAL sql_slave_skip_counter = 1; -- 重新开启复制 START SLAVE; -- 查看复制状态,确认是否恢复正常 SHOW SLAVE STATUSG
如果数据冲突范围较大,建议重新搭建从库,从主库导出全量数据恢复到从库,再重新开启主从复制,保证数据一致性。
冲突预防的最佳实践
除了上述解决方法,日常运维中还需要做好冲突预防。定期监控主从复制状态,通过SHOW SLAVE STATUSG命令查看复制延迟、错误日志,及时发现潜在问题。业务层尽量避免使用非确定性函数,如果必须使用,建议将函数的结果先计算为固定值再写入数据库。同时做好主从切换的预案,切换前确认新主库的数据完整性,避免切换后出现数据冲突。