半同步、复制拓扑与分片

共 21 题
📑 题目列表 21 题
#
★★★

1. PostgreSQL synchronous_commit 的级别,off、local、on、remote_write、remote_apply?

PostgreSQL synchronous_commit 有哪些级别?off、local、on、remote_write、remote_apply 分别代表什么?

  • synchronous_commit 各级别含义
  • 同步提交与数据持久化程度
  • 与复制同步性的关系

PostgreSQL 的 synchronous_commit 参数控制事务提交时对持久化的等待程度,级别从低到高:off——不等待本地 WAL 刷盘就返回,最快但可能丢最近事务;local——等待本地 WAL 刷盘,但不等待从库,RPO 依赖本地;remote_write——等待从库收到 WAL 写入但未刷盘,比 local 多一层同步;on(默认)——等待从库收到并刷盘 WAL,保证事务已同步到至少一个从库的磁盘;remote_apply——等待从库不仅收到刷盘,还已经回放(应用)了该事务,从库查询可见,最严格。级别越高,主库提交延迟越高,但数据同步性越强。

synchronous_commit 级别在"主库性能"与"数据同步程度"之间权衡。off 牺牲数据安全换性能(适合临时表),remote_apply 最严格但延迟最大。它需配合 synchronous_standby_names 指定的同步从库生效。理解级别差异有助于按业务选择合适的一致性等级。

#
★★★

2. 半同步复制(Semi-Sync),MySQL after sync、after commit?

MySQL 半同步复制(Semi-Sync)中 after sync 与 after commit 两种模式有何区别?

  • 半同步复制的基本流程
  • after_commit 与 after_sync 的实现差异
  • 数据丢失窗口

半同步复制保证主库至少等一个从库确认收到 binlog 后才向客户端返回成功。after_commit(旧版默认):主库先提交事务(引擎 commit),再等待从库 ACK,再返回客户端。其丢失窗口是"主库已 commit 但未收到 ACK 时若崩溃,该事务可能丢失"。after_sync(MySQL 5.7 起默认):主库先写 binlog,等待从库 ACK 后再提交事务,再返回客户端。这样返回成功的事务必然已被从库确认,消除主库崩溃时丢失已确认事务的窗口。after_sync 更安全但提交延迟略高。

两者核心差异是"提交"与"等待 ACK"的顺序。after_commit 在 commit 后等 ACK,存在丢失窗口;after_sync 在 commit 前等 ACK,压缩丢失窗口。因此 after_sync 提供更接近零丢失的保障,是半同步演进的关键改进。

#
★★★

3. 同步复制(Sync Replication),RPO=0 但性能下降?

同步复制(Sync Replication)是什么?为何 RPO=0 但性能下降?

  • 同步复制的定义
  • RPO=0 的保证
  • 性能下降的原因

同步复制要求主库在事务提交前,必须等待所有(或多数)同步从库确认已收到并持久化该事务的日志,然后才向客户端返回成功。这样保证主库提交的事务已存在于从库,因此 RPO=0(主库崩溃不丢已确认数据)。性能下降的原因:每个事务都要等待从库的网络往返(ACK)和刷盘,交易在客户端视角的延迟显著增加,尤其是跨地域或高延迟网络下更明显;同时主库吞吐受限于最慢的同步从库,整体吞吐下降。若同步从库故障,主库可能被阻塞,需配合降级策略。

同步复制用"主库等待从库确认"换取 RPO=0,本质是"延迟换数据安全"。其代价是提交延迟大、吞吐受限、依赖从库可用性。因此同步复制适合对数据丢失零容忍的关键场景(如核心交易),且通常只在同城低延迟网络使用。同步复制与半同步的区别在于等多少个从库、确认到什么程度。

#
★★★

4. 异步复制(Async Replication),性能高但 RPO 可能丢失数据?

异步复制(Async Replication)是什么?为何性能高但 RPO 可能丢失数据?

  • 异步复制的定义
  • 性能优势
  • RPO 的数据丢失风险

异步复制中,主库提交事务后立即向客户端返回成功,不等待从库确认,binlog/WAL 在后台异步传输给从库重放。其优势是主库不等待从库,提交延迟低、吞吐高、不受从库状态影响。其代价是 RPO 可能大于 0:主库与从库之间存在复制滞后,若主库在事务已提交但尚未传到从库时崩溃,这些事务会丢失,从库无法追平。RPO 取决于复制滞后的时间,可能丢失短时间(秒级到分钟级)的数据。

