
做推理服务这几年我经常被问到同一个问题单卡能跑的模型是不是就没有必要上分布式推理其实这个问题的答案取决于你把“分布式”理解成什么。如果只是把一个大模型拆开放到多张卡上那确实很多场景不需要但如果你想要的是一个能扛住多路并发请求、按负载自动扩容、跨节点访问资源、甚至在某个节点挂掉之后还能继续服务的推理网络那分布式就绕不开。这篇文章想聊的就是从零开始搭一套分布式推理网络的具体过程。我会用一个典型的真实部署场景做底子多节点GPU集群跨节点部署模型推理服务前面挂网关做路由和负载均衡后面是多个推理引擎节点协同工作。内容会覆盖推理集群怎么组网、跨节点协同用哪些并行策略、请求进来之后怎么调度、以及我实际踩过的坑。适合有基础部署经验、正准备把推理服务从单机往多机迁移的工程师也适合做推理平台研发的算法同学参考。1. 先想清楚分布式推理到底要解决什么问题分布式是个手段不是目的。在设计一套推理网络之前我会先花时间把问题定义清楚。否则很容易出现“用分布式的复杂度换来了单机本来就能解决的性能”得不偿失。1.1 单卡放不下被忽略的显存膨胀很多人在评估模型能不能单卡跑的时候只看模型权重的显存占用比如一个7B模型用BF16加载大约15GB40GB的卡好像挺宽裕。但真正部署起来就会发现显存根本不是这么算的。以我常用的7B模型为例实际显存占用通常包含四块模型权重、KV Cache、推理时的临时激活值、以及CUDA上下文和其他运行缓冲。序列长度一上来KV Cache的膨胀非常吓人。按每层KV Cache大小估算7B模型在8K上下文、1024并发请求的场景下KV Cache就可能接近40GB。也就是说单卡部署7B模型长上下文场景下很快就会OOM。70B模型就更难了。170B的FP16精确推理需要约280GB显存而单机8卡A100 80G也就640GB理论上能塞下但如果考虑KV Cache和并发单机依然捉襟见肘。所以第一种分布式需求本质上不是“想不想把模型切开”而是“单卡物理上放不下只能放到多卡甚至多节点上”。1.2 显存够用但吞吐上不去还有一类场景模型其实能单卡放进去但并发请求一多单卡的算力和显存带宽就成了瓶颈。我这里有一个很直观的例子用单张A100 80G部署一个13B模型模型权重占27GB跑16K上下文时单卡能稳定支撑约30路并发请求。一开始觉得挺不错但业务方过来说需要300路并发那这时单卡即使能通过扩大batch硬扛也会面临两个问题一是显存不够装那么多KV Cache二是单卡的计算单元会被长时间占满让每个请求的TTFT和TPOT都明显变差。分布式推理在这类场景里的作用是通过多个节点分担请求压力而不是单纯把一个模型切开。这个思路其实就是数据并行和多副本部署的雏形。很多团队在实际落地中最刚需的并不是“大模型多卡切分”而是“多个推理节点协作承接高并发”。1.3 单节点可用性故障域必须分散还有一个很容易被忽视的点是故障安全。我在生产环境里经历过一次整机内存故障那个节点上跑了3个推理实例结果所有路由到那个节点的请求全部失败而且因为健康检查周期是30秒在线上的表现就是“服务突然变慢然后部分请求超时”。单节点部署尤其是把所有实例都放在一台机器上意味着这个节点的电源、内存、GPU、网络任何一个环节出问题都会直接暴露给用户。分布式网络的一个重要价值就是故障域分散。当一个节点不可用网关能自动摘除这个节点把流量打到别的副本上。要做到这一点依赖的不只是推理引擎本身还要求整个系统的路由层、健康检查机制、节点注册发现问题都能联动起来。这也是“推理集群组网”和“分布式推理网络”这两个词背后最实际的意义。1.4 分布式推理的两条主线我习惯把所有相关工作拆成两条主线后面所有设计和反复调优都围绕这两条线第一是集群组网解决的是硬件拓扑、网络连通性、资源管理和通信库配置的问题。说白了就是让多台机器的GPU能够互相通信形成一个可以被调度的资源池。第二是跨节点协同解决的是模型怎么切分、请求怎么分配、任务怎么调度、异常怎么恢复的问题。这是分布式推理的核心也是理论上最复杂的地方。下文我会按这两条主线展开先把集群组网讲透再进入跨节点协同的细节。2. 推理集群组网从一个可用的硬件拓扑开始组网这一步看起来像“拉网线、装驱动”但实际做的时候很多问题是在这里埋下的。尤其是当模型要跨节点做张量并行时通信的带宽和延迟会直接决定推理性能光看显卡本身根本不够。2.1 硬件选型与比例我当前环境采用的是一组相对常见的配置8个GPU节点每个节点8卡卡型是80G显存的A800CPU是64核内存512GB系统盘用NVMe SSD模型数据放在并行文件系统上。这个配置里CPU核数和内存往往是被低估的。推理引擎不只是算GPU它还要处理请求的预处理、tokenize、采样、调度、日志、指标上报等一大堆CPU任务。如果CPU核数太少即使GPU算力空着请求还是会在CPU侧排队。我通常建议每张GPU至少配8个物理核内存按每张卡6到8GB算。比如8卡节点内存64GB起步实际生产环境我建议直接上128GB以上缓存和临时数据会吃掉不少。SSD也很关键加载一个大模型文件到显存从并行文件系统读几十GB数据如果磁盘IO不行模型冷启动可能要等十分钟以上这在自动扩缩容场景下根本没法用。2.2 网络拓扑Spine-Leaf 为核心推理集群内部流量有三个方向设计网络时最好分开考虑管理流量SSH、监控、控制面通信量不大但对可用性敏感。存储流量模型加载、数据集读取大文件传输带宽敏感。推理通信流量跨节点张量并行、流水线并行时的中间结果传递既带宽敏感又延迟敏感。我们组网采用的是Spine-Leaf两级架构。Leaf层按GPU节点接入每个节点两张25G网卡做bonding分别连接两个不同的Leaf交换机Spine层作为核心互联。GPU节点之间的跨节点通信走RoCEv2用的网卡是支持RDMA的25G卡存储节点走单独的存储网络。这里有个经验供参考如果条件允许跨节点张量并行的通信最好跑在100G以上的RDMA网络上。25G能做但张量并行通信量非常大端到端推理时延会明显上升。如果预算有限更建议先通过数据并行解决并发问题把张量并行限制在同一节点内的8卡之间因为节点内NVLink带宽远高于网卡。2.3 IP与端口规划这个细节不复杂但规划不好会影响后期扩展。我习惯把节点按角色划分网段比如GPU推理节点172.16.10.0/24每台机器一个管理IP和一个RDMA IP。存储节点172.16.20.0/24。网关和负载均衡节点172.16.30.0/24。这样做的好处是安全策略和监管规则可以按网段下发排查问题时看IP段就能判断流量路径。端口规划上每个推理引擎进程至少需要两个端口一个用于接收外部推理请求一般是HTTP/gRPC端口另一个用于节点间通信和分布式协调。如果用了RayRaylet默认会占用多个端口要提前在防火墙和安全组里放行同时在配置里固定端口范围避免每次启动动态分配导致可用性问题。2.4 通信环境检查NCCL 是重中之重跨节点协同一旦遇到通信问题大多数情况下都出在NCCL配置上。NCCL是NVIDIA的集合通信库PyTorch DDP、Megatron、vLLM等多卡训练推理都会用到它。简单地跑通一个矩阵乘法但跨节点性能上不去基本都是NCCL没调好。我常用的检查方法分三档第一档是网络连通性检查。用ping和ib_write_bw或RoCE的perftest工具打点测带宽。第二档是NCCL测试。跑nccl-tests的all_reduce_perf比如8机每机8卡看跨节点带宽是否接近网卡上限。如果你发现跨节点带宽经常只有理论值的1/5先别怀疑网卡先检查是不是掉到了TCP模式没有走RDMA。第三档是实际推理框架的通信日志。vLLM这类框架在多卡推理时会输出设备信息和NCCL初始化日志注意看日志里网络接口的IP是不是走了预期的RDMA网段而不是管理网段。还有一个小坑如果/etc/nccl.conf里设置了NCCL_SOCKET_IFNAME一定要指向正确的物理网卡名比如ens3是管理口ib0是RDMA口配错了会导致所有跨节点通信都走管理口网络一忙整个集群都卡顿。3. 跨节点协同并行策略怎么选硬件组好之后跨节点协同才是真正的重头戏。跨节点协同的本质是把大模型的计算、显存、通信进行拆分和重组。实际推理场景里最常用的三个并行策略是张量并行、流水线并行和数据并行它们的侧重点完全不同。3.1 张量并行把每层的计算切开张量并行是把模型每一层的矩阵运算拆分到多张GPU上并行计算。通俗地说本来一个(4096, 4096)的矩阵乘法由一张卡完成现在切成两半两张卡各算一半再拼起来。这种方式的好处是显存压力分摊非常直接模型权重、激活值、梯度都能按切分比例减少。一个70B模型用8卡张量并行每卡只承担约1/8的权重和计算量单卡显存完全能放下。代价是通信极其密集。每一次矩阵乘法后卡与卡之间都要做AllReduce交换中间结果这个通信量和模型宽度成正比。所以张量并行的扩展不是无脑的实践经验是单节点8卡以内效果很好超过8卡跨节点以后每增加一张卡通信开销会快速蚕食算力收益。在分布式推理网络里我通常把张量并行限制在一个节点内跨节点不做张量并行否则网络的带宽和延迟会成为硬瓶颈。3.2 流水线并行按层切模型流水线并行是把神经网络按层切成多个Stage每个Stage放在不同的GPU或节点上。比如一个36层的模型切成4段每段9层4个GPU串行处理。流水线并行最大的优点是对通信带宽要求低因为只需要在Stage边界传递激活值和梯度不像张量并行那样每层都要通信。缺点是存在天然的空闲气泡即前一个Stage算完才能交给下一个流水线中间会有等待。推理场景里流水线并行并非常态选择。因为推理是逐token生成的串行依赖本来就很强流水线并行会让请求链路变长latency变差。我通常只在两种情况下用流水线一是模型大到单节点放不下必须跨节点二是做Prefill和Decode分离时将前处理和生成逻辑拆到不同批次的实例上。其他情况下优先用数据并行多副本而不是流水线并行。3.3 数据并行最划算的并发扩展数据并行其实最简单同一个模型加载到多个GPU或多个节点上每个副本独立处理不同的请求互不干扰。从系统角度看这些副本构成了一个无状态服务池请求可以任意路由到任何一个副本。数据并行对跨节点协同的技术要求最低扩容也最容易只需要注册新的副本到服务发现组件网关就能把流量分担过去。缺点是每个副本都要完整加载模型显存占用线性增长对于超大模型来说硬件成本很高。但对大多数线上推理场景数据并行是最稳定、最可运维的方案。3.4 混合并行以请求类型为导向实际部署中我不会只用某一种并行策略而是根据请求类型做组合。这里分享一个我常用的分法短文本、高并发走数据并行动态批处理每个副本独立处理请求网关按权重轮询。长文本、大上下文使用张量并行大显存实例减少KV Cache换入换出最好单节点内8卡TP。超大模型使用张量并行流水线并行混合切分把模型拆到多个节点同时每个节点内部通过NVLink加速。这套组合的好处是能按业务场景动态调度资源而不是用一套配置去硬扛所有请求。比如我线上环境把短文本请求路由到一批L20节点长文本请求路由到一批A800节点网关根据请求的prompt长度和max_tokens做路由实测排队时间下降明显GPU利用率也更均衡。4. 推理服务化请求路由、动态批处理与KV Cache跨节点协同不光是把模型切开还要把推理服务真正变成一套能对外提供服务、能动态扩缩容、能自动容错的网络。这一部分主要讲控制面和数据面的协同。4.1 网关层请求怎么找到对的节点分布式推理网络的前端一定有个网关它承担服务发现、路由、负载均衡、限流和健康检查。我自己用的方案是Nginx做七层负载均衡后面接一组推理引擎实例实例启动时向服务注册中心注册IP和端口定期上报心跳。路由规则上我目前的策略是按模型版本路由/v1/models/{model_name}路径拆出模型版本。按请求类型路由根据prompt长度、max_tokens、是否需要流式返回决定走哪组instance。按权重路由不同节点算力不同配不同权重比如A800节点权重设为2L20节点权重设为1。这里有一个实际经验不要把流式请求和非流式请求混在同一组实例上。流式请求会长时间占用一个worker的流式连接导致后面的普通请求排队。我踩过这个坑之后把SSE流式请求单独路由到一组实例普通短文本请求走另一组整体p99明显下降。4.2 动态批处理吞吐和延迟的平衡单个推理引擎内部请求会进入调度队列调度器把队列里的多个请求拼成一个batch喂给GPU并行计算这就是Dynamic Batching。这么做是为了提高GPU利用率因为推理计算要等GPU资源如果一个个请求单独跑GPU大部分时间都在等待数据搬运。动态批处理有几个参数很关键max_num_seqs一个batch最多包含多少条请求。太小吞吐上不去太大单条请求等待时间过长。max_seq_len_to_captureKV Cache预分配的长度上限。调度策略饥饿优先还是FCFS先来先服务。实践上我一般先把max_num_seqs设为GPU显存能够承受的最大值再降20%作为安全余量避免个别长序列把缓存撑爆。比如A800 80G卡跑7B模型32K上下文max_num_seqs设32左右比较稳。4.3 KV Cache管理和预分配KV Cache是推理服务内存管理里最核心也最容易出事故的部分。对每个请求推理引擎需要为它的context分配一份KV Cache上下文越长KV Cache越大。如果不同请求长度差异很大静态预分配会导致浪费动态分配又容易造成显存碎片。目前主流推理框架会把KV Cache按显存剩余容量做完块预分配比如vLLM的PagedAttention就是把KV Cache拆成固定大小的块按需分配和释放类似操作系统虚拟内存的分页。这个设计让KV Cache利用率显著提高也让我们能把更大的并发请求塞进同一张卡。跨节点场景下KV Cache的管理更要注意如果一个请求因为负载均衡被调度到了节点A但它的上下文已经保存在节点B那要么接受冷启动重新计算要么引入分布式KV Cache让缓存可共享。目前线上业务我们优先保证同一个客户端的会话亲和性通过网关层的一致性哈希把同一路会话的请求固定路由到同一组实例大幅减少跨节点缓存搬迁。4.4 动态扩缩容让节点组跟着请求量走推理网络不能一直是固定节点数那样要么浪费资源要么扛不住流量高峰。我在实践中采用了两层扩缩容一是实例级扩缩容。通过Kubernetes或Ray Autoscaler监控每个推理引擎的GPU利用率、队列深度、TTFT等指标。当队列深度持续超过阈值就自动拉起新的推理实例当利用率低时自动缩容。二是节点级扩缩容。实例扩容的前提是物理节点有空闲GPU。如果整组节点都满了需要考虑扩容节点。这一步在云环境很简单直接建机器加入集群在自建机房就需要提前预留冗余节点。有一个容易被忽略的细节扩容时模型加载时间很长。如果从冷启动到服务可用需要8到10分钟那扩缩容根本无法应对突发的分钟级流量。所以我会让每个节点预烤热一个“最小可用模型”也就是节点启动时就把最常用的那个模型加载到显存拉起的副本直接注册到网关把新增流量切过去。真正复杂的模型做按需加载但会有冷启动延迟。5. 常见的坑跨节点协同的排查实录我把在搭建这套分布式推理网络过程中踩过的几个比较典型的坑记录在这里。这些问题不一定每个团队都会遇到但遇到了排查思路基本是通用的。5.1 跨节点训练通信时好时坏TLE报错现象多机8卡做张量并行启动时经常报NCCL timeout重试几次才能成功。原因排查我一开始怀疑交换机和网卡后来发现是网卡驱动版本和NCCL版本不匹配导致NCCL在初始化时回退到TCP Socket通信跨节点带宽远低于预期AllReduce超时。解决方法固定一套经过验证的驱动和CUDA版本组合把NCCL测试加进CI节点上线前先跑一遍all_reduce_perf带宽低于阈值就直接拒绝上线。5.2 GPU显存OOM但不知道是哪个环节导致现象请求并发一高模型服务直接OOM任务崩溃重启。原因排查一开始以为只是batch设太大后来仔细看监控发现某个时段大上下文请求把所有显存碎片化再有新请求时找不到连续的KV Cache块直接报OOM。解决方法一是限制单实例最大并发和最大上下文长度二是给推理引擎设置显存余量不要全部预分配完三是给每个实例设置它是“短文本优先”还是“长文本优先”避免长短请求混跑导致KV Cache碎片。5.3 流式请求导致非流式请求排队现象网关后面某几个节点延迟很高但GPU利用率并不高。原因排查打开节点日志发现一批SSE长连接请求占满了worker进程而普通短请求一直在等worker释放。解决方法把流式和非流式路由到不同实例组同时给Nginx配置连接超时与proxy_buffering off让SSE请求不要长期占用工作连接。5.4 健康检查太灵敏节点频繁被摘除现象某节点偶发延迟高网关反复摘除和恢复导致请求频繁切换节点整体成功率反而下降。原因排查健康检查探针用的是“调用一次推理接口并判断是否返回”但推理接口耗时本身就会波动偶发超时被误判定为不健康。解决方法健康检查改为“进程存活端口连通最近30秒成功率”三合一判定。只要进程在、端口通、30秒成功率不低于阈值就认为健康只有当条件持续不满足时才摘除节点。5.5 模型加载慢扩容跟不上流量现象流量高峰时扩容但新实例迟迟不能服务等它起来流量已经过去了。原因排查节点启动后需要从存储节点读取模型到显存大模型几十GB冷启动需要好几分钟。解决方法双管齐下。一是前面说的预加载常用模型二是把模型文件放到节点本地NVMe而不是每次从分布式存储拉取。首次冷启动做一次后续通过文件锁避免并发重复加载。6. 监控、告警和日常运维建议分布式推理网络比单机推理复杂一个量级没有一个完善的监控体系出了问题就是“大海捞针”。我日常最依赖的指标有下面这些节点级GPU利用率、显存占用、显存碎片率、NVLink带宽、网卡收发速率、RDMA重传率。实例级排队请求数、每秒处理请求数、TTFT、TPOT、首字延迟、尾字延迟、请求失败率。集群级总请求量、平均排队时间、待调度副本数、节点数变化、模型加载状态。告警规则我有一条至今受益的原则不要对瞬时值告警对持续状态告警。比如GPU利用率低于10%持续3分钟才告警避免偶发的空闲误报排队数连续30秒超过阈值才告警避免抖动引发无意义告警。运维层面还有一个容易被忽略的点版本管理。模型文件、推理引擎版本、运行参数这三者要绑定为一个可发布的版本不能单独升级其中一个。我出现过一次模型文件换了但推理引擎的tokenizer配置没同步更新导致生成的文本和预期不符定位了很久。7. 现在的一点点心得体会把分布式推理网络跑起来难的不是装环境、起服务而是把每个环节里的“为什么”想清楚。为什么这里用数据并行而不是张量并行为什么健康检查要用三合一判断为什么流式请求要单独一组实例这些都是线上业务反复锤炼出来的经验。如果让我给正在做这件事的人一个建议我会说先做最简单的方案。先用一组数据并行实例加一个网关把请求跑通把监控打好再根据瓶颈一步步引入更复杂的并行策略。不要一开始就追求张量并行和流水线并行的大规模协同那是把复杂度一次性推到了自己头上。最后分享一个小技巧每次上线前我会模拟一次节点故障主动把某个推理节点上的服务停掉观察网关能不能在正常时间内把流量切走。这个动作花不了几分钟但比任何配置检查都更能暴露真实问题。分布式推理网络本质上是系统工程稳定性不是配出来的是测出来的。