MySQL事务与主从复制深度耦合:事务保证单机ACID,复制负责跨节点同步;binlog写入时机、sync_binlog与innodb_flush_log_at_trx_commit配置、半同步复制及读写分离策略共同决定数据一致性。

MySQL 事务和主从复制不是一回事,但它们在数据一致性上深度耦合:事务保证单机上的 ACID,而主从复制负责跨节点的数据同步;一旦事务提交后没被正确复制到从库,就会出现「主库有、从库无」的一致性断裂。
事务提交后,binlog 写入时机决定复制起点
MySQL 默认使用 binlog_format = ROW(推荐),事务的变更内容只有在 commit 成功后,才会被写入 binlog。这意味着:
- 未提交的事务不会进入 binlog,从库根本看不到——这是正确的,避免传播脏数据
- 但如果主库 crash 在 commit 成功但 binlog 还没刷盘时,事务可能丢失(主库回滚,但从库已收到部分事件),造成主从不一致
- 关键配置:
sync_binlog = 1(每次事务都 fsync 到磁盘)+innodb_flush_log_at_trx_commit = 1,才能确保事务和 binlog 的原子性落盘
主从延迟导致「读到旧数据」不是事务问题,而是复制机制限制
即使所有事务都严格 ACID,主从之间仍存在天然延迟。常见现象:
- 用户刚下单(主库 insert 成功),立刻刷新订单页却查不到——因为从库还没重放完这条 relay-log
- 这不是事务失败,而是
SELECT被路由到了 lagging 的从库 - 解决思路不是改事务,而是业务层规避:强一致性读走主库(如用
SELECT ... FOR UPDATE或显式指定 master connection);或用 GTID +SELECT MASTER_POS_WAIT()等待同步到位
半同步复制(semi-sync)是事务与复制对齐的关键补丁
异步复制下,事务在主库 commit 后立即返回客户端,不管从库是否收到——这就是数据丢失风险的根源。半同步强制要求:
- 至少一个从库确认收到了该事务的 binlog event(
Ack),主库才向客户端返回成功 - 插件需在主从两端都启用:
INSTALL PLUGIN rpl_semi_sync_master SONAME 'semisync_master.so'和对应从库插件 - 注意副作用:网络抖动时会退化为异步,且性能下降约 5%~15%,尤其小事务高频场景
mysql> SHOW VARIABLES LIKE 'rpl_semi_sync%'; +-------------------------------------------+-------+ | Variable_name | Value | +-------------------------------------------+-------+ | rpl_semi_sync_master_enabled | ON | | rpl_semi_sync_master_timeout | 10000 | | rpl_semi_sync_slave_enabled | ON | +-------------------------------------------+-------+
真正难的不是配通主从,而是理解「事务结束」和「复制完成」之间那几十毫秒的灰色地带——它既不在 ACID 范畴内,也不在复制协议里明确定义,而是由你的 sync 参数、网络质量、从库负载共同决定的边界。