异步复制是"性能优先"的默认选择,用"可能丢失最近数据"换取低延迟高吞吐。它适合对数据丢失容忍度高的读写分离场景,但核心交易等强一致场景需配合强制读主或升级为同步/半同步。RPO 不是固定值,而是随复制滞后动态变化,危险区间是主库崩溃瞬间。

#
★★★

5. 主从切换(Primary-Replica Switchover)的 Runbook 编写?

主从切换(Primary-Replica Switchover)的 Runbook 应如何编写?包含哪些关键步骤?

  • Runbook 的编写原则
  • 切换前的准备与检查
  • 切换执行与回滚

主从切换 Runbook 是计划内切换的操作手册,应包含:切换前准备(确认从库追平、校验数据一致性、备份、通知业务、记录在位/切换时间窗口)、详细步骤(逐条列出切换命令与操作,如停止写流量、提升从库、重挂其他从库、更新路由/域名/VIP)、验证步骤(切换后检查新主可写、从库追平、业务连通、数据校验)、回滚步骤(若切换失败如何回切)、风险与注意事项(数据丢失可能、主从角色确认、避免双写)。Runbook 编写原则是"可执行、可验证、可回滚、有检查点",并需演练验证。

Runbook 的核心价值是把"容易出错的高风险操作"流程化、可检查化,降低人为失误。写好 Runbook 的前提是理解切换原理与数据一致性保证。计划内切换(switchover)与紧急切换(failover)不同,前者可从容准备,后者更侧重快速恢复。Runbook 应定期演练并更新。

#
★★★

6. 紧急切换(Emergency Failover)的步骤?

紧急切换(Emergency Failover)的步骤是什么?与计划内切换有何不同?

  • 紧急切换的触发与决策
  • 快速恢复的步骤
  • 与计划内切换的差异

紧急切换(Emergency Failover)指主库异常故障时,为快速恢复服务而执行的切换。步骤包括:确认故障(多源确认,避免误判)、评估数据状态(检查从库追平情况,评估 RPO 可接受程度)、选择并提升新主(选数据最全的从库,必要时补拉日志)、更新路由与流量(VIP/域名/DNS/注册中心切到新主)、重挂其他从库、验证业务、记录故障。与计划内切换(switchover)的差异:紧急切换无准备时间、优先保证 RTO、可能接受一定数据丢失(受 RPO 约束)、只做必要验证、风险更高;计划内切换从容准备、可先停机维护、完整验证、可回滚。

紧急切换的核心是"在 RTO 与 RPO 之间快速决策"。它必须在最短时间内恢复服务,同时尽量不丢失数据(受 RPO 约束)。因此需要预置故障预案、自动切换工具和演练,避免故障时临场决策。紧急切换后要尽快做数据校验与业务恢复验证。

#
★★★

7. 分片(Sharding)复制拓扑,每分片独立主从?

分片(Sharding)复制拓扑是什么?为什么每个分片独立主从?

  • 分片复制拓扑
  • 每分片独立主从的意义
  • 分片与复制的关系

分片(Sharding)把数据按分片键切分到多个数据库实例(分片),每个分片存储部分数据。每个分片通常配置独立的复制拓扑(自己的主从复制链),即"每分片独立主从":每个分片有主库承担该分片的写,从库承担该分片的读与容灾。这样做的意义:一是故障隔离——单个分片的主从故障不影响其他分片;二是扩展性——每个分片独立承载读写,可整体水平扩展;三是容灾——每个分片都有自己的从库保障高可用。分片复制拓扑与单库复制原理相同,只是复制组按分片独立组织。

"分片独立主从"是分布式数据库的常见做法,把复制与分片结合,兼顾水平扩展与高可用。分片间相互独立,若要跨分片查询则需额外机制(如全局二级索引、分布式查询)。分片复制拓扑的管理复杂度随分片数量增加,需统一的元数据管理。

#
★★★

8. 双主复制(Master-Master)的冲突解决,MySQL 双写、PostgreSQL BDR?

双主复制(Master-Master)如何解决写冲突?MySQL 双写与 PostgreSQL BDR 有哪些方案?

  • 双主复制的冲突来源
  • MySQL 双写冲突方案
  • PostgreSQL BDR 的冲突解决

