收官:复盘与下一步
六个阶段走完,盘点你造出的系统和长出的能力;对照 Weka/Ceph/GPFS 的真实差距,规划三条继续深入的路。
学完这节你能做到
- 完成 forge 1.0 的全量验收清单
- 写出技术复盘:最难的三个 bug 与最值的三个决策
- 选定下一步方向:贡献开源存储 / 深入内核 / 造轮子 2.0
forge 1.0:验收清单
六个阶段,五个 crate 长成七个,现在给 forge 打上 1.0 标签。 按你写变更方案的习惯,先列全量验收清单 —— 每一项都是前面某个里程碑的承诺,今天一次性兑付:
| 编号 | 验收项 | 来源 |
|---|---|---|
| A1 | forge-store 万次随机 kill -9,重启全量校验通过 | 里程碑① |
| A2 | 位翻转注入,读路径报错而非返回脏数据 | 里程碑① |
| A3 | forge-bench 单机达 NVMe 标称 IOPS 70% 以上 | 里程碑② |
| A4 | 3 节点 kill 任一节点,读写不中断;kill leader 写恢复小于 2s | 里程碑③ |
| A5 | forgefs 挂载后编译任务通过,中途拔节点,产物 checksum 正确 | 里程碑④ |
| A6 | 重建期间业务 P99 受控(限速生效) | 里程碑④ |
| A7 | 模拟测试:一万种子过夜扫描零失败,决定论 grep 门禁在 CI | L5 testing |
| A8 | 全节点暴露 /metrics,Grafana 大盘三行齐全,三条告警各带 runbook | L5 observability |
| A9 | 三项负载较 L4 基线提升不低于 24%,性能回归 CI 每 PR 生效 | L5 tuning |
| A10 | CI 全绿: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.0 | Weka | Ceph | GPFS |
|---|---|---|---|---|
| 4k 随机写(单客户端) | 5 万级 IOPS | 数十万级,SPDK + DPDK + 独占核 | 万级,走内核栈 | 十万级,内核客户端 |
| 元数据扩展 | 按 inode 哈希分片,粗粒度 | 64k bucket,细粒度可搬迁 | 多活 MDS,目录子树/哈希 | 分布式 token,锁开销大 |
| 客户端路径 | FUSE,天花板明显 | 自研,绕内核 | 内核 CephFS 客户端 | 内核模块 |
| 崩溃一致性验证 | 模拟测试 + 故障注入 | 厂商内部体系 | Teuthology 集群测试 | 数十年生产打磨 |
| 快照/配额/分层/多协议 | 无 | 全有 | 全有 | 全有 |
| 生产就绪 | 否,教学系统 | 是 | 是 | 是 |
看清三件事。第一,机制上 forge 没有缺课:条带 EC、日志聚合、分片元数据、 Raft 共识、声明式重建,每个核心机制都是你定的规格、你验的收 —— 这正是当初砍范围时保住的东西。 第二,量级差距来自工程深度:SPDK 对 io_uring、内核客户端对 FUSE、 64k bucket 对粗分片,每一档你都知道贵在哪,因为你在里程碑数据里见过这一档的墙。 第三,没做的功能是真没做:快照的写时复制、配额的分布式计数,都是再来一个 L 级阶段的工作量。
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, 判断力归你。 判断力没法靠代码行数证明,只能靠三问,而且每一问都要有当场能演示的答案:
- 你能不能把它弄坏? 说得出三种让 forge 出错的手法,并且现在、当着人,演示一次。 拔盘、丢写、分区、满盘、位翻转,你手里的刑具全在这门课里练过。 弄不坏通常不代表它结实,只代表你还没找到怎么弄 —— 这一问是防你自满的。
- 坏了你能不能定位到原因? 从现象出发,经过大盘、日志、盘上字节, 最终落到某个具体的落盘顺序或某条被违反的不变量,说得出「是哪一步崩在哪一步之后」。 这一问最像你的老本行,只是终点从「重启大法」换成了根因。
- 每个设计决策你能不能说清为什么这么定? EC 为什么是 4+2、元数据为什么按 inode 哈希分片、 group commit 为什么值得让每个请求多等一小会儿 —— 每条都要给得出当时的取舍和它的代价。 唯一不合格的答案是「AI 是这么写的」。
三问都答得上,这套系统才真是你的。答不上哪一条,回去把那一条补上 —— 这比打 1.0 标签重要得多。
盘点系统,也盘点自己。六个阶段前你会看 iostat、懂故障域;现在你还能:读懂一段落盘代码 并说清它为什么必须这么落、给分布式系统定测试与可观测体系的规格、拿火焰图做有据可查的调优 —— 同时保留着运维的验收本能和故障直觉。「既懂怎么运维、又懂怎么实现」的复合视角, 在存储圈是稀缺品:排障时你能从现象直接推到代码层,选型时你能看穿白皮书的修辞。
下一步:三条路
forge 1.0 是毕业作品,不是终点。三条路都通,选让你眼睛发亮的那条:
- 贡献开源存储:你已经用过 openraft,它的 issue 区就是入口;Ceph 的下一代 OSD crimson(Seastar 框架,和 Weka 同款 shared-nothing 独占核思路)长期缺人; 曾经「不敢看源码」的项目,现在是你的主场。从修一个测试、复现一个 issue 开始。
- 深入内核与硬件:io_uring 再往下是 SPDK 用户态驱动、ublk、NVMe-oF; forge 的 Drive 层可以真的换成 SPDK,把那 30% 的差距亲手抹掉一半。
- 造轮子 2.0:带着复盘清单重新设计 —— 这次从第一天就上模拟测试, 元数据做成真正可搬迁的细粒度 bucket,客户端试试 ublk 绕开 FUSE。 第二遍造轮子的速度会让你自己吃惊。
这一次你是验收方,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; 这门课到此结束,你的存储生涯翻到了新的一页