Finding 1: Identity no longer address-derived - ReplicaAddr.ServerID field added (stable server identity from registry) - BlockVolumeAssignment.ReplicaServerID field added (scalar RF=2 path) - ControlBridge uses ServerID, NOT address, for ReplicaID - Missing ServerID → replica skipped (fail closed), logged Finding 2: Wired into real ProcessAssignments - BlockService.v2Bridge field initialized in StartBlockService - ProcessAssignments converts each assignment via v2Bridge.ConvertAssignment BEFORE existing V1 processing (parallel, not replacing yet) - Logged at glog V(1) Finding 3: Fail-closed on missing identity - Empty ServerID in ReplicaAddrs → replica skipped with log - Empty ReplicaServerID in scalar path → no replica created - Test: MissingServerID_FailsClosed verifies both paths 7 tests: StableServerID, AddressChange_IdentityPreserved, MultiReplica_StableServerIDs, MissingServerID_FailsClosed, EpochFencing_IntegratedPath, RebuildAssignment, ReplicaAssignment Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
18 KiB
V2 算法综述
日期:2026-03-27 状态:战略级设计综述 读者:CEO / owner / 技术管理层
文档目的
本文用于说明 sw-block 当前 V2 方向背后的核心判断:
V2到底想解决什么问题- 为什么
V1/V1.5不足以作为长期架构 - 为什么我们仍然认为基于
WAL的方向值得继续走 V2与主要市场方案 / 论文路线相比的取舍是什么simulation与真实test runner如何形成系统化验证闭环
这不是 phase 汇报,也不是对生产可用性的承诺文档。
它是对 V2 这条架构线的高层技术解释。
与其他文档的关系
| 文档 | 作用 |
|---|---|
v1-v15-v2-comparison.md |
三条技术线的详细比较 |
v2-acceptance-criteria.md |
V2 协议验证下限 |
v2_scenarios.md |
场景清单与 simulator 覆盖 |
v2-open-questions.md |
仍未关闭的算法问题 |
protocol-development-process.md |
协议开发方法论 |
learn/projects/sw-block/algorithm_overview.md |
当前 V1/V1.5 系统级算法综述 |
learn/projects/sw-block/design/algorithm_survey.md |
论文 / vendor 调研与借鉴项 |
learn/projects/sw-block/test/README.md |
真实测试系统入口 |
learn/projects/sw-block/test/test-platform-review.md |
test runner 的平台化方向 |
1. 执行摘要
当前最准确的结论是:
V1证明了基于WAL的复制块存储基本路径是可行的。V1.5在真实恢复场景上已经比V1明显更强,并且有真实硬件上的运行证据。V2的意义,不是在已有逻辑上继续打补丁,而是把最关键的恢复与一致性问题直接上升为协议对象。
V2 的核心想法可以概括为:
- 短间隙恢复要显式
- 过期 authority 要显式 fencing
catch-up与rebuild的边界要显式- 恢复 ownership 要成为协议的一部分,而不是实现细节里的偶然行为
所以今天正确的策略是:
- 继续用
V1.5作为当前生产线 - 继续用
V2作为长期架构线 - 继续认真研究
WAL路线,因为现在我们已经具备了可信的验证框架 - 如果后续 prototype 证明
V2有结构性缺陷,就应当先演进到V2.5,而不是硬着头皮直接实现
2. V2 真正要解决的问题
从前端看,块存储似乎只有几个简单动作:
writeflush/sync- failover
- recovery
但真正难的,不是这些前端动作本身,而是异步分布式边界:
- primary 本地 WAL 追加
- replica 端 durable progress
- client 可见的 sync / commit 真值
- failover / promote 时的数据边界
- lag、restart、address change、timeout 后的恢复正确性
这才是 V2 存在的根因。
项目已经反复验证过:块存储真正的 bug 通常不出在 happy path,而出在:
- replica 短暂掉线又回来
- replica 重启后地址变化
- 延迟到达的 stale barrier / stale reconnect 结果
- 一个 lagging replica 看起来“差一点点就能恢复”
- failover 时基于错误 lineage 做了 promote
V2 就是要把这些情况变成协议的第一公民,而不是上线后再继续被动修补。
3. 为什么 V1 / V1.5 不够
这份综述不需要长篇回顾 V1 和 V1.5 的所有细节。
只需要讲清它们为什么不足以作为长期架构。
V1 做对了什么
V1 建立了最重要的基础:
- 严格有序的
WAL - primary-replica 复制
- 基于
epoch + lease的初步 fencing - 以
extent作为稳定数据面,而不是一开始就做全日志结构
V1 的不足
它的关键短板主要在恢复与退化场景:
- 短 outage 很容易演化成 rebuild 或长期 degraded
- 恢复结构过于隐式
- changed-address restart 脆弱
- stale authority / stale result 还不是协议层的显式对象
- 系统没有足够清晰地区分:
- 当前 head
- committed prefix
- recoverable retained range
- stale / divergent tail
V1.5 的不足
V1.5 已经解决了不少真实问题:
- retained-WAL catch-up
- same-address reconnect
sync_all的真实行为- catch-up 失败后的 rebuild fallback
- changed-address restart 之后的 control-plane 刷新
所以它今天是更强的生产线。
但它仍然不是长期架构,因为它本质上仍然是增量修复:
- reconnect 逻辑仍然附着在旧 shipper 模型上
- 恢复 ownership 是先作为 bug 暴露出来,再逐步被抽象
catch-upvsrebuild更清楚了,但还不够成为协议顶层契约- 整体感觉仍然更像“继续修 V1”,而不是“定义下一代复制协议”
V2 的变化
V2 不是重新发明一个完全不同的存储模型。
它的目标是把最关键的东西显式化:
- recovery ownership
- lineage-safe recovery boundary
catch-up/rebuild分类- per-replica sender authority
- stale-result rejection
- 明确的 recovery orchestration
因此最诚实的比较是:
V1.5今天在运行证据上更强V2今天在架构质量上更强
这不是矛盾,而是“当前生产线”和“下一代架构线”应有的分工。
flowchart TD
V1[V1]
V15[V1_5]
V2[V2]
realFailures[真实故障]
realTests[真实硬件验证]
simAndProto[仿真与原型]
V1 --> V15
V15 --> V2
realFailures --> V15
realFailures --> V2
V15 --> realTests
V2 --> simAndProto
4. V2 如何解决 WAL 与 Extent 的同步问题
V2 的核心问题不是“还要不要 WAL”。
真正的问题是:
primary 与 replica 之间,WAL 和 extent 如何保持同步,同时还能兼顾稳定性与性能。
这才是 V2 的中心。
4.1 基本分工
V2 把数据路径拆成两个既分离又协作的层:
- WAL:近期历史的有序真相
- extent:稳定的物化数据镜像
WAL 负责:
- 严格写入顺序
- 本地崩溃恢复
- 短间隙 replica catch-up
- 基于
LSN的 durable progress 计量
Extent 负责:
- 稳定读镜像
- 长期存储
- checkpoint / base image 生成
- 长间隙恢复时作为真正 base image 的来源
第一条稳定性原则就是:
- 不要让当前 extent 冒充历史状态
- 不要让 WAL 永远承担所有长距离恢复责任
4.2 Primary-replica 同步模型
V2 理想中的 steady-state 同步模型是:
- primary 分配单调递增的
LSN - primary 本地顺序追加
WAL - primary 把记录放入 per-replica sender loop
- replica 按顺序接收并推进显式 progress
barrier/sync依赖 replica 的 durable progress,而不是 optimistic send progress- flusher 再把 WAL-backed dirty state 物化到 extent
本地 WAL -> extent 生命周期可以理解为:
stateDiagram-v2
[*] --> WalAppended
WalAppended --> SenderQueued
SenderQueued --> ReplicaReceived
ReplicaReceived --> ReplicaDurable
ReplicaDurable --> SyncEligible
SyncEligible --> ExtentMaterialized
ExtentMaterialized --> CheckpointAdvanced
这里最关键的规则是:
- client 可见的 sync 真值必须跟随 durable replica progress
- 不能跟随 send progress
- 不能跟随 local WAL head
- 不能跟随“看起来 replica 应该已经收到了”
这也是为什么 V2 使用像 CommittedLSN 这样的 lineage-safe 边界,而不是松散的“当前 primary head”。
4.2.1 不同 sync mode 如何判断结果
V2 让不同 sync mode 的成功条件变得更明确:
best_effort:primary 达到本地 durability point 后即可成功,replica 可以后台恢复sync_all:所有 required replica 都要在目标边界上 durablesync_quorum:必须存在真实 durable quorum
其判断路径可以表示为:
flowchart TD
writeReq[WriteAndSyncRequest]
localDurable[PrimaryLocalDurable]
barrierEval[EvaluateReplicaDurableProgress]
bestEffortAck[best_effort成功]
syncAllAck[sync_all成功]
syncQuorumAck[sync_quorum成功]
rejectOrBlock[阻塞或失败]
writeReq --> localDurable
localDurable --> bestEffortAck
localDurable --> barrierEval
barrierEval -->|"allRequiredReplicasDurable"| syncAllAck
barrierEval -->|"durableQuorumExists"| syncQuorumAck
barrierEval -->|"notEnoughDurableReplicas"| rejectOrBlock
这意味着 sync 结果不再依赖:
- socket 看起来还活着
- sender 好像还在发
- replica 似乎“差不多收到了”
而是依赖显式 durable progress。
4.3 为什么这个设计应该更稳定
它试图把最危险的模糊边界拆开:
- 写入顺序 由
WAL + LSN表达 - durability truth 由 barrier / flushed progress 表达
- recovery ownership 由 sender + recovery attempt identity 表达
- catch-up vs rebuild 由显式分类表达
- promotion safety 由 committed prefix 与 lineage 表达
也就是说,V2 的稳定性来自于减少隐式耦合。
4.4 为什么它仍然可以有高性能
这里不能夸大说 V2 一定在所有情况下都更快。
更准确的性能论点是:
- 保持 primary 前台写路径简单:
- 本地顺序
WAL append - 投递到 per-replica sender loop
- 不把复杂恢复逻辑塞进前台写路径
- 本地顺序
- 把复杂度主要放在健康热路径之外:
- sender ownership
- reconnect classification
- catch-up / rebuild decision
- timeout 和 stale-result fencing 主要都在 recovery / control path
- 让 WAL 只承担它擅长的工作:
- 近期 ordered delta
- 短间隙 replay
- 不再让 WAL 承担所有长距离恢复:
- 长间隙恢复转向 checkpoint/snapshot base + tail replay
所以 V2 的性能论点应该是:
- 健康 steady-state 应该尽量接近
V1.5 - 退化与恢复路径会更干净
- 短间隙恢复会比 rebuild 更便宜
- 长间隙恢复不再逼迫系统支付无上限的 WAL retention 税
这比“V2 天然更快”要可信得多。
4.5 为什么仍然选择 WAL
之所以还继续走 WAL,是因为它仍然是解决这个同步问题最有力的基础:
- 显式顺序
- 显式历史
- 显式 committed prefix
- 显式短间隙 replay
- 显式 failover reasoning
只有当设计把以下概念混淆时,WAL 才会变得危险:
- 本地写入接受
- replica durable progress
- committed boundary
- recoverable retained history
而 V2 的存在,正是为了不再混淆这些东西。
5. 与市场和论文路线的比较
选择 V2 这条路线,并不是因为别的 vendor 都错了,而是因为他们解决的是不同问题,也承担了不同复杂度。
Ceph / RBD 路线
Ceph/RBD 避开了这种 per-volume replicated WAL 形态。
它获得的是:
- 对象存储深度一体化
- 成熟的 placement 与 recovery 体系
- 更强的集群级分布能力
但代价是:
- 系统层次更多
- object-store / peering 复杂度更重
- 运维与概念模型更重
所以这不是“更简单”,而是把复杂度迁移到了别处。
对 sw-block 而言,当前选择是:
- 保持更窄的软件块服务模型
- 用更显式的 per-volume correctness 来换取更可控的复杂度
PolarFS / ParallelRaft 路线
这类系统探索更激进的顺序与并行策略:
- conflict-aware 或乱序并行
- 更深的日志并行
- 更复杂的 apply / replay 机制
它们在未来仍然值得借鉴:
- LBA conflict reasoning
- replay 成本与恢复成本
- flusher 并行优化
但它们也明显扩大了正确性边界。
在当前阶段,项目不应该在还没彻底证明严格顺序模型之前,就过早买入这类复杂度。
AWS 链式复制 / EBS 类经验
链式复制之类的路线吸引人,是因为它们能解决真实问题:
- Primary NIC 压力
- forward 拓扑
- RF=3 时更好的扩展性
这是后续较有希望借鉴的方向。
但它会改变:
- 延迟画像
- 失败处理方式
- barrier 语义
- 运维拓扑
所以它属于更后面的架构阶段,而不是当前 V2 核心证明。
当前的真实选择
项目当前选择的是:
- 更窄的软件优先 block 设计
- 明确的 per-volume correctness
- 在性能英雄主义之前先把逻辑讲清
- 在功能扩张之前先建立验证闭环
这不是保守,而是为了让这个 block 产品未来真的值得信任。
6. 为什么这条方向适合 SeaweedFS 与未来独立 sw-block
sw-block 起步于 SeaweedFS,但 V2 已经在按下一代独立 block service 的方向成形。
这意味着架构上要同时保留两类东西:
需要保持兼容的部分
- placement / topology 这些概念
- 可解释的 control-plane contract
- 与 SeaweedFS 生态的运维连续性
应该更 block-specific 的部分
- replication correctness
- recovery ownership
- recoverability classification
- block 特有的 test / evidence 体系
因此当前方向不是“继续把 V2 当成 weed 里的一个 patch”,而是:
- 以 SeaweedFS 作为经验与生态基础
- 同时把
V2逐步塑造成真正独立的块服务架构
7. 系统化验证方法
当前方向之所以合理,另一个重要原因是验证方法本身已经系统化。
项目不再依赖:
- 先实现
- 再观察
- 出 bug 再修
而是依赖如下层次:
- contract / invariants
- scenario backlog
- simulator
- timer/race simulator
- standalone prototype
- real engine test runner
flowchart TD
contract[ContractAndInvariants]
scenarios[ScenarioBacklog]
distsim[distsim]
eventsim[eventsim]
prototype[enginev2Prototype]
runner[RealTestRunner]
confidence[SystemAndProductConfidence]
contract --> scenarios
scenarios --> distsim
scenarios --> eventsim
distsim --> prototype
eventsim --> prototype
prototype --> runner
runner --> confidence
这对于一个高风险块存储算法是非常正确的结构:
- simulation 用来证明协议逻辑
- prototype 用来证明执行语义
- 真实 runner 用来证明系统与产品行为
8. Simulation 系统证明什么
simulation 系统的目标是回答:
- 应该发生什么
- 绝不能发生什么
- 为什么旧设计会失败
- 为什么 V2 更好
distsim
distsim 是主协议仿真器,主要用于:
- 协议正确性
- 状态迁移
- stale authority fencing
- promotion / lineage safety
- catch-up vs rebuild
- changed-address restart
- candidate safety
- reference-state checking
eventsim
eventsim 是时间 / race 层,主要用于:
- barrier timeout
- catch-up timeout
- reservation timeout
- 同 tick / 延迟事件顺序
- stale timeout 的影响
simulation 擅长证明什么
它特别擅长证明:
- stale traffic rejection
- recovery boundary 的显式性
- timeout/race 语义
- committed prefix 下的 failover 正确性
- 旧 authority 不能修改新 lineage
simulation 不证明什么
它不证明:
- 真实 TCP 行为
- 真实 OS 调度
- 磁盘时序
- 真正的
WALShipper集成 - iSCSI / NVMe 前端的真实行为
因此 simulation 不是全部真相。
它是 算法 / 协议真相层。
9. 真实 test runner 证明什么
learn/projects/sw-block/test/ 下的真实 test runner 是系统与产品验证层。
它不只是 QA 工具,而是设计是否可信的重要组成部分。
它覆盖什么
当前 runner 与周边测试体系已经覆盖:
- unit
- component
- integration
- distributed scenario
- 真实硬件 workflow
而且环境已经包含:
- 真实节点
- 真实 block target
- 真实 fault injection
- benchmark 与结果采集
- run bundle 与 scenario traceability
为什么它重要
它帮助我们判断:
- 实际引擎是否按设计运行
- 产品在真实 restart / failover / rejoin 场景下是否可靠
- operator workflow 是否可信
- benchmark 结果是不是有效而非偶然
所以 test runner 最好被理解为:
- implementation truth
- system truth
- product truth
而不只是“测试脚本框架”。
10. Simulation 与 test runner 如何系统性推进
理想的反馈闭环是:
V1/V1.5出现真实故障- 这些故障被转化为设计要求
- 再被提炼为 simulator 场景
- simulator 关闭协议歧义
- standalone prototype 关闭执行歧义
- 真实 test runner 在硬件与分布式环境中验证系统行为
- 新故障或新偏差再反哺设计
这就形成了两类互补真相:
simulation -> algorithm / protocol correctnesstest runner -> implementation / system / product correctness
这种分层是健康的,因为它避免了两种常见错误:
- 只相信设计推导,却没有真实行为
- 只相信系统测试全绿,却没有真正理解协议本身
11. 当前状态与诚实边界
现在已经比较强的部分
V1.5相比V1的恢复能力已经明显增强,并且有真实运行证据V2的架构清晰度已经明显强于V1.5- simulator 已经有较强的 acceptance 覆盖
- prototype 已经开始关闭 ownership 与 orchestration 风险
- 真实 test runner 已经足够大,可以支撑严肃的系统验证
现在还没有完成的部分
V2还不是生产引擎- prototype 仍处于早中期
- historical-data / recovery-boundary prototype 还没有闭合
V2steady-state 性能还没有真实证明V2还没有真实硬件上的运行验证
所以最准确的话不是:
- “V2 现在已经在生产上更强”
而是:
- “V2 是长期更好的架构,但今天还不是更强的已部署引擎”
12. 为什么当前方向是理性的
当前方向之所以理性,是因为它保持了正确的分工:
V1.5继续作为今天的生产线V2继续作为下一代架构线
这样项目就可以:
- 在已有可运行系统上继续交付和加固
- 在不扰动生产线的前提下认真验证更强的架构
- 用 simulation、prototype 和真实 runner 来决定
V2是否真能成为下一代引擎
最终的战略规则应当保持不变:
- 继续研究 WAL,因为现在我们已经有可信的验证框架
- 继续推进 V2,因为架构证据已经很强
- 如果 prototype 证明 V2 有结构性缺陷,就先演进到
V2.5,不要急于重实现
结论
如果按当前生产证据选择:
- 选择
V1.5
如果按长期协议质量选择:
- 选择
V2
如果问 WAL 是否还值得继续研究:
- 值得,因为现在项目已经拥有了足够严肃的验证体系,可以负责任地继续推进
这就是当前最合理的技术与战略判断。