双主复制(Master-Master)允许两个节点同时写入,会引入写冲突(同一行被两侧同时修改)。MySQL 传统双主复制本身不解决冲突,需应用层保证(如按业务分片路由、避免同一行双写、用时间戳/自增偏移),或用 Galera 等提供冲突检测的方案。PostgreSQL BDR(Bi-Directional Replication)通过逻辑复制支持多主,提供冲突检测与解决策略(如 last-write-wins、按节点优先级、错误报告),并利用节点标识和冲突解决方案处理。真正的双主冲突解决需要"冲突检测 + 冲突消解 + 幂等"的完整机制,复杂度高。

双主复制的核心难点是冲突解决。无冲突检测的 MySQL 双写容易产生数据不一致,需应用层规避;BDR 等逻辑复制方案提供自动冲突检测与解决策略,但处理复杂且可能引入性能开销。因此多数系统选择"单点写、多点读"而非真双写,以规避冲突问题。

#
★★★

9. 级联复制(Cascading Replication),主 → 中继 → 从?

级联复制(Cascading Replication)是什么?主 → 中继 → 从的拓扑如何工作?

  • 级联复制的拓扑
  • 中继节点的作用
  • 级联复制的利弊

级联复制(Cascading Replication)指复制链经过中继节点:主库 → 中继节点(充当从库同时又是下一级的主库)→ 从库。中继节点接收主库的日志并转发给下游从库,从而减轻主库的连接和发送压力(主库只需连接中继节点)。其优点是减少主库的连接数、便于分级管理。缺点是延迟逐级放大(下游延迟 = 中继接收延迟 + 下游接收延迟)、中继故障影响下游所有从库、故障传播范围更广。级联复制适合"主库连接数受限、需要大量只读从库"的场景,但对延迟敏感业务需谨慎。

级联复制是"用层次结构换主库压力"的架构。中继节点承担了转发职责,但引入延迟放大和单点故障传播。它通常在只读扩展需求大、主库连接数受限时使用。

#
★★★

10. MySQL Group Replication(MGR)如何通过 XCom(Paxos 变体)做事务认证(certification)保证全局有序?单主与多主模式在冲突检测与写吞吐上有何差异?

MySQL Group Replication(MGR)如何通过 XCom(Paxos 变体)做事务认证(certification)保证全局有序?单主与多主模式在冲突检测与写吞吐上有何差异?

  • MGR 的 XCom 共识层
  • 事务认证(certification)机制
  • 单主与多主模式差异

MGR(MySQL Group Replication)基于 XCom(Paxos 变体)提供组内共识与总序(total order)广播:所有节点通过 XCom 把事务提交顺序协商为全局一致,保证每个节点都以相同顺序看到事务。事务认证(certification)机制:节点提交事务前,把事务的写集合广播给组内所有节点,每个节点用写集合做冲突检测(若与其他已提交事务的写集合交叠则冲突),根据冲突结果决定提交或回滚,从而保证全局一致性。单主模式:只有一个节点可写,其余只读,无写冲突,吞吐稳定,适合写并发的关键场景;多主模式:所有节点可写,任一节点写冲突时需回滚并重试,冲突检测开销大,吞吐受冲突率影响,写并发高时冲突多、吞吐下降。因此单主写吞吐更可控,多主适合低冲突分布式写。

MGR 的核心是"XCom 共识(总序)+ certification(冲突检测)",用多数派协议保证全局有序与最终一致。单主避免了写冲突,吞吐稳定;多主提高写可用性但引入冲突回滚开销。选择单主 vs 多主需权衡写冲突率与可用性需求。MGR 能自动故障转移,是 MySQL 高可用的现代方案。

#
★★★

11. Galera Cluster 的写集认证(writeset certification)如何在提交前检测跨节点冲突?流控(Flow Control)与状态传输(SST/IST)分别在何时触发?

Galera Cluster 的写集认证(writeset certification)如何在提交前检测跨节点冲突?流控(Flow Control)与状态传输(SST/IST)分别在何时触发?

  • Galera 的写集认证机制
  • 流控(Flow Control)的触发
  • SST/IST 状态传输的触发

Galera Cluster 是同步多主复制方案。写节点在事务提交前,将该事务的写集(写入的行集合)广播给集群所有节点,各节点对写集做 certification(认证):若该写集与节点上已提交的写集冲突(行集合交叠),则冲突事务在部分节点回滚(由发起节点重试),未冲突则提交。这保证跨节点冲突在提交前被检测。流控(Flow Control)在节点接收速度跟不上(如慢节点落后、发送队列积压)时触发,通过与写节点协商放慢提交速率,防止慢节点掉队。状态传输(SST/IST)在节点加入集群或旧节点落后过多时触发:SST(State Snapshot Transfer)全量传输数据(用于新节点或落后超过阈值),IST(Incremental State Transfer)增量传输缺失的写集(用于落后较少、仍缓存中的节点)。

