Storforge
里程碑预计 40 分钟

收官:复盘与下一步

六个阶段走完,盘点你造出的系统和长出的能力;对照 Weka/Ceph/GPFS 的真实差距,规划三条继续深入的路。

学完这节你能做到

  • 完成 forge 1.0 的全量验收清单
  • 写出技术复盘:最难的三个 bug 与最值的三个决策
  • 选定下一步方向:贡献开源存储 / 深入内核 / 造轮子 2.0

forge 1.0:验收清单

六个阶段,五个 crate 长成七个,现在给 forge 打上 1.0 标签。 按你写变更方案的习惯,先列全量验收清单 —— 每一项都是前面某个里程碑的承诺,今天一次性兑付:

编号验收项来源
A1forge-store 万次随机 kill -9,重启全量校验通过里程碑①
A2位翻转注入,读路径报错而非返回脏数据里程碑①
A3forge-bench 单机达 NVMe 标称 IOPS 70% 以上里程碑②
A43 节点 kill 任一节点,读写不中断;kill leader 写恢复小于 2s里程碑③
A5forgefs 挂载后编译任务通过,中途拔节点,产物 checksum 正确里程碑④
A6重建期间业务 P99 受控(限速生效)里程碑④
A7模拟测试:一万种子过夜扫描零失败,决定论 grep 门禁在 CIL5 testing
A8全节点暴露 /metrics,Grafana 大盘三行齐全,三条告警各带 runbookL5 observability
A9三项负载较 L4 基线提升不低于 24%,性能回归 CI 每 PR 生效L5 tuning
A10CI 全绿:fmt、clippy -D warnings、test、bench 对比L0 起累积

有一项不过就不叫 1.0 —— 这是你从运维带来的底线:验收标准写下了就不打折。

全链路 demo:一镜到底

清单是给自己看的,demo 是给别人看的。准备一个 15 分钟、不剪辑、一条命令接一条命令的演示, 从裸盘走到故障演练:

# 1. 格式化三个节点的盘并起集群
forge-cli mkfs /dev/nvme1n1 --node-id 0        # 每节点执行
forge-node --config node0.toml &               # 三节点起服务
forge-cli cluster status                       # 三节点 alive,Raft 有 leader

# 2. 建文件系统并挂载
forge-cli fs create demo --stripe 4+2
forge-fuse mount demo /mnt/forge

# 3. 真实负载:在 forgefs 上编译一个项目
git clone <某个中型 C 项目> /mnt/forge/src && make -C /mnt/forge/src -j16 &

# 4. 编译到一半,当着观众 kill 一个数据节点
kill -9 $(pgrep -f node2.toml)
# Grafana 上看:错误率不动,P99 短暂上抬,重建 backlog 开始下降

