在 MySQL 的高可用架构中,主从复制是最核心的基础组件。然而,默认的异步复制存在一个致命缺陷:主库提交事务后立即返回客户端,不等待从库确认。一旦主库崩溃,尚未传输到从库的事务就会永久丢失。为了解决这个问题,MySQL 先后引入了半同步复制和无损复制机制,在数据安全与性能之间寻找平衡点。这也是面试中高频出现的考点,下面我们逐一拆解。
一、异步复制的先天缺陷
在理解半同步复制之前,先回顾异步复制的工作流程:
- 主库执行事务,写入 binlog。
- 主库存储引擎提交事务,返回客户端成功。
- dump 线程异步将 binlog 发送给从库。
- 从库的 I/O 线程接收并写入 relay log,SQL 线程回放。
问题出在第 2 步和第 3 步之间——主库根本不关心从库是否收到 binlog。如果主库在发送前宕机,这些事务就彻底丢失了。对于金融、订单等场景,这是不可接受的。
二、半同步复制的核心原理
半同步复制(Semisynchronous Replication)的核心思想是:主库提交事务后,至少等待一个从库确认收到 binlog(而非执行完成),才向客户端返回成功。
2.1 工作流程
- 主库提交事务,写入 binlog。
- 主库等待至少一个从库的 ACK 确认。
- 从库 I/O 线程收到 binlog 并写入 relay log 后,向主库发送 ACK。
- 主库收到 ACK 后,才返回客户端成功。
注意关键点:从库只需确认收到并写入 relay log,不需要等待 SQL 线程执行完成。这比全同步复制轻量得多。
2.2 两种模式:AFTER_SYNC 与 AFTER_COMMIT
MySQL 5.7 之前,半同步复制采用 AFTER_COMMIT 模式,存在一个隐蔽的“幻读”问题:
- 主库在存储引擎层提交事务后,才等待从库 ACK。
- 此时其他会话已经可以看到该事务的数据。
- 但如果等待超时,主库会退化为异步复制,客户端收到成功,而从库可能永远收不到这个事务。
MySQL 5.7 引入了 AFTER_SYNC 模式(默认),将等待 ACK 的时机提前到存储引擎提交之前:
- 主库写入 binlog 后,先等待从库 ACK。
- 收到 ACK 后再进行存储引擎提交。
- 这样在等待期间,其他会话看不到未提交的数据,避免了幻读。
AFTER_SYNC 是半同步复制的重要改进,也是面试中经常追问的细节。
2.3 超时与退化机制
半同步复制并非“死等”。通过参数 rpl_semi_sync_master_timeout(默认 10000 毫秒)控制等待时间:
- 超时后,主库自动退化为异步复制,不再阻塞客户端。
- 当从库恢复并追上进度后,主库会自动切回半同步模式。
这个设计保证了主库的可用性,但也意味着在极端情况下仍可能丢失数据。
三、无损复制的提出
半同步复制虽然大幅提升了数据安全性,但在 AFTER_SYNC 模式下仍有一个理论上的丢数据窗口:
主库等待 ACK 超时后退化为异步复制,此时如果主库宕机,那些已经写入 binlog 但未被从库确认的事务,在从库提升为主库后会丢失。
MySQL 5.7.17 引入了无损复制(Lossless Replication),本质上是半同步复制的一种增强配置,核心参数是 rpl_semi_sync_master_wait_point=AFTER_SYNC 配合 sync_binlog=1 和 innodb_flush_log_at_trx_commit=1。
3.1 无损复制的关键条件
无损复制并非一个独立的新机制,而是以下配置的组合:
rpl_semi_sync_master_wait_point = AFTER_SYNC:确保等待 ACK 在存储引擎提交之前。sync_binlog = 1:每次事务提交都刷盘 binlog。innodb_flush_log_at_trx_commit = 1:每次事务提交都刷盘 redo log。- 至少一个从库正常响应 ACK。
在这些条件下,主库只有在确认从库收到 binlog 后,才会完成存储引擎提交并返回客户端。因此,任何已返回客户端成功的事务,都至少存在于一个从库的 relay log 中,不会丢失。
3.2 与半同步复制的区别
| 维度 | 半同步复制 | 无损复制 |
|---|---|---|
| 等待时机 | 可配置 AFTER_COMMIT 或 AFTER_SYNC | 必须 AFTER_SYNC |
| 数据丢失风险 | 超时退化后可能丢失 | 已提交事务不丢失 |
| 性能影响 | 较低 | 略高(需等待 ACK 后才提交) |
| 核心参数 | rpl_semi_sync_master_enabled | wait_point + sync_binlog + flush_log |
简单来说,无损复制是半同步复制在 AFTER_SYNC 模式下的“完全体”,通过严格的刷盘策略消除了退化时的数据丢失窗口。
四、面试常见追问
Q1:半同步复制能保证数据绝对不丢吗?
不能。在 AFTER_COMMIT 模式下,超时退化后主库崩溃会丢数据。即使在 AFTER_SYNC 模式下,如果 sync_binlog 不为 1,主库宕机时 binlog 可能还未刷盘,同样会丢。
Q2:半同步复制等待的是从库执行完 SQL 吗?
不是。等待的是从库 I/O 线程将 binlog 写入 relay log 并返回 ACK,SQL 线程是否执行不影响主库返回。
Q3:无损复制和 MySQL Group Replication 有什么区别?
无损复制基于传统主从架构,本质仍是半同步;MGR 基于 Paxos 协议,是真正的多副本一致性协议,能自动选主和冲突检测,但架构复杂度和性能开销更高。
Q4:如何监控半同步复制状态?
通过 SHOW STATUS LIKE 'Rpl_semi_sync%' 查看,重点关注 Rpl_semi_sync_master_status(是否处于半同步)、Rpl_semi_sync_master_no_tx(未收到 ACK 的事务数)和 Rpl_semi_sync_master_yes_tx(收到 ACK 的事务数)。
五、总结
半同步复制通过“等待至少一个从库 ACK”在异步和全同步之间取得平衡,MySQL 5.7 的 AFTER_SYNC 模式进一步消除了幻读问题。无损复制则是半同步复制在严格刷盘配置下的形态,确保已提交事务不丢失。理解两者的演进逻辑和参数配置,不仅能应对面试,更能帮助我们在实际架构中做出合理的数据安全决策。
未经允许不得转载:任鹏个人博客 » MySQL 中的半同步复制与无损复制机制