Galera 的写集认证是"提交前障碍同步"的冲突检测,保证集群一致。流控是"保护慢节点"的背压机制,状态传输是"追平新/落后节点"的恢复机制。理解认证、流控、SST/IST 的触发条件,是运维 Galera 集群的关键。SST 全量、IST 增量,按落后程度选择。

#
★★★

12. 复制过滤(replicate-do-db/replicate-ignore-db)为何容易导致主从不一致(基于 USE 的库语义、跨库语句被漏放)?如何用 replicate-wild-do-table 基于表名过滤替代?

复制过滤(replicate-do-db/replicate-ignore-db)为何容易导致主从不一致?如何用 replicate-wild-do-table 基于表名过滤替代?

  • 复制过滤的语义问题
  • 基于 USE 与跨库语句的漏放
  • replicate-wild-do-table 的替代方案

MySQL 复制过滤 replicate-do-db/replicate-ignore-db 基于数据库(库)过滤,其语义依赖 "USE" 动作:在 statement 复制下,它根据当前默认库(USE 指定的库)判断是否过滤,而不是根据语句实际影响的库。这导致跨库语句(单条语句访问多个库,或语句的库与当前默认库不同)被错误过滤或漏放,造成主从数据不一致。例如 replicate-do-db=a 时,执行 UPDATE b.t SET ...(当前 USE a)可能被错误放行或过滤。更稳妥的方案是用 replicate-wild-do-table/replicate-wild-ignore-table 基于表名(db.table 模式)过滤,它按语句实际影响的表匹配,避免基于 USE 的库语义问题,更精确地控制复制范围。

复制过滤的坑在于"基于库的过滤语义与实际语句影响范围不一致"。基于表名的过滤(replicate-wild-do-table)直接匹配实际表,语义清晰,避免跨库语句漏放。因此需要精确过滤时应使用表级过滤,并对过滤后的主从一致性做校验。这也是为何复制过滤被普遍认为"危险"、需谨慎使用的原因。

#
★★★

13. 分片键(Sharding Key)的选择准则,高基数、均匀分布、业务边界?

分片键(Sharding Key)的选择准则是什么?高基数、均匀分布、业务边界如何权衡?

  • 分片键的准则
  • 高基数与均匀分布
  • 业务边界与查询友好性

分片键(Sharding Key)的选择是分片设计的核心,准则包括:其一,高基数——分片键的取值种类要多,避免集中到少数分片;其二,均匀分布——分片键的值分布要均匀,使数据与请求均衡分散到各分片,避免热点分片;其三,业务边界——分片键应契合业务查询模式,使同一业务实体的数据尽量落在同一分片(如按用户 ID 分片,使一个用户的所有数据在同分片),从而避免跨分片查询/事务;其四,稳定性——分片键值不应频繁变化,否则迁移成本高。这几个准则可能冲突(如高业务边界但基数低),需根据业务查询重分布与流量特征综合权衡。

分片键的最终目标是"均衡 + 查询友好"。高基数保证可扩展空间,均匀分布避免热点,业务边界减少跨分片操作。理想分片键是三者兼顾(如订单按用户 ID 分片),但现实中需取舍。分片键的选择决定了后续的查询路由、跨分片 JOIN 与再平衡复杂度,因此是最重要的设计决策。

#
★★

14. 计划内切换(Planned Switchover)的步骤?

计划内切换(Planned Switchover)的步骤是什么?与紧急切换有何区别?

  • 计划内切换的步骤
  • 与紧急切换的对比
  • 切换的验证与回滚

计划内切换(Planned Switchover)是在主从均健康时,为维护、升级或演练而主动执行的切换。步骤:切换前准备(通知业务、确认从库追平、备份、设定窗口、检查健康)、切换执行(停止写流量、将目标从库提升为新主、重挂其他从库、更新路由/域名/VIP)、切换验证(验证新主可写、从库追平、业务连通、数据一致性)、回滚预案(若失败回切)。与紧急切换的区别:计划内切换有充分准备时间、先校验数据、可完整验证、可回滚、风险低;紧急切换无准备、优先 RTO、可能接受数据丢失、只做最小验证。计划内切换通常数据零丢失(从库已追平)。

计划内切换是"可控、可回滚"的主动操作,核心是"先确认从库追平,再提升,再校验"。它与紧急切换的差异源于"是否可准备"。计划内切换常与 Runbook 配合,用于演练和验证高可用方案。切换后应观察一段时间确认稳定。

