mysql主从复制默认异步,主库提交不等待从库确认,导致数据可能丢失或读不到;半同步可缓解但非强一致;gtid切换需严格对齐;读请求须规避延迟从库。

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,单位微秒)则自动降级为异步,避免阻塞业务。
关键点:
采用 php+mysql 数据库方式运行的强大网上商店系统,执行效率高速度快,支持多语言,模板和代码分离,轻松创建属于自己的个性化用户界面 v3.5更新: 1).进一步静态化了活动商品. 2).提供了一些重要UFT-8转换文件 3).修复了除了网银在线支付其它支付显示错误的问题. 4).修改了LOGO广告管理,增加LOGO链接后主页LOGO路径错误的问题 5).修改了公告无法发布的问题,可能是打压
- 不是强一致性:仍允许主库在未收到 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自动切主
最常被忽略的一点:即使启用了半同步,只要应用没做写后读一致性保障,从库延迟带来的数据不可见问题依然存在——复制机制管不到应用怎么读。









