mysql主从复制中的同步方式与数据一致性问题

来源:这里教程网 时间:2026-02-28 20:49:38 作者:

MySQL 主从复制默认是异步复制,主库不等从库确认就提交

这是绝大多数 MySQL 主从部署的默认行为:主库执行

COMMIT
后立刻返回成功,binlog 事件由后台线程异步发送给从库。这意味着网络延迟、从库繁忙或宕机时,主库完全感知不到——
INSERT
返回了,但数据可能还没到从库,甚至永远丢失。

常见错误现象包括:

应用写完立即查从库,查不到刚插入的记录(
SELECT
返回空)
主库故障切换后,部分最近事务在从库上缺失,导致数据回退 监控显示
Seconds_Behind_Master
持续增长,但主库无任何报错

这不是配置错误,而是异步机制本身的特性。想缓解,只能靠降低写入压力、优化从库 SQL 线程性能,或改用半同步。

半同步复制(semi-sync)能强制主库等待至少一个从库应答

启用

rpl_semi_sync_master_enabled=ON
rpl_semi_sync_slave_enabled=ON
后,主库在提交事务前,会等待至少一个已启用半同步的从库返回
ACK
。超时(默认
rpl_semi_sync_master_timeout=10000
,单位微秒)则自动降级为异步,避免阻塞业务。

关键点:

不是强一致性:仍允许主库在未收到 ACK 时降级提交,只是“尽力而为” 只保证至少一个从库落盘(
relay log
写入并刷盘),不保证已执行(
Exec_Master_Log_Pos
不一定推进)
必须安装插件:
INSTALL PLUGIN rpl_semi_sync_master SONAME 'semisync_master.so'
(Linux)
5.7+ 默认不带插件,8.0+ 需确认插件路径和版本兼容性
mysql> SHOW VARIABLES LIKE 'rpl_semi_sync%';
+-------------------------------------------+------------+
| Variable_name                             | Value      |
+-------------------------------------------+------------+
| rpl_semi_sync_master_enabled              | ON         |
| rpl_semi_sync_master_timeout              | 10000000   |
| rpl_semi_sync_master_trace_level          | 32         |
+-------------------------------------------+------------+

GTID + 基于位置的复制切换容易引发数据不一致

当主库故障、需手动提升某从库为主时,若未严格按

gtid_executed
对齐,或误用
CHANGE MASTER TO ... MASTER_LOG_FILE
混用 GTID 和 file-position 模式,会导致复制中断或跳过事务。

典型踩坑场景:

从库开启
gtid_mode=ON
,但主库是
OFF
,强行配置复制会报错
ERROR 1777 (HY000)
执行
RESET SLAVE ALL
后忘记重置
gtid_purged
,新主库的
gtid_executed
缺失旧事务,从库重连后重复执行或跳过
使用
mysqlbinlog --base64-output=DECODE-ROWS -v
查看 binlog 时忽略
SET @@SESSION.GTID_NEXT
,误判事务边界

安全切换口诀:先查

SELECT @@global.gtid_executed;
,再在目标新主库执行
SET GLOBAL gtid_purged = '...';
(仅当为空时),最后让其他从库指向它并启用 GTID 自动定位。

从库延迟大时,读请求路由必须有 fallback 或超时控制

没有任何中间件能自动判断“这条 SELECT 是否涉及刚写入的数据”。如果应用层盲目把读请求发给延迟 30 秒的从库,结果就是脏读或不可见读——这不是 MySQL 的 bug,是架构设计责任。

不要依赖
SHOW SLAVE STATUS
Seconds_Behind_Master
做实时判断:该值可能为 0 但实际 SQL 线程卡在锁等待
SELECT MASTER_POS_WAIT('mysql-bin.000001', 123456789, 2)
在主库上阻塞等待从库追上指定位置,适合关键操作后同步等待(但别在高并发接口里用)
真正可控的方式是:写后生成唯一 token(如订单号),读时带上 token 并强制走主库;或用 ProxySQL / MyCat 的
delay_threshold
自动切主

最常被忽略的一点:即使启用了半同步,只要应用没做写后读一致性保障,从库延迟带来的数据不可见问题依然存在——复制机制管不到应用怎么读。

相关推荐