AI训练血管与粮仓,高性能网络存储怎么选?

摘要:AI 算力基础设施深度系列(五):高性能网络与存储——AI 训练的血管与粮仓 本文是《AI 算力基础设施深度系列》第 5 篇,共 6 篇。 系列目录:① 容器与 K8S 基础 → ② K8S 底层原理 → ③ GPU 与异构算力 → ④ A
AI 算力基础设施深度系列(五):高性能网络与存储——AI 训练的血管与粮仓 本文是《AI 算力基础设施深度系列》第 5 篇,共 6 篇。 系列目录:① 容器与 K8S 基础 → ② K8S 底层原理 → ③ GPU 与异构算力 → ④ AI 平台架构 → ⑤ 高性能网络与存储 → ⑥ 生产运维与成本优化 导语 2024 年 6 月,Meta 公开了训练 Llama 3 405B 的基础设施细节:16,384 块 H100 GPU,跨 2,048 台服务器分布式训练。 其中一个数据让网络工程师集体停顿——训练过程中 AllReduce 通信占总训练时间的 38%,网络吞吐峰值达到 3.15 TB/s。 如果使用传统 TCP/IP 网络,光是协议栈的 CPU 开销和上下文切换延迟,就会把训练效率拖到不可接受的水平。 同样的故事在存储端上演。一次 405B 模型的完整 Checkpoint 大小约 3.2 TB,如果使用传统 NFS 存储,写入一次需要 18 分钟。而 GPU 集群平均每 3 小时就有一块 GPU 出现故障,如果 Checkpoint 频率跟不上故障频率,一次故障可能导致数小时的训练进度丢失——按 H100 的云上价格计算,这是数十万美元的直接损失。 上一篇我们设计了完整的 AI 算力平台架构,包括调度、编排和多集群联邦。但架构再优雅,如果底层网络撑不住 AllReduce 的通信压力、存储接不住 Checkpoint 的 IO 需求,一切都是空谈。 如果 GPU 是算力平台的"心脏",那么高性能网络就是"血管",存储就是"粮仓"。 本文将从硬件原理到 Kubernetes 集成方案,帮你搞清楚:为什么 AI 训练不能用 TCP?RDMA 是什么?GPUDirect 解决了什么问题?双平面网络怎么设计?分层存储如何平衡性能和成本?Checkpoint 策略如何在故障频发的环境下保住训练进度? 一、为什么 AI 训练需要 RDMA? 1.1 分布式训练的通信瓶颈 在理解网络技术之前,先搞清楚一个问题:分布式训练为什么对网络要求这么高? 现代大模型训练普遍采用数据并行 + 模型并行 + 流水线并行的混合并行策略。以数据并行为例,每个 GPU Worker 在前向传播和反向传播后,需要与其他所有 Worker 同步梯度——这就是 AllReduce 操作。 分布式数据并行训练的一个 Step: ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ GPU 0 │ │ GPU 1 │ │ GPU 2 │ │ GPU 3 │ │ │ │ │ │ │ │ │ │ 前向传播 │ │ 前向传播 │ │ 前向传播 │ │ 前向传播 │ │ ↓ │ │ ↓ │ │ ↓ │ │ ↓ │ │ 反向传播 │ │ 反向传播 │ │ 反向传播 │ │ 反向传播 │ │ ↓ │ │ ↓ │ │ ↓ │ │ ↓ │ │ 计算梯度 │ │ 计算梯度 │ │ 计算梯度 │ │ 计算梯度 │ │ ↓ │ │ ↓ │ │ ↓ │ │ ↓ │ └────┬─────┘ └────┬─────┘ └────┬─────┘ └────┬─────┘ │ │ │ │ └──────────────┴──────┬───────┴──────────────┘ │ ┌──────┴──────┐ │ AllReduce │ ← 梯度同步(通信密集) │ 梯度聚合 │ └──────┬──────┘ │ ┌──────────────┬──────┴───────┬──────────────┐ ↓ ↓ ↓ ↓ ┌────┴─────┐ ┌────┴─────┐ ┌────┴─────┐ ┌────┴─────┐ │ GPU 0 │ │ GPU 1 │ │ GPU 2 │ │ GPU 3 │ │ 更新权重 │ │ 更新权重 │ │ 更新权重 │ │ 更新权重 │ └──────────┘ └──────────┘ └──────────┘ └──────────┘ 关键数据点: 模型规模 梯度大小/卡 每 Step AllReduce 数据量 通信时间占比 7B 参数 ~14 GB (FP16) 14 GB × 2 (Ring) 15-25% 70B 参数 ~140 GB (FP16) 分片后 ~35 GB/卡 25-35% 405B 参数 ~810 GB (FP16) 分片后 ~100 GB/卡 30-50% 生产经验: 在 Meta 的 Llama 3 训练中,他们发现通信优化带来的训练吞吐提升,等效于增加 20% 的 GPU 数量。网络投入的 ROI 远超直觉。 1.2 TCP/IP 为什么不行? 传统 TCP/IP 网络之所以无法满足 AI 训练需求,根本原因在于数据路径太长: TCP/IP 数据发送路径(从 GPU 到网络): ┌──────────────────────────────────────────────────────┐ │ 发送端 │ │ │ │ GPU 显存 ──① DMA──→ CPU 主内存 │ │ │ │ │ ② 用户态 → 内核态切换 │ │ │ │ │ ③ TCP/IP 协议栈处理 │ │ (校验和、分段、流控) │ │ │ │ │ ④ 数据拷贝到 Socket Buffer │ │ │ │ │ ⑤ 驱动程序处理 │ │ ↓ │ │ ⑥ NIC 发送 ─────→ [ 网络 ] │ │ │ │ ↓ │ │ ⑥' NIC 接收 ←──── │ │ │ │ │ ⑤' 中断 + 驱动处理 │ │ │ │ │ ④' Socket Buffer → 用户内存 │ │ │ │ │ ③' TCP/IP 协议栈处理 │ │ │ │ │ ②' 内核态 → 用户态切换 │ │ │ │ │ ①' CPU 主内存 ──DMA──→ GPU 显存 │ │ │ │ 接收端 │ └──────────────────────────────────────────────────────┘ 总共:2 次 GPU⟷CPU 拷贝 + 4 次上下文切换 + 2 次协议栈处理 这个路径有几个致命问题: CPU 开销巨大: 每个数据包都要经过内核协议栈处理,100 Gbps 网卡仅协议处理就要消耗 4-8 个 CPU 核心 内存拷贝过多: 数据需要从 GPU 显存拷贝到 CPU 主内存,再拷贝到内核缓冲区 上下文切换开销: 用户态/内核态的频繁切换,每次约 1-5 μs 延迟不可控: TCP 的重传机制、Nagle 算法、拥塞控制等引入不可预测延迟 指标 TCP/IP (100GbE) RDMA (100GbE) RDMA (400G IB) 延迟 (μs) 15-50 1-2 0.5-1 吞吐 (Gbps) 40-60 (实际) 95+ 390+ CPU 占用 30-50% < 5% < 3% 内存拷贝次数 4+ 0 (零拷贝) 0 (零拷贝) 抖动 (Jitter) 高 极低 极低 直观理解: TCP/IP 像是寄快递——你要打包、写地址、交给快递员、快递员分拣、运输、拆包、签收。RDMA 像是你家和邻居之间开了一个直通洞——东西直接递过去,不需要任何中间环节。 1.3 RDMA:Remote Direct Memory Access RDMA(远程直接内存访问)的核心思想是:绕过内核,让网卡直接访问应用程序的内存。 RDMA 数据发送路径: ┌──────────────────────────────────────────────────────┐ │ 发送端 │ │ │ │ 应用内存 (已注册 MR) ──────→ RDMA NIC (RNIC) │ │ ① 无需内核参与 │ │ │ 无需 CPU 处理 ↓ │ │ 无需数据拷贝 [ 网 络 ] │ │ ↓ │ │ RDMA NIC (RNIC) ──────→ 应用内存 │ │ ② 无需内核参与 (已注册 MR) │ │ 无需 CPU 处理 │ │ │ │ 接收端 │ └──────────────────────────────────────────────────────┘ 总共:0 次 CPU 介入 + 0 次数据拷贝 + 0 次上下文切换 RDMA 的三个核心操作: 操作 描述 是否需要对端 CPU 典型场景 Send/Recv 类似传统 socket 的双端操作 是(接收端要 post recv) 控制面消息 RDMA Write 直接写入对端注册内存 否(单端操作) 大块数据传输 RDMA Read 直接读取对端注册内存 否(单端操作) 分布式存储 RDMA 关键概念: ┌─────────────────────────────────────────────┐ │ 应用程序 │ │ │ │ ┌───────────┐ ┌────────────┐ │ │ │ QP │ │ MR │ │ │ │ (Queue │ │ (Memory │ │ │ │ Pair) │ │ Region) │ │ │ │ │ │ │ │ │ │ ┌───────┐ │ │ 注册内存区 │ │ │ │ │ SQ │ │ │ ·虚拟地址 │ │ │ │ │ 发送队 │ │ │ ·物理页面 │ │ │ │ └───────┘ │ │ ·权限标志 │ │ │ │ ┌───────┐ │ │ ·Remote Key│ │ │ │ │ RQ │ │ └────────────┘ │ │ │ │ 接收队 │ │ │ │ │ └───────┘ │ ┌────────────┐ │ │ └─────┬─────┘ │ CQ │ │ │ └──────────→│ (Completion│ │ │ │ Queue) │ │ │ └────────────┘ │ ├─────────────────────────────────────────────┤ │ 用户态 Verbs 库 (libibverbs) │ ├─────────────────────────────────────────────┤ │ RDMA NIC (RNIC / HCA) │ │ 硬件卸载协议栈 │ └─────────────────────────────────────────────┘ QP (Queue Pair): 通信端点,包含发送队列(SQ)和接收队列(RQ) MR (Memory Region): 注册给网卡直接访问的内存区域,pin 在物理内存 CQ (Completion Queue): 操作完成的通知队列 PD (Protection Domain): 安全隔离域 二、RDMA 三大技术流派 2.1 InfiniBand (IB) InfiniBand 是一套完全独立于以太网的网络架构,包括专用的交换机、网卡(HCA)、线缆和协议栈。 InfiniBand Fat-Tree 拓扑: ┌──────────┐ │ Core SW │ ← 核心层 (Director 级) └──┬───┬──┘ │ │ ┌────────┘ └────────┐ ↓ ↓ ┌──────────┐ ┌──────────┐ │ Spine SW │ │ Spine SW │ ← 汇聚层 └──┬───┬──┘ └──┬───┬──┘ │ │ │ │ ┌────┘ └────┐ ┌────┘ └────┐ ↓ ↓ ↓ ↓ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ Leaf SW │ │ Leaf SW │ │ Leaf SW │ │ Leaf SW │ ← 接入层 └──┬──┬──┘ └──┬──┬──┘ └──┬──┬──┘ └──┬──┬──┘ │ │ │ │ │ │ │ │ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ HCA HCA HCA HCA HCA HCA HCA HCA ← GPU 服务器 InfiniBand 核心技术特征: 特性 说明 信用流控 发送方只在接收方有空间时才发送,无丢包 子网管理 Subnet Manager (SM) 集中管理路由和 QoS Virtual Lanes 硬件级 QoS 流量隔离 自适应路由 交换机动态路径选择,负载均衡 速率演进 SDR(10G)→DDR(20G)→QDR(40G)→EDR(100G)→HDR(200G)→NDR(400G)→XDR(800G) InfiniBand 的最大优势是 无损网络 (Lossless)——基于信用的流控机制使 IB 网络几乎不丢包。 选型提示: InfiniBand 是大规模训练的事实标准。集群超过 256 块 GPU 且主要做预训练,IB 几乎是唯一选择。但 IB 生态相对封闭(NVIDIA 主导),一台 NDR 400G Leaf 交换机约 $40K-60K。 2.2 RoCE v2 (RDMA over Converged Ethernet) RoCE v2 在标准以太网硬件上实现 RDMA,将 RDMA 协议封装在 UDP/IP 包头中: RoCE v2 协议封装: ┌──────────────────────────────────────────────────┐ │ ┌──────────┬──────────┬──────────┬────────────┐ │ │ │ Ethernet │ IP │ UDP │ IB Transport│ │ │ │ Header │ Header │ Header │ Payload │ │ │ │ 14B │ 20B │ 8B │ │ │ │ └──────────┴──────────┴──────────┴────────────┘ │ │ ← 标准以太网交换机可转发 → ← RNIC 处理 → │ └──────────────────────────────────────────────────┘ 但 RoCE v2 面临核心挑战:以太网本质有损。RDMA 对丢包极度敏感——一个丢包就可能导致 QP 进入错误状态。因此需要 无损以太网 支持: RoCE v2 无损以太网配置栈: ┌──────────────────────────────────────┐ │ 应用层(NCCL) │ ├──────────────────────────────────────┤ │ RDMA Verbs (libibverbs) │ ├──────────────────────────────────────┤ │ RoCE v2 协议 (NIC 硬件) │ ├──────────────────────────────────────┤ │ ┌─────────────────────────────────┐ │ │ │ PFC (Priority Flow Control) │ │ ← 优先级流控 │ ├─────────────────────────────────┤ │ │ │ ECN (Explicit Congestion Notif) │ │ ← 拥塞通知 │ ├─────────────────────────────────┤ │ │ │ DCQCN (拥塞控制算法) │ │ ← 发送端降速 │ └─────────────────────────────────┘ │ ├──────────────────────────────────────┤ │ 以太网交换机 (100G/400G) │ └──────────────────────────────────────┘ PFC 配置示例: # 启用 PFC(对 Priority 3 启用,用于 RoCE 流量) mlnx_qos -i eth0 --pfc 0,0,0,1,0,0,0,0 # 配置 ECN 标记阈值 echo 150000 > /sys/class/net/eth0/ecn/roce_np/min_time_between_cnps # 验证 DCQCN 配置 cat /sys/class/net/eth0/ecn/roce_rp/enable 生产经验(PFC 死锁): PFC 在复杂拓扑中可能引发 PFC Storm——一台服务器的暂停信号沿链路反压,导致整个网络瘫痪。解决方案:① 限制 PFC 传播跳数(Watchdog);② ECN 为主、PFC 为安全网;③ 部署 PFC Storm Detection 自动恢复。 2.3 云厂商弹性 RDMA 方案 传统 RDMA 在虚拟化和云环境中部署困难,各大云厂商推出了弹性 RDMA 方案: 方案 厂商 核心思路 带宽 eRDMA 阿里云 自研网卡+驱动,兼容 Verbs API 最高 100 Gbps EFA AWS SRD 协议(容忍丢包的类 RDMA) 最高 3200 Gbps GPUDirect-TCPX GCP 自研网络栈,TCP 加速到接近 RDMA 200 Gbps/卡 AWS EFA (SRD) vs 传统 RoCE 对比: 传统 RoCE: AWS EFA (SRD): ┌──────────────┐ ┌──────────────┐ │ NCCL │ │ NCCL │ ├──────────────┤ ├──────────────┤ │ libibverbs │ │ libfabric │ ├──────────────┤ │ (EFA Provider)│ │ RoCE v2 │ ├──────────────┤ │ 需要无损网络 │ │ SRD 协议 │ │ PFC + ECN │ │ 容忍丢包! │ ├──────────────┤ │ 多路径负载均衡│ │ 标准以太网 │ ├──────────────┤ └──────────────┘ │ AWS VPC 网络 │ └──────────────┘ 关键区别:SRD 不需要无损网络,大大降低部署复杂度 2.4 三大方案综合对比 维度 InfiniBand RoCE v2 eRDMA/EFA 延迟 0.5-1 μs 1-3 μs 2-5 μs 带宽 400-800G 100-400G 100-400G 无损保证 原生无损 需 PFC+ECN 容忍丢包 交换机成本 极高 中等 低(云虚拟化) 部署复杂度 高 中高 低 虚拟化支持 差 中 原生 适用场景 自建大集群 自建/混合云 公有云 选型决策: 超过 1000 GPU 且自建机房 → InfiniBand 100-1000 GPU,已有以太网 → RoCE v2 公有云训练 → 云厂商原生方案(EFA/eRDMA/GPUDirect-TCPX) 推理/微调 → RoCE v2 或 eRDMA 即可 三、GPUDirect 技术:消除最后一公里拷贝 3.1 GPU 通信中的数据拷贝问题 即使用了 RDMA,数据仍要先从 GPU 显存拷贝到 CPU 主内存,再由 RNIC 发送: 没有 GPUDirect 的 GPU 间通信: GPU 服务器 A GPU 服务器 B ┌────────────────┐ ┌────────────────┐ │ ┌────────────┐ │ │ ┌────────────┐ │ │ │ GPU 显存 │ │ │ │ GPU 显存 │ │ │ └─────┬──────┘ │ │ └─────▲──────┘ │ │ │① PCIe │ │ │④ PCIe │ │ ↓ DMA │ │ │ DMA │ │ ┌────────────┐ │ │ ┌────────────┐ │ │ │ CPU 主内存 │ │ │ │ CPU 主内存 │ │ │ └─────┬──────┘ │ │ └─────▲──────┘ │ │ │② RDMA │ │ │③ RDMA │ │ ↓ │ 网络 │ │ │ │ ┌────────────┐ │───────────→ │ ┌────────────┐ │ │ │ RDMA NIC │ │ │ │ RDMA NIC │ │ │ └────────────┘ │ │ └────────────┘ │ └────────────────┘ └────────────────┘ 瓶颈:步骤①④ 经 PCIe 总线,额外延迟 5-15μs 3.2 GPUDirect RDMA (GDR) GPUDirect RDMA 让 RDMA NIC 直接访问 GPU 显存,彻底消除 GPU↔CPU 拷贝: GPUDirect RDMA: GPU 服务器 A GPU 服务器 B ┌────────────────┐ ┌────────────────┐ │ ┌────────────┐ │ │ ┌────────────┐ │ │ │ GPU 显存 │ │ │ │ GPU 显存 │ │ │ └─────┬──────┘ │ │ └─────▲──────┘ │ │ │ PCIe │ │ │ PCIe │ │ │ P2P │ 网络 │ P2P │ │ │ ↓ │ │ │ │ │ ┌────────────┐ │───────────→ │ ┌────────────┐ │ │ │ RDMA NIC │ │ ① 一步到位 │ │ RDMA NIC │ │ │ └────────────┘ │ │ └────────────┘ │ └────────────────┘ └────────────────┘ 优势:消除 2 次 GPU⟷CPU 拷贝,延迟降低 5-10μs 配置验证: # 1. 检查 GPU 与 RDMA NIC 的拓扑亲和性 $ nvidia-smi topo -m GPU0 GPU1 mlx5_0 mlx5_1 GPU0 X NV12 PXB SYS # PXB=同Bridge(最优) GPU1 NV12 X SYS PXB # SYS=跨NUMA(性能降30%) # 2. 加载 nvidia-peermem 内核模块 $ modprobe nvidia-peermem $ lsmod | grep nvidia_peermem # 3. NCCL 验证 GDR 是否生效 $ NCCL_DEBUG=INFO torchrun --nproc_per_node=8 test.py # 查看日志:NET/IB : Using [0]mlx5_0:1/GDR ; ... GDR: Enabled 3.3 GPUDirect Storage (GDS) 类似思路延伸到存储——GPUDirect Storage 让 NVMe 直接与 GPU 显存交换数据: 传统路径: GPUDirect Storage: NVMe → CPU 内存 → GPU 显存 NVMe → GPU 显存 (直接 DMA) 性能提升: - Checkpoint 写入速度 2-3x - 模型加载速度 2-4x - CPU 内存带宽释放 # GPUDirect Storage 示例(使用 kvikio) import kvikio import cupy as cp # 传统方式:GPU → CPU → Disk tensor_cpu = tensor_gpu.cpu() # GPU→CPU 拷贝(慢) torch.save(tensor_cpu, '/mnt/nfs/ckpt.pt') # GDS 方式:GPU → Disk(直接) gpu_array = cp.asarray(tensor_gpu) f = kvikio.CuFile("/mnt/nvme/ckpt.bin", "w") f.write(gpu_array) # 不经过 CPU f.close() 3.4 GPUDirect 家族全景 NVIDIA GPUDirect 技术全景: ┌──────────────────────────────────────────────────┐ │ ┌──────────────────┐ ┌──────────────────┐ │ │ │ GPUDirect P2P │ │ GPUDirect RDMA │ │ │ │ (GPU⟷GPU 同机) │ │ (GPU⟷NIC 跨机) │ │ │ │ NVLink/PCIe P2P │ │ PCIe P2P │ │ │ │ ~900 GB/s (NVL) │ │ ~200 Gbps/NIC │ │ │ └──────────────────┘ └──────────────────┘ │ │ │ │ ┌──────────────────┐ ┌──────────────────┐ │ │ │ GPUDirect │ │ GPUDirect │ │ │ │ Storage │ │ Video │ │ │ │ (GPU⟷NVMe) │ │ (GPU⟷视频采集卡) │ │ │ │ cuFile API │ │ 低延迟视频管线 │ │ │ └──────────────────┘ └──────────────────┘ │ │ │ │ 关键依赖:nvidia-peermem 模块 / PCIe 拓扑亲和 │ └──────────────────────────────────────────────────┘ 四、Kubernetes 中的 RDMA 网络配置 4.1 K8S 默认网络模型的局限 Kubernetes 的默认 CNI 为微服务设计,不支持 RDMA: K8S 默认网络: AI 训练需要: Pod eth0 ←→ veth ←→ bridge Pod 直通物理 RDMA NIC (只有 TCP/IP) 多网络接口(管理+训练) (veth 额外开销) RDMA 设备映射到容器内 4.2 Multus CNI:多网络接口方案 Multus CNI 让 Pod 同时连接多个网络: Pod (AI 训练容器) ┌────────────────────────────────────┐ │ ┌─────────┐ ┌───────────────┐ │ │ │ eth0 │ │ net1 (RDMA) │ │ │ │ (管理网) │ │ (训练网) │ │ │ └────┬────┘ └──────┬────────┘ │ └───────┼────────────────┼───────────┘ │ │ ┌─────┴──────┐ ┌────┴────────────┐ │ 默认 CNI │ │ SR-IOV/Macvlan │ │ (Calico) │ │ CNI │ └─────┬──────┘ └────┬────────────┘ │ │ ┌─────┴──────┐ ┌────┴────────────┐ │ Node eth0 │ │ Node RDMA NIC │ │ (25GbE) │ │ (400G IB/RoCE) │ └────────────┘ └─────────────────┘ 完整部署步骤: # Step 1: 安装 Multus CNI kubectl apply -f https://raw.githubusercontent.com/k8snetworkplumbingwg/multus-cni/master/deployments/multus-daemonset-thick.yml # Step 2: 创建 RDMA 网络定义 apiVersion: "k8s.cni.cncf.io/v1" kind: NetworkAttachmentDefinition metadata: name: rdma-net-sriov namespace: ai-training spec: config: | { "cniVersion": "0.3.1", "type": "sriov", "vlan": 100, "ipam": { "type": "whereabouts", "range": "10.56.0.0/16" } } # Step 3: RDMA Device Plugin apiVersion: v1 kind: ConfigMap metadata: name: rdma-devices namespace: kube-system data: config.json: | { "periodicUpdateInterval": 300, "configList": [{ "resourceName": "rdma_shared_device_a", "rdmaHcaMax": 1000, "selectors": { "vendors": ["15b3"], "deviceIDs": ["101b"], "ifNames": ["ib0"] } }] } # Step 4: 训练 Pod 使用 RDMA 网络 apiVersion: v1 kind: Pod metadata: name: pytorch-worker-0 annotations: k8s.v1.cni.cncf.io/networks: rdma-net-sriov spec: containers: - name: pytorch image: nvcr.io/nvidia/pytorch:24.04-py3 resources: limits: nvidia.com/gpu: 8 rdma/rdma_shared_device_a: 1 env: - name: NCCL_IB_DISABLE value: "0" - name: NCCL_NET_GDR_LEVEL value: "5" - name: NCCL_IB_HCA value: "mlx5" - name: NCCL_SOCKET_IFNAME value: "eth0" securityContext: capabilities: add: ["IPC_LOCK"] # RDMA 需要锁定内存 4.3 SR-IOV:硬件级虚拟化 SR-IOV 将一个物理网卡虚拟化为多个 VF (Virtual Function),每个 VF 独立分配给 Pod: 物理 RDMA NIC (PF) ┌──────────────────────────────────────┐ │ Mellanox ConnectX-7 (400G) │ │ ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐│ │ │ VF 0 │ │ VF 1 │ │ VF 2 │ │ VF 3 ││ ← 硬件虚拟化 │ └──┬───┘ └──┬───┘ └──┬───┘ └──┬───┘│ └─────┼────────┼────────┼────────┼────┘ │ │ │ │ ┌────┴───┐┌───┴───┐┌───┴───┐┌──┴────┐ │ Pod A ││ Pod B ││ Pod C ││ Pod D │ └────────┘└───────┘└───────┘└───────┘ 每个 VF:独立 PCIe 设备 + 独立 MAC + 硬件级隔离 # 启用 SR-IOV VF echo 8 > /sys/class/net/ib0/device/sriov_numvfs # 验证 VF 创建 lspci | grep -i "Virtual Function" 4.4 NCCL:把一切串起来的通信库 所有分布式训练框架几乎都通过 NCCL 做 GPU 间通信: NCCL 通信栈: ┌──────────────────────────────────────────┐ │ PyTorch DDP / DeepSpeed / Megatron-LM │ ├──────────────────────────────────────────┤ │ torch.distributed │ ├──────────────────────────────────────────┤ │ NCCL │ │ ┌────────────────────────────────────┐ │ │ │ AllReduce, AllGather, ReduceScatter│ │ │ ├────────────────────────────────────┤ │ │ │ Transport: │ │ │ │ ┌────────┐ ┌──────┐ ┌──────────┐ │ │ │ │ │ NVLink │ │ IB │ │ NET(TCP) │ │ │ │ │ │(机内) │ │(RDMA)│ │ (fallback)│ │ │ │ │ └────────┘ └──────┘ └──────────┘ │ │ │ └────────────────────────────────────┘ │ ├──────────────────────────────────────────┤ │ NVLink/NVSwitch │ IB/RoCE │ TCP/IP │ └──────────────────────────────────────────┘ NCCL 关键环境变量(生产必备): # 网络选择 NCCL_IB_DISABLE=0 # 启用 IB/RoCE NCCL_NET_GDR_LEVEL=5 # GPUDirect RDMA 最大等级 NCCL_IB_HCA=mlx5_0,mlx5_1 # 指定 RDMA HCA NCCL_SOCKET_IFNAME=eth0 # OOB 控制面接口 # 性能调优 NCCL_BUFFSIZE=8388608 # 通信 buffer 8MB NCCL_ALGO=Ring,Tree # 通信算法 NCCL_PROTO=LL128 # 协议 # 拓扑 NCCL_TOPO_FILE=/etc/nccl/topo.xml # 自定义拓扑 NCCL_TOPO_DUMP_FILE=/tmp/nccl_topo # 导出拓扑 # 调试 NCCL_DEBUG=INFO # 日志级别 生产经验: NCCL_IB_HCA 一定要指定正确的网卡——NCCL 可能选到与 GPU 不亲和的 NIC,导致性能下降 50%+。多 NIC 场景确保 NCCL_IB_GID_INDEX 正确。 五、双平面网络架构设计 5.1 为什么需要网络平面分离? 流量类型 管理/服务流量 训练/RDMA 流量 协议 TCP/IP RDMA (IB/RoCE) 带宽 1-25 Gbps 100-400 Gbps 延迟 毫秒级 微秒级 可靠性 容忍重传 不可丢包 内容 K8S API、SSH、监控 AllReduce 梯度同步 两种流量混在一起必然互相干扰——一个 Prometheus 抓取请求可能触发 PFC 暂停,影响 RDMA 训练流量。 5.2 双平面架构 双平面网络架构: ┌──────────────────────────────────────────────────────┐ │ GPU 服务器 │ │ │ │ ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐ │ │ │GPU0 │ │GPU1 │ │GPU2 │ │GPU3 │ │ │ └──┬──┘ └──┬──┘ └──┬──┘ └──┬──┘ │ │ └───┬───┘───┬───┘───┬───┘ │ │ │ NVSwitch/NVLink │ │ │ ↓ ↓ │ │ ┌────────────┐ ┌────────────┐ │ │ │ RDMA NIC 0 │ │ RDMA NIC 1 │ ← 训练网(双NIC) │ │ │ 400G │ │ 400G │ │ │ └─────┬──────┘ └─────┬──────┘ │ │ │ │ │ │ ┌────────────┐ │ │ │ 管理 NIC │ ← 管理网 (25GbE) │ │ └─────┬──────┘ │ └────────┼─────────────────┼───────┼───────────────────┘ │ │ │ ↓ ↓ ↓ ┌──────────────┐ ┌──────────────────────┐ │ 管理网交换机 │ │ 训练网交换机 (IB/RoCE) │ │ 25GbE ToR │ │ 400G Leaf-Spine │ │ │ │ │ │ ·K8S API │ │ ·AllReduce 梯度同步 │ │ ·SSH/监控 │ │ ·模型并行通信 │ │ ·镜像拉取 │ │ ·Checkpoint 写入 │ └──────────────┘ └──────────────────────┘ 5.3 K8S 双平面网络实战 # 训练 Job 使用双网络 apiVersion: kubeflow.org/v1 kind: PyTorchJob metadata: name: llm-training spec: pytorchReplicaSpecs: Worker: replicas: 16 template: metadata: annotations: # 请求两个 RDMA 训练网接口 k8s.v1.cni.cncf.io/networks: | training-network@net1, training-network@net2 spec: containers: - name: pytorch image: nvcr.io/nvidia/pytorch:24.04-py3 resources: limits: nvidia.com/gpu: 8 mellanox.com/cx7_sriov_rdma: 2 env: - name: MASTER_ADDR value: "llm-training-worker-0" # DNS走管理网 - name: NCCL_SOCKET_IFNAME value: "eth0" # OOB走管理网 - name: NCCL_IB_HCA value: "mlx5_2,mlx5_3" # RDMA走训练网 - name: NCCL_NET_GDR_LEVEL value: "5" 5.4 网络拓扑感知调度 调度器把两个通信密集的 Worker 调度到不同 Leaf 交换机下,跨 Spine 延迟会显著影响性能: 同 Leaf (延迟~1μs): 跨 Spine (延迟~3-5μs): Worker0 ←→ Worker1 Worker0 Worker1 │ │ │ │ └────┬─────┘ ┌────┘ └────┐ Leaf SW Leaf0 Spine SW Leaf1 ↑↓ 延迟增加 + oversubscription 生产经验: Google GKE 的 Topology-Aware Routing 能自动感知 GPU 服务器的网络拓扑(NVLink 域和 IB 交换机层级),将通信密集的 Pod 调度到拓扑最优位置。测试中 AllReduce 延迟降低了 40%。 六、分层存储架构 6.1 AI 训练的存储需求 不同训练阶段有完全不同的 IO 特征: 阶段 IO 模式 带宽需求 延迟要求 容量 持久性 数据集读取 顺序/随机读 10-100 GB/s 中 TB-PB 只读 Shuffle/预处理 随机读写 高 中 同数据集 临时 Checkpoint 写 大块顺序写 50-200 GB/s 秒级 GB-TB/次 持久 Checkpoint 读 大块顺序读 50-200 GB/s 低 同上 持久 模型导出 顺序写 中 不敏感 GB-TB 长期 6.2 三层存储架构 分层存储: ┌──────────────┐ ┌──────────────┐ ┌──────────────────┐ │ L1: 本地 │ │ L2: 分布式 │ │ L3: 对象存储 │ │ 热存储 │ │ 温存储 │ │ 冷存储 │ │ │ │ │ │ │ │ ·本地 NVMe │ │ ·Lustre │ │ ·S3/GCS/OSS │ │ ·tmpfs │ │ ·GPFS/Weka │ │ ·MinIO │ │ │ │ ·JuiceFS │ │ │ │ │ │ │ │ │ │ 延迟:<100μs │ │ 延迟:~1ms │ │ 延迟:10-100ms │ │ 带宽:~7GB/s │ │ 带宽:~50GB/s│ │ 带宽:~10GB/s │ │ (per NVMe) │ │ (per client)│ │ (per client) │ │ 容量: TB级 │ │ 容量: PB级 │ │ 容量: EB级 │ │ 成本: $$$ │ │ 成本: $$ │ │ 成本: $ │ │ │ │ │ │ │ │ 用途: │ │ 用途: │ │ 用途: │ │ ·数据缓存 │ │ ·训练数据集 │ │ ·数据湖 │ │ ·Shuffle │ │ ·Checkpoint │ │ ·冷 Checkpoint │ │ ·临时空间 │ │ ·模型仓库 │ │ ·归档存储 │ └──────────────┘ └──────────────┘ └──────────────────┘ 6.3 分布式文件系统选型 维度 Lustre GPFS Weka JuiceFS 最大带宽 数 TB/s 数 TB/s 数 TB/s 受后端限制 小文件 一般 好 好 好 POSIX 完整 完整 完整 完整 K8S CSI 支持 支持 支持 原生 GDS 支持 是 是 是 否 运维复杂度 高 极高 中 低 成本 中 高 高 低 适用 HPC/大规模训练 超大企业 全闪存 云原生 选型建议: 500+ GPU 自建 → Lustre/GPFS;全闪存极致性能 → Weka;云原生低运维 → JuiceFS + S3;加速层 → Alluxio + S3 6.4 K8S 存储配置实战 # 1. 训练数据 PVC(ReadOnlyMany - 多 Pod 共享读) apiVersion: v1 kind: PersistentVolumeClaim metadata: name: training-data namespace: ai-training spec: accessModes: - ReadOnlyMany resources: requests: storage: 100Ti storageClassName: lustre-sc --- # 2. Checkpoint PVC(ReadWriteMany) apiVersion: v1 kind: PersistentVolumeClaim metadata: name: checkpoint-storage namespace: ai-training spec: accessModes: - ReadWriteMany resources: requests: storage: 10Ti storageClassName: lustre-sc --- # 3. 本地 NVMe 缓存 apiVersion: v1 kind: PersistentVolume metadata: name: nvme-cache-node01 spec: capacity: storage: 3Ti accessModes: - ReadWriteOnce local: path: /mnt/nvme0 nodeAffinity: required: nodeSelectorTerms: - matchExpressions: - key: kubernetes.io/hostname operator: In values: ["gpu-node-01"] --- # 4. 训练 Pod 使用多层存储 apiVersion: v1 kind: Pod metadata: name: training-worker spec: containers: - name: pytorch image: nvcr.io/nvidia/pytorch:24.04-py3 volumeMounts: - name: training-data mountPath: /data/dataset # L2: 分布式 FS readOnly: true - name: checkpoint mountPath: /data/checkpoints # L2: Checkpoint - name: nvme-cache mountPath: /data/cache # L1: 本地 NVMe - name: shm mountPath: /dev/shm # DataLoader 共享内存 resources: limits: nvidia.com/gpu: 8 volumes: - name: training-data persistentVolumeClaim: claimName: training-data - name: checkpoint persistentVolumeClaim: claimName: checkpoint-storage - name: nvme-cache persistentVolumeClaim: claimName: nvme-cache-node01 - name: shm emptyDir: medium: Memory sizeLimit: 256Gi # 大内存 DataLoader 七、Checkpoint 策略:保住训练进度的生命线 7.1 为什么 Checkpoint 如此关键? 大规模训练中,GPU 故障是常态: GPU 集群故障频率: 集群规模 平均故障间隔(MTBF) 影响 ───────────────────────────────────────────── 64 GPU ~7 天 低频 256 GPU ~2 天 需自动恢复 1024 GPU ~12 小时 必须高频 Checkpoint 4096 GPU ~3 小时 Checkpoint 是生命线 16384 GPU ~45 分钟 需极致优化 Meta Llama 3 训练实际数据: · 54 天训练,419 次中断 · 平均每 3 小时中断一次 · 58.7% 是硬件故障 7.2 同步 vs 异步 Checkpoint 同步 Checkpoint: 训练: ████████████ ▓▓▓▓▓ ████████████ ▓▓▓▓▓ ████████████ 计算 Step 暂停 计算 Step 暂停 计算 Step ↑写Ckpt ↑写Ckpt 问题:所有 GPU 空闲 3-5 分钟/次! 异步 Checkpoint: 训练: ████████████████████████████████████████████████████ 计算不中断 ↑ 计算不中断 ↑ │ │ 异步IO: [后台写Ckpt] [后台写Ckpt] 优势:训练不中断,GPU 利用率~100% 7.3 PyTorch 分布式 Checkpoint (DCP) import torch.distributed.checkpoint as dcp from torch.distributed.checkpoint.state_dict import ( get_state_dict, set_state_dict, StateDictOptions ) # 分布式保存(每个 rank 只保存自己的分片,避免 OOM) def save_checkpoint(model, optimizer, epoch, step, path): model_state, optim_state = get_state_dict( model, optimizer, options=StateDictOptions(full_state_dict=False) ) dcp.save( state_dict={"model": model_state, "optimizer": optim_state, "epoch": epoch, "step": step}, storage_writer=dcp.FileSystemWriter(path), ) # 异步 Checkpoint(PyTorch 2.4+) from torch.distributed.checkpoint import AsyncCheckpointIO async_ckpt = AsyncCheckpointIO() def save_async(model, optimizer, epoch, step, path): model_state, optim_state = get_state_dict( model, optimizer, options=StateDictOptions(full_state_dict=False) ) future = async_ckpt.save( state_dict={"model": model_state, "optimizer": optim_state, "epoch": epoch, "step": step}, storage_writer=dcp.FileSystemWriter(path), ) return future # 后台写入,立即返回 # 分布式加载(支持不同并行度间 resharding) def load_checkpoint(model, optimizer, path): model_state, optim_state = get_state_dict( model, optimizer, options=StateDictOptions(full_state_dict=False) ) state_dict = {"model": model_state, "optimizer": optim_state} dcp.load(state_dict=state_dict, storage_reader=dcp.FileSystemReader(path)) set_state_dict(model, optimizer, model_state_dict=state_dict["model"], optim_state_dict=state_dict["optimizer"]) 7.4 Checkpoint 优化策略矩阵 策略 原理 效果 适用场景 异步写入 后台线程写存储 减少 90%+ 暂停时间 所有场景 增量 Checkpoint 只保存差异 减少 60-80% IO 量 长时间训练 分片保存 (DCP) 每 rank 保存自己分片 避免 rank 0 OOM FSDP/TP 模型 本地 NVMe 缓存 先写本地,异步同步 写延迟降低 10x 有本地 NVMe 压缩 对 Checkpoint 压缩 减少 30-50% 空间 存储成本敏感 滚动保留 只保留最近 N 个 控制存储空间 所有场景 GPUDirect Storage GPU→NVMe 直接写 速度提升 2-3x GDS 硬件 Checkpoint 写入优化流水线: Step 1: GPU 快照 (~1s) GPU 显存 ──snapshot──→ CPU pinned memory Step 2: 本地写入 (~3-5s) CPU memory ──write──→ 本地 NVMe(训练已恢复) Step 3: 异步同步 (后台 ~30-60s) 本地 NVMe ──async──→ 分布式 FS (Lustre) Step 4: 冷备归档 (定期) 分布式 FS ──policy──→ 对象存储 (S3) ┌─────┐ ┌────────┐ ┌───────┐ ┌───────┐ ┌─────┐ │ GPU │──→│CPU Mem │──→│ NVMe │──→│Lustre │──→│ S3 │ └─────┘ └────────┘ └───────┘ └───────┘ └─────┘ ~1s ~3-5s 后台 定期 7.5 Checkpoint 的 K8S 集成 # 自动恢复最近 Checkpoint 的训练 Job apiVersion: kubeflow.org/v1 kind: PyTorchJob metadata: name: resilient-training spec: pytorchReplicaSpecs: Worker: replicas: 8 restartPolicy: OnFailure template: spec: initContainers: - name: checkpoint-finder image: python:3.11-slim command: ["python", "-c"] args: - | import os ckpt_dir = "/data/checkpoints" ckpts = sorted([d for d in os.listdir(ckpt_dir) if d.startswith("step_")], key=lambda x: int(x.split("_")[1])) if ckpts: latest = os.path.join(ckpt_dir, ckpts[-1]) open("/tmp/resume_path","w").write(latest) print(f"Found checkpoint: {latest}") else: print("No checkpoint, training from scratch") volumeMounts: - name: checkpoint mountPath: /data/checkpoints - name: tmp mountPath: /tmp containers: - name: pytorch image: nvcr.io/nvidia/pytorch:24.04-py3 command: ["bash", "-c"] args: - | RESUME="" [ -f /tmp/resume_path ] && RESUME=$(cat /tmp/resume_path) python train.py \ --resume-from "$RESUME" \ --checkpoint-dir /data/checkpoints \ --checkpoint-interval 500 \ --async-checkpoint volumeMounts: - name: checkpoint mountPath: /data/checkpoints - name: nvme-cache mountPath: /data/cache - name: tmp mountPath: /tmp resources: limits: nvidia.com/gpu: 8 volumes: - name: checkpoint persistentVolumeClaim: claimName: checkpoint-storage - name: nvme-cache persistentVolumeClaim: claimName: nvme-cache - name: tmp emptyDir: {} 八、数据管道优化 8.1 数据加载瓶颈 训练数据加载是另一个常被忽视的瓶颈。如果 GPU 等数据的时间超过计算时间,GPU 利用率直接下降: 数据加载瓶颈示意: 理想情况(数据预取足够快): GPU: [计算][计算][计算][计算][计算][计算] Data: [加载][加载][加载][加载][加载][加载] 完全重叠,GPU 利用率 100% 瓶颈情况(存储跟不上): GPU: [计算] 等待 [计算] 等待 [计算] 等待 Data: [====加载====] [====加载====] GPU 空闲等待数据,利用率 < 50% 8.2 优化策略 1. 本地缓存预热(最有效) # 训练开始前,将热数据预加载到本地 NVMe # 使用 Init Container 实现 initContainers: - name: data-prefetch image: python:3.11-slim command: ["bash", "-c"] args: - | echo "Prefetching training data to local NVMe cache..." rsync -avP /data/dataset/train/ /data/cache/train/ \ --include="*.parquet" --exclude="*" echo "Prefetch complete: $(du -sh /data/cache/train/)" volumeMounts: - name: training-data mountPath: /data/dataset readOnly: true - name: nvme-cache mountPath: /data/cache 2. 多 Worker DataLoader from torch.utils.data import DataLoader train_loader = DataLoader( dataset, batch_size=32, num_workers=8, # 多进程预取 pin_memory=True, # 锁页内存,加速 GPU 传输 prefetch_factor=4, # 每 worker 预取 4 个 batch persistent_workers=True, # worker 进程常驻,避免反复 fork ) 3. WebDataset / Mosaic StreamingDataset 对于超大数据集(PB 级),传统的文件级随机读取效率极低。WebDataset 将数据打包为 TAR 分片,实现顺序读取: import webdataset as wds # 数据以 TAR 分片存储在对象存储 dataset = ( wds.WebDataset("s3://bucket/dataset/shard-{000000..009999}.tar") .shuffle(10000) .decode("pil") .to_tuple("input.jpg", "target.cls") .map_tuple(transform, identity) .batched(32) ) # 优势: # - 顺序读取,最大化存储吞吐 # - 内置 shuffle,无需随机 seek # - 原生支持 S3/GCS 流式读取 # - 数据分片天然支持多 worker 并行 8.3 模型加载优化 大模型的加载时间也不可忽视——一个 70B 模型约 140 GB,从网络存储加载可能需要 5-10 分钟: 优化方案 原理 加载时间 (70B) 默认 NFS CPU 内存 → GPU ~10 min 本地 NVMe 预拉取到本地 ~2 min GCS FUSE + Cache 对象存储 + 本地缓存 ~3 min (首次), ~1 min (后续) Secondary Boot Disk 预烤镜像 ~30 sec GPUDirect Storage 直接加载到 GPU ~1 min Fluid 数据加速 分布式缓存加速 ~1.5 min # 使用 Fluid 数据集加速(CNCF Sandbox 项目) apiVersion: data.fluid.io/v1alpha1 kind: Dataset metadata: name: model-repo spec: mounts: - mountPoint: s3://model-bucket/llama-70b/ name: llama70b options: fs.s3a.endpoint: s3.amazonaws.com --- apiVersion: data.fluid.io/v1alpha1 kind: AlluxioRuntime metadata: name: model-repo spec: replicas: 3 tieredstore: levels: - mediumtype: SSD path: /mnt/nvme/cache quota: 500Gi high: "0.95" low: "0.7" 九、总结与全景回顾 本文深入了 AI 算力平台的两大基础设施短板——网络和存储。核心要点回顾: 高性能网络与存储知识地图: 1. 为什么需要 RDMA: └── AllReduce 通信占 30-50%,TCP 延迟 + CPU 开销不可接受 2. RDMA 三大流派: ├── InfiniBand: 无损原生、性能最优、成本最高 ├── RoCE v2: 以太网硬件、需 PFC+ECN、性价比好 └── 云厂商 RDMA: EFA/eRDMA、容忍丢包、开箱即用 3. GPUDirect 家族: ├── GDR: GPU↔NIC 直通,消除 CPU 拷贝 └── GDS: GPU↔NVMe 直通,加速 Checkpoint 4. K8S RDMA 集成: ├── Multus CNI: 多网络接口 ├── SR-IOV: 硬件级虚拟化 └── NCCL: 通信库调优 5. 双平面网络: └── 管理网 (TCP 25G) + 训练网 (RDMA 400G) 物理隔离 6. 分层存储: └── 本地 NVMe (热) → 分布式 FS (温) → 对象存储 (冷) 7. Checkpoint 策略: ├── 异步写入: 减少 90%+ 暂停 ├── 分片保存 (DCP): 避免 OOM └── 本地缓存 + 异步同步: 生产最佳实践 8. 数据管道: └── 预热缓存 + WebDataset + 多 Worker DataLoader 下一篇预告 网络和存储搞定了,平台架构也设计好了——但在真正推向生产之前,还有最后一道关卡:运维、安全和成本。 第 6 篇《生产运维、安全与成本优化:将 AI 算力平台推向生产》 将深入: GPU 故障类型有哪些?如何实现自动化故障检测与恢复? 多租户环境下,如何做到 GPU 资源的安全隔离? 可观测性体系如何设计?哪些 GPU 指标必须监控? 成本优化有哪些策略?GPU 共享、Spot 实例、队列管理如何配合? GitOps 和平台工程如何让运维可控、可复现、可审计? 从 PoC 到生产的分阶段实施路线图是什么? 这是整个系列的收官之作——让一切从"能跑"变成"能用在生产上"。 参考资料 The Llama 3 Herd of Models - Meta - Llama 3 训练基础设施细节 RDMA over Commodity Ethernet - RoCE v2 - RoCE 技术规范 NVIDIA GPUDirect RDMA - GPUDirect RDMA 官方文档 NVIDIA GPUDirect Storage - GDS 官方文档 NCCL Documentation - NCCL 用户指南 Multus CNI - 多网络接口 CNI SR-IOV Network Device Plugin - SR-IOV 设备插件 AWS EFA Documentation - AWS EFA 弹性网络 PyTorch Distributed Checkpoint - DCP 官方文档 Fluid - CNCF Sandbox - 数据集加速引擎 WebDataset - 大规模数据集加载库 InfiniBand Trade Association - IB 技术规范 关注公众号「coft」,获取更多 AI 实战干货和 AI-Infra 深度教程。