Skip to content

语言English | 简体中文

复制协议实验矩阵

tick 是确定性的事件排序步,不是墙上时钟。下表每个单元格都有协议 pytest 或只调用公开 API 的 lab 断言支撑。

实验 协议 1:异步主从 协议 2:WAL 运输 协议 3:ISR + HW 协议 4:Raft
1. 正常复制 LEADER 在 replica apply 前返回;流消息送达后收敛。 LEADER 在 primary 本地 WAL flush 后、异步 standby apply 前返回;QUORUM 等待全部配置的同步 standby flush。 LEADER 可留下 follower 缺口;ALL_ISR 仅在当前 ISR 全部拥有该 offset 且 HW 推进后返回。 QUORUM 在多数派复制后返回;commit 传播后全部存活状态机收敛。
2. ack 后杀 leader 立即 promote stale replica 会丢已确认写。 异步 LEADER 写可能不在被 promote 的 standby;同步 QUORUM 写存在于全部配置的同步候选。 ALL_ISR 写已位于所有 ISR 成员的 HW 以下,controller clean election 后保留。 QUORUM 已提交前缀存活,多数派选出新 leader 后仍可读。
3. 旧 leader 位于少数派 两个手工指定 primary 都能确认本地脏写;愈合后新 generation 胜出。 promote 增加 timeline;旧 timeline 排队 WAL 在 apply 前被拒,standby 跟随新分支。 controller 增加 leader epoch;旧 epoch append 被栅栏,clean election 从 HW 开始。 旧 leader 无法 commit;多数派的更高任期 leader 在愈合后覆盖未提交后缀。
4. 慢副本 primary 不依赖 replica 投票,仍可写;慢 replica stale。 异步 standby 不影响本地 commit;若配置为同步 standby,则会阻塞 QUORUM controller 将滞后 follower 移出 ISR;剩余 ISR 仍满足 min.insync.replicas 时继续写。 成员固定,但三节点中一个慢 follower 不影响多数派 commit。
5. 落后副本重连 backlog 内 partial/增量;超出 backlog 或 lineage 不同则全量快照替换。 retained WAL 内增量运输;早于最老保留 LSN 或新 timeline 时 base backup/全量追赶。 leader 保留日志内增量 fetch;早于保留起点则全量快照,追到 HW 后才重入 ISR。 M3 日志不压缩,始终通过 nextIndex 回退和增量日志重放修复;snapshot/全量传输属 v2。
6. 读一致性矩阵 LOCAL:lagging replica stale。LEADER:fresh 但无权威证明。LINEARIZABLE:不支持。 LOCAL:lagging standby stale。LEADER:fresh 但无 lease 证明。LINEARIZABLE:不支持。 LOCAL:stale。LEADER:可能暴露未提交 append。LINEARIZABLE:直到 HW/lease/min.insync 证明权威才放行并返回 fresh。 LOCAL:lagging follower stale。LEADER:fresh 但可能是分区旧 leader。LINEARIZABLE:当前任期 read-index 多数派后 fresh。
7. 脑裂读与租约 旧 primary 的 LOCAL 返回 promote 前值;不提供 linearizable/lease guard。 旧 timeline primary 的 LOCAL 返回 promote 前值;timeline 栅栏写入而非孤立 stale 读,也不提供 lease read。 旧 leader LOCAL stale;controller 所有权与逻辑 leader lease 拒绝被替换的 leader。 旧 leader LOCAL stale;当前 leader read-index 成功,分区旧 leader 无法取得 quorum barrier。

ReadLevel 结果矩阵

实验 6 区分状态,不把各种失败都包装成“没有 stale”:

协议 LOCAL LEADER LINEARIZABLE
异步主从 stale fresh unsupported
WAL 运输 stale fresh unsupported
ISR + HW stale fresh 但未提交 无 HW lease 时 blocked
Raft stale fresh read-index 后 fresh

运行方法

uv run python labs/exp04_slow_replica.py
uv run python labs/exp05_replica_reconnect.py
uv run python labs/exp06_read_consistency.py
uv run python labs/exp07_split_brain_lease.py
uv run pytest -q tests/labs/test_experiments.py

实验 4、5、7 接受 --protocol async|wal|isr|raft|all,默认打印四列;实验 6 总是打印完整 3 × 4 矩阵。脚本只调用 replication group 公开 API,不直接调用 RPC handler,也不修改 scheduler/network 内部状态。

确定性与持久化边界

两个新协议都有同 seed、逐事件相同的 Trace 回放测试。显式 lose_unfsynced=True crash 是断电注入:节点回滚到最近一次模拟 fsync; 普通 crash(node) 保留已接受的持久状态。Raft 在依赖其结果的 RPC response 前持久化 term/vote/log;WAL LEADER flush primary,WAL QUORUM 还 flush 全部同步 standby;Kafka 式副本暴露类似 page cache 的未 fsync copy,但 ALL_ISR 依靠多副本保护;异步 primary 可确认尚未 fsync 的本地 dataset。