
1. AI负载凭什么改写了分布式系统的设计规则先说个我观察了很久的现象很多有分布式系统背景的团队一接触大模型训练和推理第一反应是“这不就是分布式系统的一个新场景吗”。结果真把微服务那套经验搬过来之后发现处处碰壁。问题不在分布式理论本身而在AI负载对分布式系统的要求几乎把传统设计原则反过来了一遍。这个系列前两篇聊了分布式系统的基础协议、一致性模型和数据副本机制。到了第三篇我们把视线彻底转向分布式AI系统一个集群里跑着大模型训练和在线推理服务时分布式架构到底该怎么设计并行策略怎么选基础设施又该怎么配套。这篇不打算做理论综述就讲我在实际项目里看到的、踩过的、最后沉淀下来的东西。1.1 负载模式从随机请求变成确定性集体通信传统Web服务或者订单系统流量模型是“随机请求”。用户什么时间点来、查哪个数据、请求什么接口你很难预测。所以架构上要搞无状态、多副本、负载均衡把随机流量摊到大量实例上。AI场景完全不是这么回事。训练任务的计算图是固定的每一次迭代都包含一次全局梯度同步这意味着系统内的通信模式是确定性的、周期性的、集体性的——所有GPU卡必须同时参与对等通信。推理任务虽然请求是随机到达的但每个请求的处理路径高度相似都要经过同样的模型层、都要读写同一个模型的KV Cache。这种差异带来的架构后果非常直接传统分布式可以靠“加机器”来解决大部分扩展问题而AI系统首先要解决的是“这些机器之间的通信怎么组织、怎么降低开销”。你加100张卡如果AllReduce通信设计得不好可能比8张卡还慢。这在Web服务里几乎不会出现。1.2 故障语义从可用性优先变成“宁停不要错”传统分布式服务的故障处理逻辑是挂了就重启请求切走短暂不可用可以接受关键是别丢数据。所以大家习惯做多副本、做自动扩缩容K8s滚动更新一个服务毫无压力。训练任务不行。一个训练跑了一半挂了你需要恢复的不只是“进程”还有模型权重、优化器状态、数据加载位置、随机数种子状态。随便一个不一致训练结果就废了几十个小时的GPU算力白烧。更麻烦的是大模型训练里“静默错误”比崩溃更可怕——显存比特翻转、梯度传播出NaN传统健康检查根本发现不了。所以AI系统对分布式基础设施的要求是“确定性”要么严格成功要么严格失败并且可从检查点恢复中间不能出现部分成功、部分失败的状态。这一点后面讲到检查点设计时会仔细展开。1.3 资源形态GPU不是CPU不能随便扩容传统分布式资源管理考虑的是CPU、内存、网络带宽这些资源池化之后给容器分配就行了很成熟。到了GPU时代事情变复杂GPU的显存容量决定了一个模型能不能放得下GPU的算力决定了计算时间而GPU之间的通信带宽决定了多卡协同的可行性。更关键的是GPU资源很难“pooling”——A100 80G和A100 40G是两个物种NVLink互联的8卡和普通千兆网联的8卡更是天壤之别。这带来一个核心约束传统分布式可以先架构后优化AI系统必须从第一行架构设计就开始考虑显存和通信带宽的预算。这也是为什么这一篇会花大量篇幅在“算账”上。2. 训练并行的底层账本显存、通信与切分方式的选择进入训练阶段分布式架构的核心问题只有一个模型太大放不下或者算太慢怎么把训练任务拆到多张卡上同时尽量保证GPU利用率。很多人一上来就问“该用哪种并行策略”我的建议是先算账再谈策略。2.1 单卡放得下吗显存账本怎么算训练一个大模型的显存占用主要由四部分构成模型权重参数量乘以每个参数占用的字节数。FP16混合精度训练权重通常以FP16保存每参数2字节。优化器状态Adam优化器需要保存FP32主权重、一阶动量、二阶方差每参数大约12字节。梯度通常也是FP16每参数2字节。激活值前向传播过程保存的中间张量和batch size、序列长度直接相关。以13B参数模型为例权重26GB优化器状态大约156GB梯度26GB这就已经200多GB了还没算激活值。一张A100 80G根本放不下。这就是为什么7B以上的模型几乎都必须做分布式训练。注意很多人只算权重不算优化器状态结果模型明明“放得下”一训练就OOM。我见过不止一个人拿着FP16权重的大小去判断显卡够不够反手就被优化器状态教育了。2.2 数据并行梯度AllReduce是最大的通信压力数据并行是最直观的切分方式每张卡放一个完整的模型副本训练数据切成N份分给N张卡每张卡各自前向反向然后把梯度做AllReduce得到全局梯度再各自更新参数。这里的核心难点是梯度同步的通信量。以13B模型为例每步训练都要对所有参数进行一次梯度聚合理论上通信量约等于模型参数的2倍Ring AllReduce的通信量近似2倍模型大小也就是大约50GB。如果跑在10Gbps网络约1.25GB/s上光通信就要40秒而GPU计算一步可能只要一两秒——计算时间被通信完全淹没。所以数据并行的关键配套条件非常苛刻要么网络带宽极高比如InfiniBand 200Gbps起步要么梯度压缩比如梯度裁剪、TopK稀疏化要么用大规模batch配合学习率缩放。我遇到过一个团队在千兆网环境里硬跑数据并行结果训练速度比单卡还慢最后发现通信占了95%以上的时间。小提示数据并行增大batch size之后学习率不是原样照搬的。经验法则是线性缩放batch从32变成64学习率大约可以翻倍但同时也要做更长的warm-up。这个规则在中小batch范围内还算可靠但batch大到一定程度就必须配合学习率调度、自适应优化器等调整盲目放大batch容易收敛到次优解。2.3 张量并行与流水线并行切出性能和气泡数据并行不解决单卡放不下的问题张量并行和流水线并行才是解决模型的“放不下”的。张量并行是把一个层内部的矩阵运算切到多张卡上。以Transformer里的线性层Y XW为例把权重矩阵W按列切成两份两张卡各算一半然后做一次AllReduce把结果合并。切分之后每张卡只持有1/N的权重和优化器状态显存压力骤减。但代价是每个Transformer层的前向和反向都要各做一次集体通信层数一多通信次数就非常密集。所以张量并行有两个经验法则第一它通常只在单机内部使用因为NVLink的延迟和带宽远好于跨机网络第二切分的维度一般控制在8卡以内切到16卡以上通信占比会急剧恶化收益反而变小。流水线并行则是按层切分模型有96层4个stage各管24层数据从前到后流过所有stage。它的核心问题是“气泡”——流水线不满载的空白时间。气泡率粗略估算为(p-1)/(mp-1)p是stage数量m是微批次数。stage越多气泡越大微批次数越多气泡越小。引入1F1B调度一个前向一个反向交替执行之后可以从整体上平衡显存和气泡率。2.4 一个70B模型的切分实例把三种并行组合起来用是现在大模型训练的标准做法。拿70B模型的训练为例假设我们手上有8台8卡A100 80G的机器总共64卡张量并行8在单机8卡内切分模型层利用NVLink高速通信。流水线并行4把模型层切成4段分布在4台机器上。数据并行2两个完整的模型副本分别处理不同batch的数据。算一下显存70B参数混合精度训练每参数大约需要16字节的权重加优化器状态总计约1120GB。经过TP8切分和PP4切分后每张卡只持有1/32的模型状态大约35GB。再加上激活值和通信缓冲区80G显存是有富余的。这个切分方案在实际项目中也是经过验证的主流选择。为什么TP8而不是TP4因为70B模型单层参数巨大TP4时每卡需要持有的权重和激活值都更多反而容易触顶显存。为什么PP4而不是PP8因为stage越多气泡越大4个stage的空闲开销还能接受8个stage就会明显拉低利用率。这些数字不是拍脑袋定的是先估算再跑实验微调出来的。3. 在线推理不是训练的精简版KV Cache、动态批处理与PD分离训练搞清楚了很多人下意识觉得推理就是“把训练好的模型加载起来调用一下forward就行”。实际做过在线推理服务的人都知道推理部署的坑一点不比训练少而且侧重点完全不同。3.1 为什么推理侧的并行策略要“保守”得多训练对延迟不敏感一个batch跑多慢都行只要吞吐高、GPU利用率高。推理完全不同线上请求等不起一次生成几十个token用户能明显感受到返回速度。模型放不下时的第一反应是“那就张量并行呗”。但在推理场景张量并行会把通信延迟直接加到每次请求的关键路径上每生成一个token都要跨卡做两次AllReduce。8卡TP的额外延迟可能比模型本身的单卡计算时间还长这就非常不划算了。所以在推理侧更常见的思路是尽量让模型在一张卡内跑完能量化就量化能用int8/int4就用实在放不下再考虑TP且TP度数能小就小。推理场景还有一个训练里不太考虑的选项把部分权重临时卸载到CPU内存或者NVMe SSD上用的时候再换入显存。这种offload方案会牺牲部分速度但能把超大模型跑在少得多的GPU上。3.2 KV Cache才是显存规划的主角训练时显存占用的大头是优化器状态和激活值推理时这些都没有了。但推理引入了一个训练里不存在的显存消耗KV Cache。Transformer自回归生成时每个token都要用到之前所有token的Key和Value向量。为了避免重复计算系统会把这些向量缓存下来。KV Cache的大小可以精确计算每个token的KV Cache 层数 × 注意力头数 × 每头维度 × 2K和V × 2FP16字节拿7B模型举例假设32层、32个注意力头、每头128维那么每个token需要32 × 32 × 128 × 2 × 2 524,288字节也就是512KB。如果并发处理32个请求每个请求的上下文长度是1024个token那么仅KV Cache就需要512KB × 32 × 1024 16GB显存。这个数字一出来你就明白为什么推理服务的显存规划要从KV Cache算起了。很多模型本身只占20GB结果并发一上来显存先被KV Cache填爆了。更麻烦的是KV Cache是动态增长的——一个请求生成的token越多占的显存越大。请求到达时间又不一样显存很容易出现碎片化。3.3 连续批处理让推理吞吐翻倍的原理传统推理服务用“静态批处理”攒够N个请求一起做前向计算。但是batch里每个请求生成速度不一样短请求干等长请求生成完才能释放GPU空转和显存浪费都很明显。连续批处理Continuous Batching的思路是按迭代来调度。每个迭代结束后完成的请求立刻腾出位置新请求随时插入batch不再是固定集合而是动态变化的请求流。这样GPU始终在处理最紧迫的请求吞吐量可以提升一到两个数量级。这个机制听起来不复杂工程上却要处理很多细节KV Cache如何做内存池分配和管理、请求优先级如何排队、显存碎片如何回收。如果你正在自研推理框架我建议优先把KV Cache的内存池设计好这决定了在线推理服务的天花板。3.4 Prefill与Decode分离部署自回归生成分为两个阶段Prefill阶段处理用户输入的整个prompt并行计算所有位置的中间状态计算密集、GPU利用率高但不那么怕延迟Decode阶段一个一个token地生成每个token只计算最后位置访存密集但对延迟极其敏感。把两个阶段放在同一批卡上必然顾此失彼。所以现在主流方案是PD分离Prefill实例用大batch把计算吃满Decode实例专门优化增量计算和KV Cache读写。网关层根据请求的序列长度、当前两个实例群的负载情况把请求路由到合适的地方。实际项目里PD分离之后还要解决一个关键问题Prefill实例算完的KV Cache如何传给Decode实例。你会发现这本质上是一个分布式系统里的状态迁移问题——大体积的KV Cache如何高效序列化、传输、重建。这一层做得好的推理平台和做得一般的线上延迟差距能到一倍以上。4. 文件系统、缓存、锁与定时任务AI基础设施的协同角色分布式AI系统不是只有训练和推理框架底下的分布式基础设施同样决定成败。这个部分容易被忽略但一旦出问题往往是连锁式事故。4.1 训练数据从哪来HDFS/对象存储与本地缓存的配合训练数据集的体量通常是TB到PB级别不可能全部放在GPU节点的本地盘。传统做法是放在HDFS这类分布式文件系统上训练框架通过DataLoader远程读取。HDFS在大数据领域很成熟但直接用在AI训练上有几个痛点HDFS对小文件的随机读不友好而很多预处理后的样本恰好是大量小文件。HDFS的元数据节点在高并发读取时会成为瓶颈。所以现在的常见做法是数据底座用HDFS或者对象存储但每个训练节点配一块大容量SSD做本地缓存。数据先按序拉取到本地训练时读本地文件避免每一次迭代都打远程存储。一个容易踩的坑是数据本地性和训练进度的耦合。DataLoader如果从远程存储拉数据拉慢了GPU就会空转等待。所以大集群训练前把数据预热到本地缓存是性价比最高的优化手段别小看这一步。4.2 分布式缓存Redis的边界与模型权重缓存AI系统里到处需要缓存但不同场景要选不同方案。特征处理和样本去重这类场景key-value结构的数据规模不大、访问频繁Redis是合适的选择。但如果你想拿Redis缓存大模型权重文件我建议趁早放弃。几百MB到几个GB的二进制模型权重序列化开销大、内存占用高、网络传输也不划算。模型权重的分发更合适用对象存储配合内容寻址来管理——简单说每个权重文件算一个哈希值作为文件名存到对象存储里各节点按需拉取并缓存在本地DFS目录。这样既能保证文件版本唯一又能利用内容哈希天然去重。4.3 分布式锁防止“同一个实验跑两份”训练平台化的过程中分布式锁是个容易被低估的组件。比如同一个实验配置被手动触发两次两个训练任务同时启动互相抢GPU资源最终结果还没法对齐。再比如模型发布时新旧版本切换需要原子操作不能出现流量已经打到新版本、旧版本却在清理文件的中间状态。分布式锁的实现Redis锁能用但要注意租约续期否则锁过期任务还在跑就可能出现双主。更稳的方案是用etcd这类支持Watch和租约的协调服务。锁的粒度也要想清楚训练任务级别还是资源配额级别锁的时间阈值设多少业务上要明确。4.4 分布式定时任务把训练变成自动化流水线模型需要定期重新训练。手动跑实验的做法在小规模阶段没问题模型多了以后必须上分布式定时任务。这里的难点远远超过cron表达式任务执行到一半失败怎么办要不要重试多个定时训练任务同时触发GPU资源不够怎么排队和抢占训练完成之后的数据评估、模型发布、监控回滚怎么串联起来。我见过一个平台级的方案用分布式调度器统一管理所有训练任务每个任务带资源需求和优先级调度器实时感知集群资源支持任务排队、抢占、失败重投。这套系统跑起来之后团队才从“手动调参拉训练”里解放出来。4.5 分布式事务在AI里长什么样业务系统里的分布式事务比如订单和库存强调的是多个服务之间的数据原子性。AI系统里真正需要“事务”的地方不太一样但同样存在最典型的就是模型版本发布。一次完整的模型发布涉及模型权重文件、训练代码版本、训练数据版本、超参数配置、评测指标这些东西分布在文件存储、代码仓库、配置中心、指标数据库里。如果只更新了权重文件而没同步更新配置记录后续追溯和回滚都会混乱。AI项目里实现这类“事务”不需要两阶段提交那种重型协议更实用的思路是对象存储里用不可变文件加版本号每次发布生成一条不可变的版本记录所有关联信息全部落齐之后再把版本指针原子切换到新记录上。这套思路借鉴了分布式系统里“日志就是状态”的思想实施成本低一致性收益非常明确。5. 从排障记录里沉淀出来的几条实战底线内容写到这技术组件基本都过了一遍。但拿这些组件搭出一个能稳定跑的分布式AI系统中间还隔着一堆经验问题。我最后分享几条从实际排障过程中沉淀下来的底线。5.1 先算后搭一分钟完成的显存和通信预算动手搭集群之前先用纸面估算做一遍预算。显存账本上面讲过按权重、优化器状态、激活值、KV Cache分别估算。通信预算则要算每一步训练的通信量多大除以实际可用带宽看通信时间占单步时间的比例是否能控制在20%以内。超过这个比例训练效率会肉眼可见地下降就该重新考虑并行策略的切分方式。很多分布式训练的失败不是“技术不会”而是“没算就搭”。我见过一个团队不加估算直接把13B模型塞到8卡环境里做张量并行结果显存勉强过了但通信开销巨大GPU利用率只有30%。先算十分钟能省下好几天调优。5.2 监控与检查点分布式训练容错的两个核心分布式训练的监控最该盯紧的指标不是GPU利用率而是通信占比和等待时间。GPU利用率高不代表效率高有可能是通信阶段大家都在空等。我建议在每个训练step里埋点统计计算时间和通信时间让这两个数字单独上报长期趋势一眼就能看出并行策略是否健康。检查点设计是另一个容易出问题的地方。多卡训练保存检查点时必须保证所有rank的状态一致权重、优化器、学习率调度器、数据加载位置、随机数种子任何一项缺了恢复出来的训练结果就和原来对不上。保存流程要像写数据库事务一样先各卡把状态写到临时目录全部成功后原子切换文件指针再统一清理旧检查点。否则训练到一半崩了恢复出来的模型精度莫名其妙掉一截排查起来极其痛苦。5.3 一次推理服务性能抖动排障实录最后分享一个真实排障案例正好把这篇提到的知识点串起来。线上一个对话模型的推理服务日常P99延迟稳定在300ms左右某天突然涨到900ms而且半小时抖动一次。先说结论直接原因是显存碎片化导致的KV Cache分配不连续带宽利用率下降深层原因是没有给KV Cache做内存池化。排查过程可以分为三层。第一层先看监控确认模型计算延迟没有明显变化问题出在生成阶段的KV Cache读写上。第二层看显存分配情况发现每次请求释放后KV Cache空间没有按照固定块回收而是频繁进行大块内存的分配释放碎片化严重。第三层和连续批处理的队列长度做了交叉比对发现抖动频率和长请求离开batch的节奏高度重合——长请求退出时释放的大块内存会被急切地分配给新请求反复搬运。修复方案就是给KV Cache建立固定大小的块式内存池按序列长度动态申请连续块用完回收后尽可能复用。改完后P99延迟回落稳定。这个案例想说明的是推理系统的性能问题往往不在模型计算本身而在分布式状态下资源调度和内存管理的细节。分布式AI系统的核心能力说到底就是把计算、通信、存储、调度这些原本分散的分布式组件放到AI负载的特性下重新协调。很多时候没有黑科技只是每层都算清楚账每层都做好容错。这个系列后续我还会继续写训练稳定性、推理成本优化这些方向的实践有兴趣的可以接着看。