#
★★

15. 一主多从(Master-Slave)拓扑的应用场景?

一主多从(Master-Slave)拓扑的应用场景是什么?有什么优缺点?

  • 一主多从的拓扑
  • 应用场景
  • 优缺点

一主多从(Master-Slave)拓扑是"一个主库 + 多个从库"的复制结构,主库承担写,从库承担读与容灾。应用场景:读写分离(把读压力分散到多个从库,提升读扩展性)、高可用(多从库互为备份,主库故障时选一个提升为新主)、数据备份(从库执行备份不影响主库)、数据分析(从库承载报表等分析查询)。优点:读写分离提升读吞吐、易于扩展读、容灾能力强。缺点:写仍集中在主库(写扩展性有限)、从库间数据存在复制延迟、主库故障仍有切换窗口、从库越多主库发送压力越大。

一主多从是最经典的复制拓扑,适合"读多写少"的业务,通过增加从库水平扩展读。它解决读扩展与容灾,但写仍是单点。随着写压力增大,需升级为分片或 MGR。理解一主多从的边界,是设计高可用与扩展架构的基础。

#
★★

16. 再平衡(Rebalance)的实现,双倍扩容、在线迁移?

再平衡(Rebalance)的实现方式有哪些?双倍扩容与在线迁移如何工作?

  • 再平衡的概念
  • 双倍扩容策略
  • 在线迁移与数据搬迁

再平衡(Rebalance)指分片数量变化时,重新分配数据/请求使其均衡的过程。常见实现:其一,双倍扩容——把分片数翻倍(如 8→16),每个旧分片的数据均匀拆分成两半迁移到新分片,减少迁移范围和影响,且每个分片只需搬迁一半数据;其二,在线迁移——在不中断服务的情况下,通过后台任务把数据从旧分片复制到新分片,校验一致后再切换路由,平滑完成扩容;其三,一致性哈希——通过哈希环和虚拟节点减少迁移量,扩容时只迁移部分 key。再平衡的关键是降低迁移对在线服务的影响(限速、分批、校验)与保证数据一致性。

再平衡的本质是"以尽量小的扰动重新分配数据"。双倍扩容是分片扩容的经典策略(每片只动一半),在线迁移是平滑迁移实现。一致性哈希则减少需要迁移的 key 数量。再平衡要兼顾迁移速度、服务影响与数据一致性,是分布式数据库运维的难点。

#
★★

17. 热点分片(Hot Shard)的检测与应对?

热点分片(Hot Shard)如何检测与应对?热点分片有哪些危害?

  • 热点分片的检测指标
  • 热点分片的应对策略
  • 热点分片的危害

热点分片(Hot Shard)指某个分片承载了远超平均的读写流量,导致该分片成为瓶颈。检测方法:监控各分片的读写量、延迟、CPU/IO 等指标,通过分位数或阈值识别异常分片;也可通过分析请求分布(如某 key 被集中访问)发现。应对策略:其一,热点 key 拆分——把热点 key 加后缀/前缀拆成多个逻辑 key 分散到不同分片;其二,热点数据缓存——用缓存层(Redis)承接热点读;其三,动态分片——按需把热点分片继续拆分或迁移;其四,读写短读——热点读走缓存/从库。热点分片的危害:单分片过载导致延迟升高、影响整体可用性,甚至引发雪崩。

热点分片破坏了分片的"均衡"假设,是分片架构的常见问题。应对的核心是"识别热点 + 分散热点(key 拆分、缓存、动态迁移)"。检测要靠可观测性(分片级指标),预防要靠均衡分片键与热点感知的负载均衡。热点分片是分片设计时需重点规避的风险。

#
★★

18. Leaf(美团点评)的号段模式与雪花模式?

美团 Leaf 的号段模式与雪花模式是什么?两者有何区别?

  • 号段模式(segment)
  • 雪花模式(snowflake)
  • 两者的取舍

美团 Leaf 是分布式 ID 生成方案,提供两种模式:号段模式(segment)——从数据库批量取一段连续的 ID(如号段),应用内存中分配,号段用尽后再取下一段,用 UPDATE 号段表 + 乐观锁/双 buffer 保证并发与平滑;雪花模式(snowflake)——基于时间戳 + 机器 ID + 序列号的 64 位 ID,本地生成、无需数据库交互,性能极高。号段模式 ID 连续、便于批量插入和页序,但依赖数据库且号码可预测;雪花模式趋势递增、性能高、无数据库依赖,但依赖时钟且 ID 不连续。Leaf 的雪花模式还通过 ZK 维护机器 ID 并解决时钟回拨。

