Files
seaweedfs/sw-block/design/v2-algorithm-overview.zh.md
T
pingqiuandClaude Opus 4.6 46ef79ce35 fix: stable ServerID in assignments, fail-closed on missing identity, wire into ProcessAssignments
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>
2026-03-31 10:46:17 -07:00

661 lines
18 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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 真正要解决的问题
从前端看,块存储似乎只有几个简单动作:
- `write`
- `flush` / `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-up` vs `rebuild` 更清楚了,但还不够成为协议顶层契约
- 整体感觉仍然更像“继续修 V1”,而不是“定义下一代复制协议”
### `V2` 的变化
`V2` 不是重新发明一个完全不同的存储模型。
它的目标是把最关键的东西显式化:
- recovery ownership
- lineage-safe recovery boundary
- `catch-up` / `rebuild` 分类
- per-replica sender authority
- stale-result rejection
- 明确的 recovery orchestration
因此最诚实的比较是:
- `V1.5` 今天在运行证据上更强
- `V2` 今天在架构质量上更强
这不是矛盾,而是“当前生产线”和“下一代架构线”应有的分工。
```mermaid
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 同步模型是:
1. primary 分配单调递增的 `LSN`
2. primary 本地顺序追加 `WAL`
3. primary 把记录放入 per-replica sender loop
4. replica 按顺序接收并推进显式 progress
5. `barrier/sync` 依赖 replica 的 durable progress,而不是 optimistic send progress
6. flusher 再把 WAL-backed dirty state 物化到 extent
本地 `WAL -> extent` 生命周期可以理解为:
```mermaid
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 都要在目标边界上 durable
- `sync_quorum`:必须存在真实 durable quorum
其判断路径可以表示为:
```mermaid
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
```mermaid
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 如何系统性推进
理想的反馈闭环是:
1. `V1` / `V1.5` 出现真实故障
2. 这些故障被转化为设计要求
3. 再被提炼为 simulator 场景
4. simulator 关闭协议歧义
5. standalone prototype 关闭执行歧义
6. 真实 test runner 在硬件与分布式环境中验证系统行为
7. 新故障或新偏差再反哺设计
这就形成了两类互补真相:
- `simulation -> algorithm / protocol correctness`
- `test 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 还没有闭合
- `V2` steady-state 性能还没有真实证明
- `V2` 还没有真实硬件上的运行验证
所以最准确的话不是:
- “V2 现在已经在生产上更强”
而是:
- “V2 是长期更好的架构,但今天还不是更强的已部署引擎”
## 12. 为什么当前方向是理性的
当前方向之所以理性,是因为它保持了正确的分工:
- `V1.5` 继续作为今天的生产线
- `V2` 继续作为下一代架构线
这样项目就可以:
- 在已有可运行系统上继续交付和加固
- 在不扰动生产线的前提下认真验证更强的架构
- 用 simulation、prototype 和真实 runner 来决定 `V2` 是否真能成为下一代引擎
最终的战略规则应当保持不变:
- 继续研究 WAL,因为现在我们已经有可信的验证框架
- 继续推进 V2,因为架构证据已经很强
- 如果 prototype 证明 V2 有结构性缺陷,就先演进到 `V2.5`,不要急于重实现
## 结论
如果按当前生产证据选择:
- 选择 `V1.5`
如果按长期协议质量选择:
- 选择 `V2`
如果问 WAL 是否还值得继续研究:
- 值得,因为现在项目已经拥有了足够严肃的验证体系,可以负责任地继续推进
这就是当前最合理的技术与战略判断。