# 5. 编译完成,校验产物;节点回归,重建收敛
sha256sum /mnt/forge/src/build/*   # 与本地盘编译产物一致
forge-node --config node2.toml &   # 大盘上看 backlog 归零

一镜到底的意义在于没有藏起来的步骤。你看过太多「精心剪辑」的产品 demo, 自己的 1.0 不许这样。录屏存档,连同验收清单的执行记录一起进仓库 —— 这就是发布材料。

诚实对照表:forge 与真实系统的差距

吹嘘毁掉复盘的价值。对照 L0 第一课的那张表,现在你有资格把每一格填上「差多少、为什么」:

维度forge 1.0WekaCephGPFS
4k 随机写(单客户端)5 万级 IOPS数十万级,SPDK + DPDK + 独占核万级,走内核栈十万级,内核客户端
元数据扩展按 inode 哈希分片,粗粒度64k bucket,细粒度可搬迁多活 MDS,目录子树/哈希分布式 token,锁开销大
客户端路径FUSE,天花板明显自研,绕内核内核 CephFS 客户端内核模块
崩溃一致性验证模拟测试 + 故障注入厂商内部体系Teuthology 集群测试数十年生产打磨
快照/配额/分层/多协议无全有全有全有
生产就绪否,教学系统是是是

看清三件事。第一,机制上 forge 没有缺课:条带 EC、日志聚合、分片元数据、 Raft 共识、声明式重建,每个核心机制都是你定的规格、你验的收 —— 这正是当初砍范围时保住的东西。 第二,量级差距来自工程深度:SPDK 对 io_uring、内核客户端对 FUSE、 64k bucket 对粗分片,每一档你都知道贵在哪,因为你在里程碑数据里见过这一档的墙。 第三,没做的功能是真没做:快照的写时复制、配额的分布式计数,都是再来一个 L 级阶段的工作量。

Checkpoint单选

forge 的 4k 随机写比 Weka 差了近一个量级。按这一路的里程碑数据,差距的大头在哪?

复盘:三个 bug 与三个决策

翻开这一路的 commit 和事故记录,按「最难的三个 bug、最值的三个决策」写复盘。 你的清单会不同,但大概率逃不出这几类:

最难的三个 bug(参考样本):WAL 恢复截断算错半条记录,dm-flakey 断电测试抓到, 根因是长度前缀写入与 crc 写入之间的 torn write —— 落盘顺序这种事,AI 第一版就是想不全; rename 跨分片两阶段协议在协调者崩溃时留下孤儿 dentry,模拟测试种子扫描抓到; 重启节点拿旧放置表返回 stale 读,也是种子扫描抓到。注意规律:三个里有两个是模拟测试抓的, 且都抓在上线前 —— 先建测试体系的钱在这里赚回来了。

最值的三个决策(参考样本):L0 就要求把存储与网络先抽成接口再动实现,L5 接模拟运行时时业务代码几乎零改动; 接口冻结纪律(L1 冻 BlobStore,L3 冻协议),让六个阶段没有一次伤筋动骨的返工; 自研 forge-bench 而不是只用 fio —— 它后来成了调优标尺和回归 CI 的地基,一件工具吃三个阶段。

毕业标准:三问

你的毕业标准从来不是「能独立写 Rust」,而是能独立完成规格与验收 —— 代码交给 AI, 判断力归你。 判断力没法靠代码行数证明,只能靠三问,而且每一问都要有当场能演示的答案:

  1. 你能不能把它弄坏? 说得出三种让 forge 出错的手法,并且现在、当着人,演示一次。 拔盘、丢写、分区、满盘、位翻转,你手里的刑具全在这门课里练过。 弄不坏通常不代表它结实,只代表你还没找到怎么弄 —— 这一问是防你自满的。
  2. 坏了你能不能定位到原因? 从现象出发,经过大盘、日志、盘上字节, 最终落到某个具体的落盘顺序或某条被违反的不变量,说得出「是哪一步崩在哪一步之后」。 这一问最像你的老本行,只是终点从「重启大法」换成了根因。
  3. 每个设计决策你能不能说清为什么这么定? EC 为什么是 4+2、元数据为什么按 inode 哈希分片、 group commit 为什么值得让每个请求多等一小会儿 —— 每条都要给得出当时的取舍和它的代价。 唯一不合格的答案是「AI 是这么写的」。

三问都答得上,这套系统才真是你的。答不上哪一条,回去把那一条补上 —— 这比打 1.0 标签重要得多。

✓复盘的另一半:你的能力面板

盘点系统,也盘点自己。六个阶段前你会看 iostat、懂故障域;现在你还能:读懂一段落盘代码 并说清它为什么必须这么落、给分布式系统定测试与可观测体系的规格、拿火焰图做有据可查的调优 —— 同时保留着运维的验收本能和故障直觉。「既懂怎么运维、又懂怎么实现」的复合视角, 在存储圈是稀缺品:排障时你能从现象直接推到代码层,选型时你能看穿白皮书的修辞。

下一步:三条路

forge 1.0 是毕业作品,不是终点。三条路都通,选让你眼睛发亮的那条:

  1. 贡献开源存储:你已经用过 openraft,它的 issue 区就是入口;Ceph 的下一代 OSD crimson(Seastar 框架,和 Weka 同款 shared-nothing 独占核思路)长期缺人; 曾经「不敢看源码」的项目,现在是你的主场。从修一个测试、复现一个 issue 开始。
  2. 深入内核与硬件:io_uring 再往下是 SPDK 用户态驱动、ublk、NVMe-oF; forge 的 Drive 层可以真的换成 SPDK,把那 30% 的差距亲手抹掉一半。
  3. 造轮子 2.0:带着复盘清单重新设计 —— 这次从第一天就上模拟测试, 元数据做成真正可搬迁的细粒度 bucket,客户端试试 ublk 绕开 FUSE。 第二遍造轮子的速度会让你自己吃惊。
⚡AI 结对:执行 1.0 验收并生成发布材料pair with ai

这一次你是验收方,AI 是执行方 —— 角色和 L0 第一课完全一致,区别是那时候你还不知道该问什么。 别去逐行读它生成的脚本,改成盯两件事:第一,有没有宽松断言 —— 超时给得过长、校验只抽样、失败被悄悄跳过;第二,每个阈值的来历能不能追到某一课的里程碑数字。 验收脚本放水,1.0 就是自欺,而且是只骗得过自己的那一种。 然后做最要紧的一件事:亲手把某一项弄坏,看脚本红不红。红了,这十项验收才算成立; 红不了,你手里这份 PASS 什么都不证明。

目标:forge 要打 1.0 标签,陪我把发布验收走完。分工和 L0 第一课一样 —— 我是验收方,你是执行方;区别是这一次清单和阈值由我定,你负责给证据。

行为规格:
1. 先通读仓库,对照下面这份清单逐项给出状态,只有三种取值:通过、不通过、缺证据。「缺证据」是独立一档,不许把「代码看起来做了这件事」记成通过。清单:万次随机 kill -9 后全量校验通过;位翻转注入时读路径报错而不是返回脏数据;单机吞吐达到 NVMe 标称 IOPS 的 70% 以上;3 节点集群拔掉任一节点读写不中断,拔掉 leader 后写恢复不超过 2 秒;forgefs 挂载后编译任务在中途拔节点的情况下产物校验和仍然正确;重建期间业务 P99 被限速控制住;一万个种子的模拟测试过夜扫描零失败;全节点暴露 /metrics、三条告警各自带 runbook;三项负载相比 L4 基线提升不低于 24%;CI 全绿;
2. 每一项的状态后面必须附证据:哪个脚本、哪次运行的哪段输出、哪个文件的哪一节。拿不出证据的一律记「缺证据」;
3. 生成 scripts/release-acceptance.sh,把可自动化的项串成一键脚本:每项打印 PASS 或 FAIL,附上证据文件路径;任何一项 FAIL,整个脚本退出码非 0。不许有「这项先跳过、继续往下报成功」的逻辑,也不许靠放宽超时或降低抽样比例来凑绿;
4. 所有判定阈值(70%、2 秒、24%、种子个数)写成脚本顶部的变量,每个变量旁边注明它出自哪个里程碑 —— 阈值来历不清,验收就可以被随便改;
5. 不能自动化的项(录屏 demo、runbook 的可读性)在脚本末尾打印人工检查清单,并说明它们为什么没法自动化;
6. 生成 CHANGELOG.md 的 1.0 段落:按 L1 到 L5 分组列主要能力,措辞克制、不写形容词,每条后面附对应的验收项编号;
7. 生成 docs/limitations.md:逐条列已知限制(FUSE 的性能天花板、没有快照与配额、元数据分片粒度粗、只支持单一 EC 配置等),每条注明它是有意取舍还是没做完,以及不做它的代价具体是什么;
8. 最后给我一份「你替我做的判断」清单:哪些项是你按证据判的,哪些是你读代码推测的 —— 后者我要亲手再验一遍。

交付:逐项验收状态表(含证据路径)+ scripts/release-acceptance.sh + CHANGELOG.md 的 1.0 段落 + docs/limitations.md + 那份推测清单。(脚本用什么写、证据文件怎么组织你定,最后告诉我为什么这么选。)
你的验收动作自己跑、自己看,不用读代码
  • 亲手跑一遍 release-acceptance.sh 并把输出留档;然后挑一项故意破坏(临时注掉一处刷盘、或把某个基线数据文件改坏),确认这一项真的变成 FAIL、整个脚本退出码非 0 —— 全绿的验收脚本必须先证明过自己会红
  • 逐条核对脚本顶部的阈值变量和课文里的里程碑数字,一处对不上就是验收在给自己放水;顺手看有没有哪项的超时长得离谱、或者校验只抽了个样
  • 挑两项 AI 判成「通过」的,不看它的结论,自己重跑一遍证据里那条命令,看结果对不对得上
  • 把所有「缺证据」的项单独拉出来:每项要么补上证据,要么写进 docs/limitations.md,一项都不许悬着进 1.0
  • 按毕业三问自测一遍:当着人演示一次把 forge 弄坏,然后只靠大盘、日志和盘上字节定位到根因 —— 中途需要回头翻代码才能说清哪一步的,就是还没到位
必须问到听懂的问题答不上来就别合并
  • 这份脚本全绿之后,还有哪几类问题它照样查不出来?
  • 如果验收在别人机器上失败、在我这里通过,你会按什么顺序排查?
  • 十项里哪一项的阈值最经不起推敲?为什么是它?
  • 假设明天有人拿 forge 上生产,最先出事的会是哪一块?你凭什么这么判断?

小结

  • forge 1.0 = 十项验收全过 + 一镜到底的全链路 demo,录屏和执行记录就是发布材料
  • 对照表要诚实:机制上没缺课,量级差距来自 SPDK/DPDK/内核客户端这些「做到头」的工程, 没做的功能就是没做
  • 复盘两份清单:最难的 bug 多数被模拟测试抓获,最值的决策都是早期的接口与测试投资
  • 毕业标准是三问:弄得坏、定得位、说得清 —— 代码可以交给 AI,判断力不行
  • 你的增量不只是一个系统,是「运维 + 研发」的复合视角:从现象推到代码,从白皮书看穿实现
  • 三条路 —— 贡献 openraft/crimson、深入 SPDK 与内核、造轮子 2.0; 这门课到此结束,你的存储生涯翻到了新的一页
这是整条路线的最后一节 🎉