号段模式与雪花模式是分布式 ID 的两种主流方案,取舍在于"是否连续、是否依赖数据库、性能"。号段模式适合需要连续 ID 的场景(如订单号按序),雪花模式适合高并发、无顺序要求或需低延迟的场景。理解两者有助于结合业务选择。

#
★★

19. 分布式全局 ID 的需求,唯一性、趋势递增、低延迟?

分布式全局 ID 的需求是什么?唯一性、趋势递增、低延迟如何理解?

  • 全局唯一性
  • 趋势递增与业务意义
  • 低延迟与高可用

分布式全局 ID 的核心需求:其一,全局唯一性——不同节点、不同时刻生成的 ID 不能重复,这是最基本要求;其二,趋势递增——ID 随时间大致递增,有利于数据库索引(有序插入,避免随机 IO 导致索引碎片与页分裂)、便于时间排序(如订单按时间)、便于分页;其三,低延迟(高可用)——生成 ID 要快(本地生成优于远程依赖),且系统高可用(如区分机器、时钟回拨处理),避免成为瓶颈;其四,信息安全——ID 通常不可预测(雪花含时间戳,可选择性加密)。实现方案有数据库自增、号段、雪花、UUID 等,不同方案在上述需求上取舍。

分布式 ID 是为支持"多节点并发 + 数据库有序索引"而生的。唯一性保证不冲突,趋势递增保证数据库写入有序、性能好,低延迟保证不拖慢业务。雪花 ID 兼顾了唯一性、趋势递增、低延迟,因此成为主流;UUID 全局唯一但无序、不递增,索引性能差。实际方案需结合业务对有序性、安全性、性能的要求选择。

#
★★

20. 雪花 ID(Snowflake)的 64 位结构与实现?

雪花 ID(Snowflake)的 64 位结构是什么?如何实现?

  • 雪花 ID 的位结构
  • 时间戳、机器 ID、序列号
  • 时钟回拨处理

雪花 ID(Snowflake)是 64 位长整型,典型结构:1 位符号位(恒为 0)+ 41 位时间戳(毫秒级,可表示约 69 年)+ 10 位机器 ID(数据中心 + 机器,可区分不同节点)+ 12 位序列号(同一毫秒内可生成 4096 个 ID)。生成时:取当前毫秒时间戳,与机器 ID 和序列号组合成 64 位。同一毫秒内序列号递增,超过 4096 则等待下一毫秒。实现要点:为每个机器分配唯一机器 ID(如通过 ZK/配置)、处理时钟回拨(记录上次时间戳,若当前时间小于上次则等待或拒绝,或保留序列号防线)、保证序列号并发安全。雪花 ID 特性:全局唯一、趋势递增、本地生成低延迟、可解析出时间信息。

雪花 ID 的精髓是"用 64 位同时编码时间、机器、序列号",从而在本地无依赖地生成唯一且趋势递增的 ID。时钟回拨是其主要风险,需处理。它权衡了唯一性、递增性、性能,是分布式 ID 的主流实现。

#

21. MySQL 半同步复制 after_commit 模式下主库崩溃可能丢失已确认事务?

MySQL 半同步复制 after_commit 模式下主库崩溃为何可能丢失已确认事务?

  • after_commit 的提交顺序
  • 丢失窗口的时序
  • after_sync 的改进

在 after_commit 模式下,主库先提交事务(存储引擎 commit),再等待从库 ACK,最后向客户端返回成功。存在一个时序窗口:主库已完成 commit,但尚未收到从库 ACK(或已返回客户端但 ACK 未到达)时,若主库崩溃,该事务已提交但可能未传给从库(binlog 已写但从库未收到/未确认),导致该事务在从库缺失,从库无法追平,已确认(返回成功)的事务丢失。因此 after_commit 的半同步不能保证"已确认事务绝不丢失"。而 after_sync 模式先等从库 ACK 再 commit,消除了这一窗口。这正是 MySQL 5.7 起默认采用 after_sync 的原因。

该问题的本质是"commit 与 ACK 的顺序"导致主库崩溃时已确认事务丢失的窗口。after_commit 的窗口在"commit 后、ACK 前",after_sync 将其消除。因此追求零丢失需用 after_sync 或 MGR 多数派确认。这也是半同步复制被诟病"并不完全可靠"的原因。