分布式存储物理学:对象存储、POSIX 并行文件系统与 Checkpoint 存储风暴
一句话结论:对象存储(S3/OSS)以「扁平命名空间 + HTTP REST + 最终一致性」换取近乎无限的水平扩展与极低的单位容量成本;POSIX 并行文件系统(Lustre/GPFS/CephFS/JuiceFS)以「共享存储集群 + 元数据/数据分离 + 细粒度锁」换取微秒级延迟与聚合 TB/s 带宽。
这两套物理规律的碰撞,在大模型训练数百台机器同时写入 500GB Checkpoint 的瞬间被推向极限。
本文分两部分:上半场讲存储范式(对象存储原理 → 四类并行文件系统架构对比 → Checkpoint 风暴的成因与缓解),下半场落到工程(万卡集群如何设计异步保存,把对训练的影响压进 1%)。
所有架构描述核对自各系统官方文档与原始论文,性能数字核对自一手来源。核对中发现原稿有二十余处需要更正,其中两处是整段数字错误,已在文中以 ⚠️ 标注。
上半场:三种存储范式的物理学
一、对象存储:HTTP 语义构建的「无限货架」
1.1 扁平命名空间与 REST 接口
与文件系统「目录树 + inode」的层次化模型不同,对象存储把整个存储池抽象为 Bucket + Object Key 两级扁平结构:Bucket 是顶层容器,Object Key 是一个任意长度的字符串,整个系统没有「目录」概念——所谓「目录」只是 key 前缀的约定俗成。
所有操作通过 HTTP REST 接口完成,以 AWS S3 为事实标准:
| 操作 | API |
|---|---|
| 写入对象 | PUT /bucket/key |
| 读取对象 | GET /bucket/key |
| 删除对象 | DELETE /bucket/key |
| 前缀列举 | GET /bucket?list-type=2&prefix=xxx |
鉴权通过 HTTP Header 的 Authorization 签名实现——SigV4 用 AWS4-HMAC-SHA256,即 HMAC-SHA256 派生签名密钥。
这种「每次操作都是一次完整 HTTP 往返」的设计,天然带来每次请求至少一次 TCP/TLS 握手、一次 HTTP 编解码、一次服务端路由的开销——这是对象存储高延迟的根本来源。
1.2 Multipart Upload:用并发换吞吐
由于单次 PUT 有上限、且大对象传输极易中途失败,S3 用 Multipart Upload 支撑超大对象:
| 参数 | 限制 |
|---|---|
| 单个对象最大 | 50 TB(实际上限 48.8 TiB) |
| Parts 数量 | 1 — 10,000 |
| 单个 Part 大小 | 5 MiB — 5 GiB(最后一个 Part 可更小) |
| 单次 PUT 上限 | 5 GB |
⚠️ 一处已过时:原稿写「单个对象最大 5 TB」。这是旧值——AWS 官方 FAQ 现在写的是 Maximum object size 48.8 TiB,并说明「documentation commonly references 50 TB object size limit, the actual maximum object size is 53.7 TB (48.8 TiB)」,由 multipart 约束推出(10,000 parts × 5 GiB)。
工作流程三步:
- Initiate ——
CreateMultipartUpload(POST /key?uploads),服务端返回uploadId; - Upload Parts —— 客户端把大文件切成 N 个 Part,并发地
PUT /key?partNumber=i&uploadId=xxx;Part 之间完全独立、可乱序、可失败重传; - Complete ——
POST /key?uploadId=xxx,携带<PartNumber, ETag>列表,服务端按序拼接。
关键在于 Parts 彼此独立,可被路由到不同存储服务器并行写入——尽管单个 HTTP 请求延迟数十毫秒,但把大对象切成几十甚至上千个 Part 并行上传,聚合吞吐可以线性扩展至网络带宽上限。
这正是对象存储「高延迟但高吞吐」悖论的技术根源:它不擅长低延迟,但极度擅长并行。
未完成或未 Abort 的 Multipart Upload 会在 S3 中留下「僵尸 Parts」,持续占用存储并计费——AWS 官方原文:
After you initiate a multipart upload and upload one or more parts, you must either complete or stop the multipart upload to stop incurring charges for storage of the uploaded parts.
生产系统通常配合生命周期规则自动清理。
1.3 高延迟劣势与语义缺失
| 存储 | 延迟量级 |
|---|---|
| JuiceFS 命中本地缓存 | 0.05 — 0.1 ms |
| JuiceFS 命中分布式缓存(企业版) | 0.1 — 0.2 ms |
| JuiceFS 穿透到对象存储 | 30 — 50 ms 以上 |
| 对象存储 TTFB | 数十毫秒量级 |
✅ 前三行逐字来自 JuiceFS 官方博客(“When hitting the local cache, latency is between 0.05 and 0.1 milliseconds” / “ranges from 0.1 to 0.2 milliseconds” / “Directly reading from object storage incurs latency above 30 to 50 milliseconds”)。
⚠️ 但另外两个数字找不到一手来源:原稿写「对象存储 TTFB 通常 20—100 毫秒」「本地 NVMe 随机读延迟 ~100µs」「Lustre/GPFS 在 RDMA/InfiniBand 加持下亚毫秒级」——这三条我在 AWS 官方文档、NVMe 厂商文档、Lustre 官方手册里都没找到可引用的基准。方向可信,但引用时宜标为量级参考而非规格。
对象存储不支持 POSIX 语义:没有 mmap、没有 fsync、没有文件锁、没有 append(需重写整个对象)、没有原子 rename,元数据(通过 HTTP Header 携带)也非常有限。
因此对象存储天然不适合海量小文件随机读——一次百万级小文件遍历会被每次数十毫秒的 HTTP 延迟拖垮;但它极适合大对象的顺序吞吐。
一句话:对象存储的物理学是「用延迟换扩展性、用 HTTP 换运维简单性」——单次访问永远不快,但并发可以无限加。
二、POSIX 并行文件系统:为共享与一致性而生
当上百台计算节点需要同时读写同一份数据、且要求 POSIX 语义时,就必须引入并行文件系统。核心物理问题只有一个:如何让多台机器在共享命名空间下不互相踩踏。
2.1 Lustre:HPC 超算的事实标准
Lustre 的架构由四类组件构成:
| 组件 | 职责 |
|---|---|
| MGS(Management Server) | 存储整个文件系统的配置信息(OST 列表、网络拓扑),是集群的「配置中心」 |
| MDS(Metadata Server) | namespace 操作(open/close/stat/rename),维护 inode 与目录结构 |
| OSS(Object Storage Server) | 数据服务器,每台管理多个 OST(Object Storage Target),一个 OST 对应一组后端磁盘 |
| Client + LNet | 计算节点内核客户端,通过 LNet 网络层(IB/RoCE/TCP)与 MDS/OSS 通信 |
关键设计是「元数据与数据分离」:所有 namespace 操作走 MDS,而文件数据 I/O 由 Client 直接与多个 OSS 上的 OST 交互,绕过任何中心瓶颈。文件写入时被条带化(striping) 切分到多个 OST,客户端并行读写,聚合带宽随 OST 数量线性扩展。
✅ 一处细节原稿写对了:MGS 是独立逻辑组件,但通常与 MDS 同机部署。Lustre 官方手册原文:「It is preferable that the MGS have its own storage space… However, the MGS can be co-located and share storage space with an MDS」。
物理限制:元数据全部落在磁盘、依赖内存缓存加速,文件数超过数亿时 MDS 内存与单点性能成为瓶颈;小文件 I/O 是它的弱项。
2.2 GPFS(IBM Spectrum Scale):商用的「全能选手」
-
Token-based 分布式锁管理器 —— GPFS 不依赖中心锁服务器,持有 token 的节点可在本地缓存执行锁操作,只有冲突时才升级到全局协商。FAST 2002 论文原文:
The global lock manager coordinates locks between local lock managers by handing out lock tokens… Once a node has obtained the token from the global lock manager, subsequent operations issued on the same node can acquire a lock on the same object without requiring additional messages. Only when an operation on another node requires a conflicting lock on the same object are additional messages necessary to revoke the lock token.
这种设计在「不同节点访问不同数据」时并行度极高,但在「大量节点竞争同一批元数据」时反而不如集中式管理。
-
NSD(Network Shared Disk) —— 所有磁盘被抽象为 NSD,可被多台节点通过 SAN 直接访问(Shared-Disk 模式)。
-
文件系统层复制 —— 支持在文件系统层面做数据多副本,allowable values 1/2/3,默认 1;max replicas 默认 2。即使一台服务器宕机,文件系统仍可继续服务。
-
存储池(Storage Pools) —— 可将不同性能/成本的磁盘划分为不同 pool,配合策略实现冷热分层。
2.3 CephFS:统一存储栈的「瑞士军刀」
Ceph 在 RADOS 这一分布式对象存储基座之上,同时提供 RGW(S3 兼容)、RBD(块设备)和 CephFS(POSIX 文件系统) 三种接口。
-
数据直接读写 RADOS —— 官方原文:
CRUSH allows Ceph clients to communicate with OSDs directly rather than through a centralized server or broker.
All file data in CephFS is stored as RADOS objects. CephFS clients can directly access RADOS to operate on file data. MDS only handles metadata operations.
-
MDS 集群管理元数据 —— 元数据存储在独立的 RADOS Pool(
ceph fs new <name> <metadata pool> <data pool>),使用 OMAP 结构(官方文档:“Open file table is stored in omap of RADOS objects”),由可动态扩缩的 MDS 集群提供服务。 -
强一致 + 可调副本/EC —— 通过多副本或纠删码保证可靠性,CRUSH 保证数据分布均匀与故障域隔离。
物理劣势:所有 I/O 都要经过 RADOS 的 PG 协商,小文件延迟高于 Lustre;元数据性能在超大规模时仍受制于 MDS 集群规模。
2.4 JuiceFS:云原生时代的「元数据/数据解耦」
JuiceFS 走了一条与前述系统截然不同的路线——把「元数据引擎」与「数据存储」彻底解耦:
-
数据层 —— 全部持久化在对象存储上,文件切分为 Chunk(默认 64 MiB)→ Slice(变长)→ Block(默认 4 MiB) 三级结构。官方原文:
each file is composed of one or more chunks. Each chunk has a maximum size of 64 MB… slices are further split into individual blocks (default maximum size of 4 MB) to enable multi-threaded concurrent writes
-
元数据层 —— 由独立的元数据引擎承载。社区版支持 Redis、TiKV、Badger(KV 类)与 SQLite、MySQL、PostgreSQL(关系类),另有 etcd;企业版使用自研全内存元数据引擎:
JuiceFS Enterprise Edition provides a custom-built, fully in-memory metadata engine that ensures an average metadata request processing time of around 100 microseconds, even when managing massive file counts.
support hundreds of billions of files in a single volume
-
客户端 —— FUSE 挂载,完整 POSIX 兼容;通过多级缓存弥补对象存储的高延迟。
-
云原生 —— 原生 CSI Driver 支持,支持跨云/多区域镜像文件系统。
注意一个措辞差异:JuiceFS 官网简介页写的是保守的 “millisecond-level metadata latency”,而官方博客明确给出 100 µs。引用时宜注明出处。
JuiceFS 的完整架构(三平面分离、多级缓存体系、K8s 挂载模式、Checkpoint 落地纪律)见 具身智能训练存储与数据管线:JuiceFS + Lance 深度实践。
2.5 四类并行文件系统横向对比
| 维度 | Lustre | GPFS (Spectrum Scale) | CephFS | JuiceFS |
|---|---|---|---|---|
| 开源/商业 | 开源(GPL) | 商业(IBM) | 开源(LGPL) | 社区版开源 / 企业版商业 |
| 元数据架构 | 独立 MDS(active/standby),磁盘存储 | 分布式 Token 锁,NSD 共享磁盘 | 可扩缩 MDS 集群,元数据存于 RADOS Pool | 独立元数据引擎(Redis/TiKV/自研内存引擎) |
| 数据存储 | OST(XFS 后端) | NSD(多种磁盘) | RADOS(副本/EC) | 对象存储(S3/OSS/GCS…) |
| 一致性模型 | 强一致(POSIX) | Token 锁强一致 | 强一致(RADOS) | 强一致(元数据事务) |
| 海量小文件 | 弱(MDS 内存瓶颈) | 中等 | 中等 | 强(百亿文件) |
| 跨云/多云 | 无原生支持 | 无原生支持 | 无原生支持 | 原生镜像文件系统 |
| 云原生/K8s | 弱 | 弱 | 中等 | CSI Driver 原生支持 |
| 典型场景 | HPC 超算、LLM 训练热层 | 科研 + 企业关键业务、AI | 统一存储栈(对象+块+文件) | 云原生 AI、数据湖、跨云训练 |
三、Checkpoint 存储风暴
3.1 风暴的物理成因
Checkpoint 的写入模式是所有存储系统最噩梦般的组合:
- 体量巨大 —— 一个 350—500 GB 的 Checkpoint,约为模型参数量的数倍;
- 瞬间爆发 —— 数百台机器上的数千个进程几乎在同一秒开始写入,每个进程写一个独立分片文件(DeepSpeed/Megatron 默认 per-rank 一文件),单次 Checkpoint 可产生数百到数千个独立文件;
- 元数据风暴 —— 数万文件的创建、打开、关闭、rename 让 MDS/元数据引擎瞬间过载;
- POSIX 缓存放大 —— 默认 buffered I/O 会在计算节点 DRAM 与文件系统缓存之间引入冗余拷贝。
⚠️ 两处数字要改:
第一处(口径明显偏低):原稿写「175B 模型 FP16 权重约 350 GB,加上 Adam 优化器状态可达 1TB+」。按 ZeRO 论文的标准口径,混合精度 + Adam 是 16 bytes/参数(fp16 参数 2 + fp16 梯度 2 + fp32 master weight 4 + 动量 m 4 + 方差 v 4),所以 175B × 16 = 约 2.8 TB——原稿的「1TB+」明显低估。ZeRO 论文原文:
Mixed-precision Adam has K = 12. In total, this results in 2Ψ + 2Ψ + KΨ = 16Ψ bytes of memory requirement.
training a 1 trillion parameter model with mixed precision requires approximately 16 terabytes (TB) of memory第二处(无一手来源):原稿写「研究表明,元数据相关操作占文件系统总操作的 60% 以上」。找不到逐字写 “>60%” 的一手来源。文献里的实际数字是**「最高 80%」(综述)与「实测 67%—96%」**(EuroSys’23 的 CFS 论文,转引自 SwitchFS)——方向对,但引用宜用后两个。
物理后果:当数百台机器同时向同一共享存储倾泻 500 GB 数据时,后端的元数据服务器、网络交换、磁盘带宽会在某一瞬间被打满,形成「存储 I/O 泥潭」——如果存储无法在 5 分钟内吸收完这次写入,训练就会被迫暂停,数千张 H100 集体空转。
3.2 风暴的量化画像
VAST Data 的官方博客对生产集群做了一次量化分析:
We surveyed 40 large (i.e., more than 1,024-GPU) production training runs, covering more than 85,000 checkpoints across 18 clusters at AI cloud providers.
⚠️ 三处口径要改:原稿写「对 40 个千卡级训练集群、85,000 个 Checkpoint 的分析」——实际是 40 个训练 run(不是 40 个集群),集群数是 18,checkpoint 数是 “more than 85,000”。原稿另一处写的「85,619」这个精确数字在原文里根本不存在(页面上的 “85.614” 之类是 SVG 路径坐标)。
这份分析给出的关键结论:
| 指标 | 数值 | 官方原文 |
|---|---|---|
| Checkpoint 重叠率 | 几乎每个 run 的中位数都 <10% | “almost every one kept the median checkpoint overlap under 10% of total training time” |
| 全局聚合带宽 | 50—200 GB/s,与模型规模无明确相关性 | “asynchronous checkpoints drained to global storage at rates of 50–200 GB/s, with no clear correlation to model size” |
| 万亿参数的带宽需求 | 远低于 1 TB/s | “even trillion-parameter-scale models can train efficiently with well under 1 TB/s of checkpoint bandwidth” |
核心洞察:全局存储不需要匹配 GPU 峰值吞吐——异步 checkpoint 只需能「消化」周期性倾泻的节点本地数据即可。
按 500 GB / 5 分钟折算,聚合突发写带宽约 1.7 GB/s——算术成立(350 GB 则是 1.17 GB/s)。但要注意 350—500 GB 与「5 分钟」这两个前提是文章自设场景,VAST 博客里并没有直接给出。
3.3 存储系统在风暴中的不同表现
如果直接写入对象存储:
- 每个文件都要经历 Initiate → Upload Parts → Complete 的 Multipart 流程;
- 每次请求数十毫秒的首字节延迟被数千并发放大;
- 最终一致性 + 无原子 rename,可能在 Checkpoint 未完全可见时训练即崩溃;
- 结果:保存时长动辄数十分钟,GPU 空转代价极高。
如果直接写入 POSIX 并行文件系统:
- 元数据风暴立即触发:数千个文件的 create/open/close 让 MDS/Token Manager 过载;
- 文件分片过小导致聚合 I/O 效率低;
- 写入与数据加载读取路径争抢同一份带宽,训练数据流被 Checkpoint I/O 挤压。
JuiceFS 的实测表现:
Based on user testing, when saving checkpoints using torch.save to JuiceFS, a single process writing a checkpoint on each GPU card can achieve a write throughput of 1.7 GB/s or higher.
注意官方措辞是 “Based on user testing”(转述用户测试),不是 JuiceFS 自建受控实测。
四、缓解方案
4.1 异步 Checkpointing:分层写入
主流方案是「GPU 本地 NVMe 高速落盘 → 后台缓慢同步到全局存储」的两阶段异步模式。这一层在下半场详细展开。
VAST 的分析给了它一个有力的论据——整机故障只占少数:
While the exact rate of whole-node failures varies (one study by the Llama team at Meta found this to be only 5% of failures)…
⚠️ 一处误归因:原稿写「VAST Data 分析指出整机故障仅占所有故障的 5%」。这个 5% 是 VAST 转引 Meta Llama 团队的研究,不是 VAST 自己的分析结论。VAST 原文明确标了出处(“one study by the Llama team at Meta”)。
绝大多数故障是单卡/网络链路问题,可从本地 Checkpoint 恢复——所以全局存储无需匹配峰值带宽。
4.2 增量 Checkpoint
只保存自上次以来发生变化的部分(例如 MoE 模型中未被激活的 Expert 权重),可将单次写入量从 500 GB 降至数十 GB,把 I/O 压力降低一个数量级。
4.3 写入聚合与 I/O 优化
有一篇论文专门做了这件事——《Understanding LLM Checkpoint/Restore I/O Strategies and Patterns》(arXiv:2512.24511):
Compared to state-of-the-art LLM checkpointing engines, our approach achieves up to 3.9× higher write throughput than DataStates-LLM and 7.6× higher than TorchSnapshot.
核心手段是文件系统感知的聚合(“file system-aware aggregation restores bandwidth and reduces metadata overhead”):
- 把同一进程的所有张量(权重、优化器状态、元数据)聚合为单个连续大文件,减少文件数量与元数据开销;
- 对大块写入使用 O_DIRECT 绕过页缓存;
- 用 liburing 等内核异步 I/O 框架替代传统 POSIX I/O。
⚠️ 一处会议名要改:原稿写「ACM SCA 2026」。这里的 SCA 是 Supercomputing Asia(HPCAsia),不是 Symposium on Computer Architecture(后者是 ISCA)。论文发在 SCA/HPCAsia 2026 Workshops。数字 3.9× / 7.6× 精确出现在摘要里,属实。
4.4 分层存储架构
| 层级 | 存储介质 | 典型系统 | 用途 |
|---|---|---|---|
| 热层 | NVMe-oF / RDMA 直连 | Lustre、GPFS、WekaFS、VAST、JuiceFS 企业版 | 训练数据实时读取、Checkpoint 同步写入 |
| 温层 | 对象存储 + 分布式缓存 | JuiceFS(对象存储 + 缓存) | Checkpoint 异步汇聚、模型版本管理 |
| 冷层 | 对象存储(低频/归档) | S3 IA/Glacier、OSS 归档 | 长期归档、灾备 |
⚠️ 两处公开案例的数字全错,已删:
第一处:原稿写「Meta Llama 3 训练在 1PB NVMe 上实现 380 GB/s 持续吞吐」。Llama 3 论文里的实际数字完全不同:
Tectonic… offers 240 PB of storage out of 7,500 servers equipped with SSDs, and supports a sustainable throughput of 2 TB/s and a peak throughput of 7 TB/s.
论文里没有「1PB」,也没有「380 GB/s」(“380” 只出现在 Table 4 的 TFLOPs/GPU,与存储无关)。这组数字整段是错的。
第二处:原稿写「Anthropic Claude 3 使用 2PB 热存储 + 15PB 对象存储冷备」。Claude 3 的 Model Card 和发布博客全文检索都没有任何 PB 级存储数字,网络上也没有出处。已删除。
4.5 写入路径优化与一个必须说清的权衡
JuiceFS 的做法有代表性:分块并发(大文件切多个 Chunk 并行写入对象存储)+ 写缓存。
但写缓存这里有一个真实的权衡,必须写清楚:
⚠️ 一处需要澄清的矛盾。JuiceFS 的
writeback模式在 Checkpoint 场景下的取舍是两个方向的,取决于你把哪一份当作恢复源:
立场 建议 理由 持久性优先 关 writeback 开启时 close()返回 ≠ 数据已到对象存储;节点崩了就丢性能优先 开 writeback Checkpoint 先落本地 NVMe,再异步上传,写入延迟显著降低 本站 JuiceFS + Lance 那篇 的立场是前者——「Checkpoint 场景必须关 writeback,确保 flush 返回 = 数据已在对象存储持久化」。
两者的分界在于「谁是恢复源」:
- 如果本地 NVMe 是恢复源(节点级故障,占绝大多数)→ writeback 可以开,本地那份就是你要恢复的;
- 如果对象存储必须是恢复源(整机故障、跨集群迁移)→ 必须关,等 flush 返回才能认为持久。
实践上的折中是分层:本地 NVMe 那份走「快速路径」供节点级恢复,对象存储那份走「严格路径」供灾难恢复——两份的目的不同,配置也就不必一致。
五、选型建议
「用正确的工具做正确的事」:
- 训练热数据(数据集读取 + Checkpoint 同步写入)→ POSIX 并行文件系统:自建超算选 Lustre、企业关键业务选 GPFS/Spectrum Scale、统一存储栈选 CephFS、云原生/多云/海量小文件选 JuiceFS;
- Checkpoint 归档与模型库 → 对象存储(S3/OSS),通过异步复制从热层同步,享受低成本与高持久性;
- 避免「对象存储直写训练热路径」——HTTP 延迟、最终一致性、缺乏 POSIX 语义决定了它不适合作为训练的实时存储层。
未来趋势是融合而非对立:对象存储正在「文件化」(S3 Express One Zone 等提供毫秒级首字节延迟);POSIX 文件系统正在「对象化」(JuiceFS 同时兼容 POSIX/HDFS/S3 三种协议);新的 I/O 栈(GPUDirect Storage、liburing)正在消除 GPU 与存储之间的 CPU 瓶颈;Checkpoint 工具链正在拥抱文件系统感知的聚合 I/O 策略。
存储物理学的边界不会消失,但工程的艺术在于:让每一种存储介质都工作在其最擅长的工作点上。
下半场:万卡集群如何把保存开销压进 1%
核心公式只有一条:
同步阻塞时长 = Checkpoint 体积 ÷(并行度 × 传输带宽)。万卡集群下唯一可行的做法,是把「同步阻塞」极限压缩到「GPU → CPU pinned memory 的一次 DMA」,把所有真正耗时的序列化、落盘、跨节点网络传输全部推到后台。
六、先算清时间预算
一个 1T 参数模型(混合精度 + Adam),每参数 12—16 字节,全局状态约 12—16 TB。
✅ 这个口径是对的:ZeRO 论文的 K=12 指纯优化器状态(fp32 master copy 4 + 动量 m 4 + 方差 v 4),加上 fp16 参数 2 + fp16 梯度 2 才是 16 bytes/参数。
在 ZeRO-3 / FSDP 分片后,每个 rank 只持有全局状态的 1/N。以 1024 张 H100 为例,每卡分片约 12—16 GB(16 TB / 1024 = 16 GB ✓,ZeRO 论文自己就用这个例子)。
逐条传输路径的物理上限:
| 路径 | 带宽(单卡) | 16 GB 分片耗时 | 是否阻塞训练 |
|---|---|---|---|
| GPU HBM → CPU pinned(PCIe Gen4 x16) | ~32 GB/s | ~0.5 s | 是,唯一必须同步的阶段 |
| GPU HBM → GPU HBM(NVLink) | ~450 GB/s(单向) | ~0.03 s | 否 |
| GPU → 本地 NVMe(GPUDirect Storage) | ~14 GB/s(单盘 Gen5) | ~1.1 s | 否(后台 DMA) |
| CPU pinned → 本地 NVMe | 7—14 GB/s | 1—2 s | 否(后台线程) |
| 节点本地 NVMe → 共享存储 | 受网络限制 | 数十秒 | 否(后台进程) |
⚠️ 三处口径要标清:
- NVLink「~450 GB/s」是单向——H100 官方标的是 900 GB/s 双向。直接写 450 会与官方数冲突,必须注明是单向。
- 「~14 GB/s」是单盘 PCIe Gen5 x4 NVMe 的顺序读上限(Gen5 x4 理论 ~15.75 GB/s,扣协议开销约 14)。
- 这些带宽数字多来自厂商博客的量级估算,不是实测基准。而且同一篇博客内部就有矛盾——它说 140 GB checkpoint 用 GDS 写「34 秒」(折算仅 ~4.1 GB/s),远低于它自己表格里的 7—14 GB/s。
如果训练迭代时间约 8 s,1% 预算 = 80 ms。
⚠️ 「1T 模型典型迭代 8 s」找不到权威来源。公开数据点差异极大(例如某 1.6T MoE 在昇腾 910C 上约 27 s/step)。dense 1T 的每步时间取决于 batch/seq,没有「8 s 典型值」这样的标准数字——宜标为经验假设。
PCIe Gen4 单次 DMA 16 GB 需约 500 ms(16 GB ÷ 32 GB/s = 0.5 s ✓),远超 80 ms 预算。但如果叠加 NVLink 多卡中转、或启用 GDS 把 HBM 直写 NVMe(绕过 CPU 中转),以及利用 forward/backward 阶段张量的不可变性把 DMA 拆散到整个迭代内,实测同步阻塞可以压到 100 ms 量级。
关键洞察:同步阻塞只发生在「数据离开 HBM 的那一刻」,其余一切皆可异步。
这条洞察来自 Argonne 的 DataStates-LLM 论文(HPDC’24,arXiv:2406.10707),它的核心机制正是:
takes advantage of the fact that the tensors making up the model and optimizer state shards remain immutable for extended periods of time
论文报告的收益是「up to 48× faster checkpointing and 2.2× faster end-to-end training runtime」。
⚠️ 但规模要标清:该论文的实验规模是 up to 180 GPUs,不是万卡。48× 是相对 SOTA 的加速比,在 180 卡规模测得。
关于「同步 checkpoint 到底有多慢」,DataStates-LLM 论文给了一组对比数字,但归属容易搞错:
despite the availability of high speed links (50+ GB/s network and 25+ GB/s PCIe), the LLM checkpointing throughput is far from saturating the link capacity (e.g., REFT reports 38% saturation), and often drops as low as a few GB/s (e.g., Nebula… reports 1-4 GB/s).
⚠️ 更正:原稿写「Microsoft Nebula 实测 1—4 GB/s,PCIe 饱和率仅 38%」。38% 是 REFT 的数字,不是 Nebula 的——1—4 GB/s 才归 Nebula。而且两者都不是万卡实测:DataStates-LLM 自己只在 ≤180 卡做实验,Nebula 那个例子是单机 GPT2-XL(20.6 GB)。「万卡规模」是原稿自行加的限定。
七、分层异步架构
整个方案物理上是三级流水,只有第一级的前半程(GPU→CPU)需要同步:
1 | ┌─────────┐ DMA ┌──────────┐ 独立进程 ┌──────────┐ 限速后台 ┌──────────┐ |
7.1 第 1 级:GPU → CPU pinned memory(同步段)
在 optimizer.step() 完成的瞬间,用 cudaMemcpyAsync + 预分配的 pinned memory 池(cudaMallocHost 或 PyTorch 的 pin_memory()),把当前 rank 持有的所有张量通过独立 CUDA stream DMA 到主机内存。
pinned memory 的作用是让 GPU 的 DMA 引擎不经 CPU 中转直接写入主机物理内存。
⚠️ 一处量级要改:原稿写「pinned memory 相比 pageable memory 能把拷贝时间从数秒压到数百毫秒」——这是 10× 量级的说法。NVIDIA 官方博客给的是:
pinned transfers are more than twice as fast as pageable transfers(示例:pageable 2.31 GB/s vs pinned 5.77 GB/s)
即约 2×。实际耗时完全取决于传输大小(16 GB @ 25 GB/s ≈ 640 ms,@ 12 GB/s ≈ 1.3 s)。宜改为「pinned 约把带宽翻倍」。
DataStates-LLM 在此基础上更进一步:利用参数与优化器状态在 forward/backward 期间不可变这一事实,把拷贝拆散到整个迭代的计算过程中间,在 CUDA stream 上与计算 kernel 交错执行。
7.2 第 2 级:CPU 内存 → 本地 NVMe(异步段)
序列化与本地落盘必须在独立进程中完成,而非线程——这是最容易被忽视的陷阱。
PyTorch async_save() 的情况:
- 2.4 引入 ✅(官方教程前置条件写的是 “PyTorch v2.4.0 or later”);
- 默认用线程 ✅(源码
AsyncCheckpointerType.THREAD为默认值)。
⚠️ 那组实测数字的出处与规模要标清:原稿写「实测在 H100 上使 step 时间从 108ms 退化到 162ms(约 50% overhead)」。数字属实,但出处是一篇个人技术博客(shayon.dev,2026-02),实验环境是 单卡 Llama 1.3B FSDP bf16、7.5 GB checkpoint——不是万卡规模。原文:
Training steps that should take 108ms were consistently running at 162ms for as long as the background thread was active – a 50% step-time penalty
绕开 GIL 的正确姿势:
⚠️ 一处「官方推荐」不成立:原稿写「正确做法是用
ProcessPoolExecutor」。PyTorch 确实提供了进程式后端(AsyncCheckpointerType.PROCESS),但那篇博客实测有效的是「用spawn起进程 + 共享内存传递 staged tensors」。PyTorch 官方教程并未推荐进程池——它只建议「limiting checkpoints to one asynchronous request at a time」,并介绍了DefaultStager把 state_dict 构建与 D2H 拷贝挪到后台线程,全文未提 GIL 或进程池。所以准确说法是:「PyTorch 提供了
AsyncCheckpointerType.PROCESS后端;实践表明进程式能绕开 GIL,但官方文档并未就此给出推荐」。
GDS 的合并路径:如果节点配备 NVMe 并启用 GPUDirect Storage(cuFile + nvidia-fs),第 1、2 级可以合并为一次 HBM→NVMe 的 DMA 直写,完全绕过 CPU 与 pinned buffer。
⚠️ 一处硬件描述与来源不符:原稿写「PCIe Gen5 NVMe + GDS,实测 140 GB Checkpoint 从 4 分 52 秒压到 34 秒(8.6×)」。那组实测跑在 1× Gen4 NVMe 上(Gen5 是同表另一行 8×H200 配置,对应约 9×)。而且来源是第三方 GPU 云厂商博客(Spheron),不是 NVIDIA 官方——NVIDIA 官方 GDS 博客给的是另一套更保守的数字。
7.3 第 3 级:本地 NVMe → 共享存储 / 对象存储(完全后台)
这是「存储风暴」真正发生的层。设计原则是错峰 + 限速:每个节点以固定速率(例如 2—4 GB/s,远低于网络峰值)在 Checkpoint 间隔的整个周期内持续向对象存储或 Lustre 后端同步,把瞬时风暴摊平成长尾流。
VAST 的实测支持这个思路:即使是万亿参数模型,全局聚合 Checkpoint 带宽需求实际低于 1 TB/s——因为故障恢复只需从最近的本地副本回读,全局存储只需在长周期内缓慢吸收。
⚠️ 一处二手描述要标注:原稿写「Microsoft Nebula 的三级方案(内存 → 邻居节点 SSD → 对象存储)」。找不到 Microsoft 官方一手文档确认「邻居节点 SSD」这一层——微软官方把 Nebula 描述为「disk-less」工具,只提到可保存到 Azure Blob / ADLS / NFS。「三级架构」的说法在二手材料中一致,但与官方「disk-less」表述存在张力,引用时宜标为「据二手描述」。
八、Checkpoint 频率与故障恢复的权衡
万卡集群的 MTBF 随规模线性恶化。Meta 的 RSC 集群(Research SuperCluster)11 个月的数据是这一领域最常被引用的实证。
⚠️ 这一段的数字原稿全错,而且是最危险的一类错——论文真实存在,数字却对不上。
论文确实存在:《Revisiting Reliability in Large-Scale Machine Learning Research Clusters》(arXiv:2410.21680,HPCA 2025,FAIR at Meta)。RSC = Research SuperCluster ✅、16k A100 ✅、11 个月 ✅ 都对得上。
但原稿的具体数字在该论文中查无实据:
| 原稿 | 论文原文 |
|---|---|
| 8000 GPU 作业需 30 分钟间隔达 0.9 ETTR | 2048—4096 GPU 作业,且假设 Daly-Young 最优间隔 + 重启 5 分钟 + 写入 5 分钟 |
| (隐含间隔 30 分钟) | 论文假设每小时 checkpoint:“we find this is a typical checkpoint interval for larger jobs on the RSC clusters” |
| 100k GPU 需压到约 2 分钟 | 论文说的是 ~12,000 GPU 需把写入开销压到 ~10 秒;对未来规模的投影是 131k GPU 的 MTTF ≈ 0.23 小时(约 14 分钟) |
论文的实际表述:
2048-4096 GPU job runs on RSC-1 show an average ETTR of around 0.9 assuming checkpoint intervals are Daly-Young optimal and that both restart overhead and checkpoint write overhead is 5 minutes.
To reach ETTR of 0.9 for the largest feasible training runs on RSC-1 (~12,000 GPUs…), checkpoint write time overhead needs to be on the order of ~10 seconds
we project the MTTF for 16384 GPU jobs to be 1.8 hours and for 131072 GPU jobs to be 0.23 hours
最优间隔的经典公式:
⚠️ 漏了系数 2:原稿写
τ* ≈ √(MTBF × C)。Young (1974) / Daly (2006) 的标准形式是τ* = √(2·C·MTBF)——一阶近似。Meta 那篇论文式(3) 用的也是√(2·w_cp/(N·r_f))这个形式。漏掉 2 会让最优间隔算小约 30%。
由于异步方案已把 C 压到近零,频率的上限实际上由第 3 级后台传输的完成时间决定——相邻两次 Checkpoint 的间隔必须 ≥ 本地 NVMe → 对象存储的排空时间,否则 pinned memory 池会被覆盖。工程上常见的配置:
- 高频本地 Checkpoint:每 1000—2000 步(约 15—30 分钟)保存到本地 NVMe,用于节点级故障恢复;
- 低频全局归档:每 2—4 小时从本地 NVMe 同步到对象存储,用于跨集群/灾难恢复;
- 保留策略:本地保留最近 2—3 份,对象存储保留里程碑与最终模型,中间态自动过期——避免 1 TB × 每 30 分钟 = 每天 48 TB 的容量爆炸。
九、代码级落地
1 | import torch, multiprocessing as mp |
NeMo/Megatron 的对应配置(两个参数都核实存在):
| 参数 | 官方语义 |
|---|---|
dist_ckpt_parallel_save: True |
每个 DP rank 独立写入自己的 shard(Fully Parallel Saving) |
dist_ckpt_torch_dist_multiproc: 2 |
每个 rank 用于 checkpoint 保存的额外进程数,等于每个 rank 创建的文件数;「Increasing this number can help saturate the write bandwidth」;默认 2 |
天然把万卡写入扇出到数千个并发文件流。
十、监控指标与一个必须澄清的误区
三个北极星指标:
| 指标 | 目标 | 说明 |
|---|---|---|
| 同步阻塞时长(P99) | < 100 ms | 在 async_checkpoint 前后埋点直接测量 |
| 重叠率(Overlap) | < 10% | VAST 对生产集群的实测显示优秀方案可压到 10% 以下 |
| 端到端恢复时间(RTO) | 5—10 分钟 | 这是经验值,不是官方建议 |
⚠️ 「RTO 5—10 分钟」找不到官方标准——没有任何官方文档把它定为目标。能找到的最接近的是技术社区的经验区间(有建议「异步备份 + 脚本恢复 → RTO 通常 5—30 分钟」)。宜标为经验值。
最后一个必须澄清的误区:「异步保存等于零开销」并不成立。
⚠️ 但那个「1—3% 吞吐损耗」的数字查无出处。原稿写「实测仍有 1—3% 的吞吐损耗」——我找不到任何一手来源给出这个具体百分比。文献讨论的是定性现象(重叠后吞吐仍会下降),没有 1—3% 这个量化值。
「零开销不成立」这个结论本身是有文献支持的——DataStates-LLM 论文明确写了异步的收益常被 PCIe 争用抵消:
this results in significant overheads that reduce the benefit of asynchronous checkpointing to the point where it is not significantly faster as compared to synchronous checkpointing approach
那篇 GIL 博客也实测了 thread-based async 在后台写盘期间造成约 50% step 时间上涨 / 约 33% 吞吐下降。
把总开销压进 1% 依赖四件事同时做到位,缺一不可:
- pinned memory 池的预分配;
- 独立进程的 GIL 隔离;
- 本地 NVMe 的缓冲;
- 对象存储上传的错峰限速。
若第 4 件没做,数百节点同时上传的存储风暴仍会反向挤压数据加载路径,间接拖慢训练本身。
相关阅读
- 具身智能训练存储与数据管线:JuiceFS + Lance 深度实践——JuiceFS 三平面分离、多级缓存与 Checkpoint 落地纪律
- 大模型容错训练系统设计:从架构到形式化验证——故障检测、原地恢复与 TLA+ 验证
- 拆解那 11.9%:大规模训练集群的生产力损失度量与自动化治理——生产力损失的量化分解
- Linux 内核 I/O 路径真相:Page Cache、mmap 零拷贝与 GPUDirect Storage 直通——本文下半场第 1、2 级涉及的 I/O 路径物理机制
- GPFS Fileset 详解:并行文件系统中的精细化运营之道——GPFS 的配额、快照与存储策略
核实说明:本文架构描述核对自 AWS S3 官方文档与 SigV4 文档、Lustre 官方手册、GPFS FAST 2002 论文与 IBM Storage Scale 官方文档、Ceph 官方文档、JuiceFS 官方文档与博客;性能数字核对自 VAST Data 官方博客(40 runs / 18 clusters / >85,000 checkpoints)、ZeRO 论文(arXiv:1910.02054)、DataStates-LLM(arXiv:2406.10707)、Meta RSC 可靠性论文(arXiv:2410.21680)、Llama 3 论文(arXiv:2407.21783)、SCA/HPCAsia 2026 的 checkpoint I/O 论文(arXiv:2512.24511)、PyTorch 源码与官方教程、NVIDIA NeMo 官方文档、NVIDIA pinned memory 博客。
原稿更正汇总:S3 单对象上限(5 TB 已过时 → 50 TB / 48.8 TiB)、175B + Adam 的 checkpoint 体积(~2.8 TB 而非「1TB+」)、「元数据操作占 60%」(无一手来源,文献为 up to 80% / 实测 67%—96%)、VAST 口径(40 个 run / 18 个集群 / >85,000,非「40 个集群」,「85,619」不存在)、Meta Llama 3 的存储规模整段错误(实为 240 PB / 2 TB/s 持续 / 7 TB/s 峰值,非「1PB NVMe / 380 GB/s」)、Anthropic Claude 3 的 2PB/15PB 查无出处(已删)、VAST 的「5% 整机故障」实为转引 Meta 而非 VAST 自研、「SCA」是 Supercomputing Asia 不是 Symposium on Computer Architecture、Nebula 的「38% 饱和率」实为 REFT 的数字且两者都非万卡实测、Meta RSC 的 ETTR 数字在论文中查无实据(实为 2048—4096 GPU / 每小时 / ~12,000 GPU 需 10 秒 / 131k GPU MTTF 0.23h)、Young-Daly 公式漏了系数 2、NVLink 450 GB/s 需注明是单向(官方 900 双向)、「1T 迭代 8s」无来源、pinned 是约 2× 而非 10×、140 GB 的 GDS 实测跑在 Gen4 而非 Gen5、「1—3% 吞吐损耗」与「RTO 5—10 分钟」均无一手来源、
async_save的 108→162ms 出自个人博客且是单卡小模型、PyTorch 官方并未推荐 ProcessPoolExecutor、Nebula 三级方案无一手来源(官方称 disk-less)。另有 JuiceFS writeback 的取舍已在 §4.5 显式澄清。