1. 先把问题说对:文件系统不是“磁盘容量的 API”
单机训练时,读取数据和保存模型看起来只是本地文件 I/O;扩展到数百或数千张 GPU 后,共享路径往往先到极限。一个 checkpoint 可能让所有 rank 同时写入,dataset shuffle 可能让所有 worker 随机读取,小文件元数据请求又可能压垮目录服务。即使总磁盘吞吐很高,某一台 metadata server、某一条上行链路或某一块 SSD 的尾延迟也足以停住整个训练 job。
网络化存储包含四个相互耦合的资源池:容量决定能保留多少版本;数据带宽决定连续读写速度;元数据吞吐和一致性决定大量文件或对象能否被正确定位;故障恢复预算决定节点、盘和网络异常时是否还能继续工作。3FS 的系统设计正是围绕高性能 AI 集群中的这组约束展开。
2. 一个分离式存储系统的最小模型
控制面回答“数据在哪里、当前版本是什么、谁有写权限”;数据面负责“把字节搬过去”。两者都不可省略。若每次 4 MiB 读都要同步问一个中心服务,元数据路径会成为带宽前的瓶颈;若客户端绕过控制面直接写盘,则没有版本、租约和故障恢复语义可言。
3. 三个名字容易混淆:文件、对象与 chunk
用户看到的是路径和文件,例如一个 tokenizer shard 或 checkpoint manifest。系统内部常把文件切成固定或变长的 chunk,再把 chunk 映射到多个 storage node。对象系统偏向“key 到不可变 blob”的接口;文件系统还要处理目录、长度、追加、rename 和权限。训练端更关心三件事:读请求能否批量化,写请求能否原子提交,失效 chunk 能否被定位和重建。
| 层 | 典型标识 | 主要职责 | 常见失败 |
|---|---|---|---|
| 命名空间 | path / checkpoint id | 用户可见版本和权限 | rename 或 listing 不一致 |
| 逻辑对象 | file/object id | 长度、generation、manifest | 读到未提交的版本 |
| 数据 chunk | chunk id / stripe id | placement、复制、校验和 | 副本缺失、热点、位腐烂 |
| 物理 I/O | NVMe block / log segment | 排队、持久化、回收 | 写放大、尾延迟、介质故障 |
4. 读路径:从 dataloader 到 GPU,不应每个样本都走一次控制面
一个好的大文件/连续 shard 路径通常是:客户端先解析 manifest,批量取得 chunk location 和有效 epoch,然后把多个范围读合并成少量大请求,数据经 NIC 到达 host pinned buffer、page cache 或 GPU staging 区。若训练格式允许顺序扫描,预取线程可以在 GPU 消费当前 batch 时读取下一个窗口。若格式是大量随机小记录,则需要把索引、缓存和批量读取纳入数据格式设计,否则再快的 RDMA 也会被请求数量淹没。
读路径要区分吞吐与首字节延迟。训练通常愿意用较大的 read-ahead 换吞吐;在线模型冷启动或紧急恢复更关心第一批权重何时可用。把二者放在同一无优先级队列里,常常会出现“训练能跑满,但线上扩容过慢”的假象。
5. 写路径:高吞吐不等于已提交
checkpoint 写入要面对一个基本事实:每个 rank 可能同时产生大块 shard,而恢复器绝不能把“已经写了一半”的目录当成可恢复版本。常见提交顺序是写入不可变数据块,生成 manifest,然后原子发布 committed generation。发布前客户端可以重试数据传输;发布后读取者只接受 manifest 指向的完整对象集合。
这里的“原子”描述命名空间的明确可见边界,各 SSD 无需在同一纳秒完成写入。若发布协议只靠“目录里文件数量看起来够了”,在重试、延迟写、GC 和节点故障下迟早会读到混合版本。
7. RDMA 在存储里解决什么,又不解决什么
RDMA 能让 NIC 在注册后的内存区域间直接移动数据,减少 CPU 协议处理和额外拷贝,因而特别适合大块并发读写、checkpoint 和高速训练数据流。GPUDirect 或 pinned host buffer 可以进一步缩短 GPU 与 NIC 之间的 bounce 路径。但 RDMA 不是“把文件系统变成内存”:仍然需要地址/密钥管理、内存注册、完成队列、流控、拥塞处理、超时、错误重试和数据持久化确认。
必须分开两类完成事件。网络完成只说明字节到达某个 buffer;存储提交才说明它已进入符合系统承诺的副本或持久层。若 checkpoint writer 把前者当成后者,断电或 daemon 崩溃会暴露出尚未持久化的版本。
| 问题 | RDMA 可帮助的部分 | 仍需系统层解决 |
|---|---|---|
| 大块数据拷贝 | 减少 CPU copy、提高并发数据面效率 | request scheduling、目标 SSD 排队 |
| 低延迟 I/O | 缩短协议与拷贝路径 | metadata lookup、tail congestion、持久化 |
| 故障检测 | completion/error 提供信号 | lease、epoch、幂等重试、re-replication |
| 端到端正确性 | 可校验传输完整性 | checksum、generation、commit protocol |
8. 元数据服务:小请求往往比大带宽更先把系统打穿
训练数据若被拆成千万个小文件,启动一个 job 时所有 rank 都可能同时 stat、open、list;这会形成元数据 thundering herd。高性能系统需要缓存不可变 manifest、批量 lookup、层级目录分片、leader/raft 或其他复制协议,并在客户端保留版本 epoch。每个读请求都同步走线性一致性 RPC 当然容易推理,但会牺牲扩展性。
另一方面,缓存又必须有失效语义。客户端拿着旧 chunk location 去读一个已经迁移或重建的副本,不能默默读错版本。常见做法是 metadata 返回 generation/lease/epoch,数据节点检查它是否仍然有效;失效时客户端重新 lookup,而不是无限重试旧地址。
9. 提交、恢复和幂等:三个保证缺一个都会让 checkpoint 不可信
提交(commit)定义可见版本边界;恢复(recovery)定义 crash 后如何从日志、manifest 和副本重建状态;幂等(idempotency)定义超时重试不会产生两个不同对象或重复计费。训练框架在网络超时后必须假设“对方可能已经成功”,因此请求需要稳定 request id、对象 generation 或 compare-and-swap 条件,而不是简单再发一次写。
一个可操作的恢复流程是:扫描未完成事务或临时对象,验证 manifest 所有引用是否存在并满足持久化门槛,把未发布的垃圾留给可审计的 GC;对已发布但副本不足的对象优先 repair。恢复器不要根据文件名猜测状态,应该依据显式 journal 或版本状态机。
10. Checkpoint 的特殊性:它是训练进度协议,不是一次普通文件保存
完整训练恢复往往需要模型参数、optimizer state、梯度缩放器、RNG、dataloader cursor、并行分片描述和训练 step。仅保存权重可以做推理,却不能保证从中断点继续得到同一训练过程。分布式 checkpoint 还要描述哪个 shard 属于哪个 TP/PP/DP rank,未来是否允许换一种并行拓扑恢复。
从系统角度看,应记录 checkpoint 的三个时间:GPU 开始导出状态的时间、数据已达到 durability 门槛的时间、manifest 被发布的时间。前两者决定训练暂停与网络压力,最后一个决定可恢复性。异步 checkpoint 能缩短训练阻塞,但会引入 host staging、后台带宽和“训练已经继续、最新稳定版本仍较旧”的窗口。
11. 训练 checkpoint、模型权重和远程 KV 不是同一类存储对象
它们都可能落到 SSD 或网络服务,但访问语义截然不同。checkpoint 是大、不可变、必须持久且可以秒级恢复的训练状态;模型权重是大、读多写少、适合复制和预热的发布物;远程 KV 是高频、可能短寿命、面向毫秒级首 token 的服务状态。把远程 KV 直接塞进 checkpoint 存储的低优先级 bulk 队列,TTFT 会被后台写入淹没;反过来用昂贵的 KV tier 保存全部 checkpoint,则成本失控。
| 对象 | 正确性要求 | 时延/吞吐重点 | 典型生命周期 |
|---|---|---|---|
| 训练 checkpoint | 完整 generation、可验证恢复 | 高顺序写与可预测恢复 | 分钟到天 |
| 模型权重 | 版本/签名一致、可回滚 | 冷启动带宽、分发扇出 | 小时到周 |
| 远程 KV | owner epoch、block 完整性、可失效 | 低尾延迟读写、热点复用 | 请求到小时 |
| 训练 dataset | 数据版本与访问权限 | 扫描吞吐、随机读放大 | 天到月 |
12. QoS:存储限流必须和网络、NIC、GPU 调度对齐
同一张网卡上,checkpoint 写、dataset read、模型下载和 PD KV 都可能并发。只在应用层说“这个任务低优先级”没有用,若它的 RDMA queue 或交换机队列仍可以塞满链路,就会把 decode 的短流量拖进长队列。至少要定义 traffic class、每租户/作业速率上限、并发 I/O 数、storage-node queue budget 和紧急保留带宽。
观察 QoS 是否生效时,不要只看平均 GB/s。应在 1 ms、10 ms、1 s 多个窗口看 NIC bytes、ECN/CNP、PFC pause、RDMA retry、SSD queue depth 和应用 P99。训练吞吐少了 3%,却换来线上 TTFT P99 不被 checkpoint 扰动,常常是正确的系统交易。
13. 故障模型:盘坏、节点失联、网络分区和控制面卡住不是一件事
- 单盘或单节点丢失:客户端应切到健康副本,后台根据副本/条带策略修复;修复流量本身也需限速。
- 网络分区:不能让两侧都以为自己拥有同一写 lease;写入需要 epoch/leader/fencing,读可在明确版本条件下降级。
- metadata 延迟或失效:已有 lease 的连续读可能暂时继续,但新写、新版本发布和位置迁移必须保守。
- 客户端崩溃:临时对象不能永远占容量,GC 又不能错误删除仍被重试或引用的数据。
- 机架/电源故障:副本若未跨故障域放置,局部灾难会变成不可恢复的数据丢失。
“高可用”要说明对象、命名空间和集群作业各自的语义。某个读可重试,不等于整个训练 step 可无损继续;某个 checkpoint 文件存在,也不等于其 generation 已提交。
14. 可观测性:从一个慢 batch 追到哪一层
排障要有跨层关联 id:训练 step、dataloader batch、file/object、chunk、RPC、NIC QP、storage daemon request 和 SSD queue。没有关联关系,只能分别看到“GPU 空闲”“网络不高”“磁盘偶尔抖动”,无法证明哪一个造成 stall。
| 层 | 关键指标 | 它回答的问题 |
|---|---|---|
| 应用 | data wait、checkpoint wall time、resume time | 训练是否因 I/O 停顿 |
| 客户端 | lookup latency、read size、retries、cache hit | 是否被小请求或旧位置拖慢 |
| 网络 | NIC queue、ECN/CNP、PFC、RDMA completion P99 | 是否出现拥塞或短流排队 |
| 存储节点 | per-disk IOPS、tail latency、write amplification、repair backlog | 是盘、daemon 还是后台修复在限速 |
| 控制面 | leader lag、lease conflict、metadata QPS、publish failures | 版本和路径解析是否成为瓶颈 |
15. 运行手册:先定对象等级,再定物理资源和故障演练
- 为 checkpoint、dataset、weight artifact、远程 KV 建立不同的 SLO、TTL、持久化和 QoS class。
- 测量真实训练 trace:读大小分布、checkpoint fan-out、峰值并发和恢复时间,而不是只跑单客户端带宽测试。
- 把 storage placement 与 GPU/网络 topology inventory 连起来,避免 repair、checkpoint 和 TP/EP 高峰永远撞在同一上行链路。
- 定期演练 node loss、rack loss、metadata failover、半写 checkpoint、客户端重试和网络限速,验证 manifest 不会发布半成品。
- 为 GC、rebuild 和数据迁移设置独立预算;后台工作在容量紧张时最容易反过来放大线上故障。
- 用 P99/P99.9 而非均值签署容量计划,并保留 repair 与热模型扩容的冗余。
16. 2026 的系统含义:存储成为推理与训练的共同控制面
到 2026,模型体积、长上下文、MoE、Agentic RL 和跨池调度使存储不再只为离线训练服务。训练侧需要更快、更可靠的分布式 checkpoint 和数据供给;推理侧需要权重预热、远程 KV、prefix cache 和 PD 传输;控制面还要在集群回收 GPU 时知道哪些状态可丢、可迁、可重建。它们可以共享底层硬件,却不应共享同一种时间尺度和一致性语义。
工程决策最终落在一张资源账本上:哪些对象值得持久化,哪些只需可重建;哪些路径必须低尾延迟,哪些可以被限速;哪些元数据操作必须强一致,哪些可由不可变 manifest 缓存;一次网络或机架故障会让多少 GPU 等待多久。3FS 系列材料把这些跨层问题放回 AI 基础设施的实际约束中,单个带宽数字无法替代这份账本。
17. 具体推演:一次训练回收和在线扩容如何同时触发存储压力
假设夜间一个 64 GPU 训练 job 使用异步 checkpoint,白天流量上涨,调度器需要归还其中 16 GPU 以加载在线副本。调度器不能直接 kill trainer。训练应在安全 step 边界生成 checkpoint;存储系统让每个 rank 写临时 shard,并限速保护在线 KV/TP traffic;manifest 验证并发布后,GPU 才能释放。与此同时,在线权重从 artifact store 预取到目标节点,建立 communicator 并 warmup,副本健康后 router 再开始导流。
若这时遇到某一 storage node 故障,系统要判断它影响的是临时 shard、已发布 checkpoint、权重副本还是短命 KV。前三者的恢复策略不同,后者可能直接失效重算。把所有错误都当“重新下载”会让网络在最需要容量时雪崩;把所有对象都追求强持久又会把毫秒路径拖成秒级事务。
18. 公众号标题级来源映射
以下仅保留文章标题和链接,用于定位阅读来源;本页的技术解释独立编写,未复制这些文章的正文。链接为公开归档页,使用时仍应核对原始发布与版本。
本页所用官方源码图:DeepSeek 3FS chunk-engine architecture asset;其 design notes 用于核对 cluster manager、metadata service、storage service、client 和 RDMA 的整体责任边界。