MySQL 中的半同步复制与无损复制机制

在 MySQL 的高可用架构中,主从复制是最核心的基础组件。然而,默认的异步复制存在一个致命缺陷:主库提交事务后立即返回客户端,不等待从库确认。一旦主库崩溃,尚未传输到从库的事务就会永久丢失。为了解决这个问题,MySQL 先后引入了半同步复制和无损复制机制,在数据安全与性能之间寻找平衡点。这也是面试中高频出现的考点,下面我们逐一拆解。

一、异步复制的先天缺陷

在理解半同步复制之前,先回顾异步复制的工作流程:

  1. 主库执行事务,写入 binlog。
  2. 主库存储引擎提交事务,返回客户端成功。
  3. dump 线程异步将 binlog 发送给从库。
  4. 从库的 I/O 线程接收并写入 relay log,SQL 线程回放。

问题出在第 2 步和第 3 步之间——主库根本不关心从库是否收到 binlog。如果主库在发送前宕机,这些事务就彻底丢失了。对于金融、订单等场景,这是不可接受的。

二、半同步复制的核心原理

半同步复制(Semisynchronous Replication)的核心思想是:主库提交事务后,至少等待一个从库确认收到 binlog(而非执行完成),才向客户端返回成功。

2.1 工作流程

  1. 主库提交事务,写入 binlog。
  2. 主库等待至少一个从库的 ACK 确认。
  3. 从库 I/O 线程收到 binlog 并写入 relay log 后,向主库发送 ACK。
  4. 主库收到 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=1innodb_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 中的半同步复制与无损复制机制

赞 (0) 打赏

评论 0

取消
  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