ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

从单卡到千卡:大模型推理集群的负载均衡与性能调优实战

从单卡到千卡:大模型推理集群的负载均衡与性能调优实战 去年底部门内部做了一次推理服务压力测试结果把所有人都整沉默了。一张性能参数相当不错的推理加速卡跑27B量级的Qwen3开源模型单并发时tokens/s数据漂亮得很演示Demo完全够用可一旦模拟真实线上流量打到20个并发首Token延迟直接飙到10秒开外生成速度也跟着崩了。这次测试让我彻底意识到一个问题单卡推理再做得好天花板就摆在那生产环境真正需要的是推理集群是从单卡到千卡都能稳定运转的架构和负载均衡策略。借这个机会我把整个从单卡推理到千卡负载均衡的思考过程、方案选型和实操踩坑整理成文。内容涉及推理引擎的核心机制、集群硬件网络规划、请求调度与负载均衡策略也包含我个人实测的具体数字和可复现的部署步骤。不管你是刚接触大模型推理还是已经在折腾多卡方案这文章应该都能给你一些参考。1. 为什么单卡推理注定撑不起生产环境1.1 显存与算力的双重天花板先说硬件层面推理卡的核心限制从来不是峰值算力而是显存容量、显存带宽和互联带宽这三样。27B量级模型就算用INT8量化权重也得占用约27GB加上推理过程中产生的KV Cache和激活值单卡显存很容易被吃满。有朋友觉得“我卡上显存勉强装下了那不就跑起来了吗”实际一测就发现问题显存占用接近上限时KV Cache分块会频繁换入换出解码速度断崖式下跌。算力也一样。推理过程中的解码阶段也叫Decode阶段是典型的访存密集型任务每个Token的生成主要受显存带宽限制算力利用率往往不高。真正吃算力的阶段是预填充Prefill也就是用户请求进来时把Prompt整体计算一遍的那一步。单卡既要处理Prefill又要处理Decode两类计算混在一起任何一个高并发请求都能把卡打满其他请求就全被堵住了。1.2 生产环境对推理系统的真实要求我们做技术方案习惯先看约束条件。生产环境的推理服务通常要满足三件事SLA稳定首Token延迟TTFT要控制在秒级生成速度不能忽快忽慢。高可用单卡故障、单机宕机不能影响整体服务要有自动摘除和重新调度能力。弹性伸缩业务高峰能快速扩容低谷能缩容省成本扩容时不能让存量连接断掉。这三点单卡一个都做不到。单卡再快也没法在故障时热切换单机再稳也扛不住突发流量。所以从单卡走向多卡、多机、千卡集群不是单纯为了“显得规模大”而是业务形态决定的必经之路。2. 推理引擎核心机制nano-vllm里的关键功能2.1 为什么要从nano-vllm入手很多人一上来就啃vLLM源码被调度器、Cache管理、SAM等一大堆概念打得晕头转向。我个人的建议是先看nano-vllm这类教学项目它把复杂推理引擎最核心的功能提取出来代码量小逻辑清晰非常适合理解“推理引擎到底在做什么”。我理解nano-vllm的核心就三块KV Cache管理、连续批处理、预填充与解码分离。把这三个机制吃透再看vLLM、SGLang这些生产级引擎就会顺畅很多。2.2 KV Cache与页式管理显存利用率的命门Self-Attention在生成第N个Token时需要用到之前所有Token的Key和Value把结果缓存下来就是KV Cache。这个缓存的量非常大一个8B模型开2048上下文单个请求的KV Cache就可能超过1GB高并发时KV Cache会远超模型权重成为显存最大的消耗者。传统深度学习框架用连续内存块预先分配KV Cache空间碎片严重显存利用率低得可怜。nano-vllm实现了类似vLLM的Paged Attention机制把KV Cache拆成固定大小的块逻辑上连续物理上可以分散在显存各处再用块表Block Table记录映射关系。这就像操作系统里的分页机制显存不再有“碎片”问题每个请求按需分配块利用不下去的块立刻回收。这块有个重要的启动参数--gpu-memory-utilization默认0.9意思是留出10%显存给激活值和临时计算。如果模型本身很大、并发又高建议把参数调低到0.85甚至0.8给调度器留足余量否则极其容易OOM。2.3 连续批处理吞吐量翻倍的关键手段传统批处理是按固定批次凑数凑满一批才计算没满就一直等请求之间的空档期浪费严重。nano-vllm里实现的**连续批处理Continuous Batching**完全不一样GPU上同时跑一个动态批次每个请求每次只生成一个Token谁生成完了就从批次里摘掉新请求立刻插进来继续跑。这个过程有点像一个流水线工位处理多个订单做完一个补一个工位永远在处理任务而不是等一批攒齐再开工。连续批处理对吞吐量的提升非常明显我自己实测过同样一张卡、同样的模型开启连续批处理后吞吐量至少提升一倍的场景很多。2.4 Prefill与Decode分离为什么大集群必须做继续沿着nano-vllm深入会发现一个关键设计Prefill和Decode占用的计算资源完全不同。Prefill阶段是密集矩阵乘法上浮GPU算力利用率很高Decode阶段是带宽瓶颈算力大量空转。要是在同一个GPU上混跑两种请求等于让一台服务器同时处理重活和轻活谁都没法跑出最佳效果。生产级集群的解法是把两种请求拆开单独部署Prefill实例和Decode实例中间通过消息传递把数据衔接起来。这就是常说的PD分离架构。好处很明显Prefill实例高算力、算得快Decode实例高带宽、生成快各自做自己擅长的事情。千卡规模下不启用PD分离集群算力利用率一般不会超过50%上了PD分离之后提升非常可观。3. 推理集群的硬件选型与网络架构设计3.1 单机多卡先搞懂片内互联很多团队的起步方案是一台8卡服务器跑推理这时候片间互联方式决定了张量并行Tensor ParallelismTP能开多大。NVIDIA环境里有NVLink和NVSwitch互联带宽高、延迟低适合做张量并行如果机器只是普通PCIe互联多卡通信就要走PCIe Switch带宽跟NVLink差一个量级。一个常见的误区是把TP开得太大。TP8意味着每做一次矩阵计算都要在8张卡之间同步通信如果片间互联带宽跟不上通信耗时甚至超过计算耗时。一般来说PCIe互联的机器建议TP不超过2有NVLink的8卡机才考虑TP4或TP8。TP不是越大越好要结合卡间互联带宽来决定。3.2 跨机互联从千兆到RDMA单机8卡用完还不够只能往多机扩展。这时候首要问题是网络。把推理集群的跨机通信分成两块看数据面通信和控制面通信。数据面通信是推理过程中张量并行的AllReduce、模型分片传输、KV Cache转发对带宽和延迟极其敏感。千兆以太网理论上能做但实际跑起来延迟高得让人崩溃只适合调试绝对不适合生产。正经方案是RDMA网络一般走RoCE或InfiniBand。RoCEv2可以用在已有的以太网上部署成本相对低但要求交换机无损配置到位流控策略不做好拥塞了会批量丢包损失比不用RDMA还大。控制面通信则是负载均衡器到各节点的心跳、健康检查、配置下发走普通管理网络就行。架构上要把两张网络物理隔离不让管理流量挤占数据面带宽这个虚拟机、物理机都要注意。3.3 千卡集群的拓扑与存储千卡规模的集群通常采用两层或三层Spine-Leaf架构。Leaf层接入计算节点Spine层提供高速转发任何两台机器之间的跳数固定网络延迟可控。规划网络时要计算带宽收敛比推理场景的数据面带宽收敛比建议做到1:1到2:1以内收敛比太高会导致大量张量并行流量在Spine交换机上拥塞。存储这块容易被忽略。模型文件动辄几十GB千卡集群要同时加载同一个模型总不能每张卡都去公共存储拉一遍。标准做法是把模型放到共享并行文件系统或对象存储里集群启动时多节点并行拉取同时利用页面缓存尽量让同一批数据只在内存中留一份。千卡规模下启动一次大型模型的服务这段模型分发时间必须纳入部署规划否则每次发版都会等半小时以上。4. 千卡负载均衡与请求调度实战4.1 先分清楚负载均衡在哪一层做“千卡负载均衡”听起来高大上落地时先回答一个问题负载均衡做在哪个层级我一般把它分成三种。网关级均衡入口流量按简单策略分散到各推理节点比如轮询、加权轮询、最小连接数。模型级均衡集群里部署了多个模型副本请求按模型路由到对应副本。Token级均衡对同一个模型副本的不同GPU做请求内调度让每张GPU都尽量忙匀。网关级最简单但功能有限。模型级和Token级才真正影响千卡集群的效能。4.2 网关层怎么做会话保持与熔断网关层如果是HTTP服务通常用Nginx、Envoy或云上的负载均衡服务。简单轮询在一个无状态接口场景下没问题但大模型推理请求往往是长连接流式输出从用户发起到最终生成完毕可能持续几十秒甚至几分钟。这时候网关必须支持连接级的会话保持让同一个用户的长连接始终路由到同一个后端实例否则流式响应会被切得七零八落。网关层还有一个重要职责是熔断限流。推理后端过热时网关要能识别并快速降级排队请求该怎么办超时请求怎么办这些策略必须在网关层提前定义好。否则后端P99延迟开始恶化时所有请求还是会一起往里面灌形成雪崩。4.3 从排队长度到实时负载打分在千卡集群里简单轮询会把请求均匀但“愚蠢”地分发出去。比如某个节点上已经有一个超长文本生成任务正在慢吞吞输出轮询还是会继续往它上面打新请求。正确做法是让每个推理节点上报动态负载信息网关根据负载打分决定下一跳。我采用的负载指标主要有这几个指标说明权重GPU显存利用率KB Cache占用情况高意味着新请求可能OOM高排队请求数节点上等待处理的请求数量高当前吞吐量最近10秒实际生成的tokens数中健康状态心跳、上报是否正常极高网关定期拉取各节点指标把负载计算成一个0到1的分数然后按“最低分数优先”做加权分发。不要小看这个逻辑它比轮询分发在整体吞吐量上能带来20%到40%的提升。4.4 KV Cache亲和力负载均衡里的隐藏优化掌握了基础负载均衡后我强烈建议大家试试KV Cache亲和力调度。原理很简单用户在同一轮对话的多次请求之间有很强的连续关系上一次生成时算好的KV Cache如果能留在原节点下一次请求直接复用就能省掉重新Prompt计算的成本。传统负载均衡把所有请求均匀打散看起来公平实际上破坏了KV Cache的复用概率。优化办法是给请求打上会话ID网关对同一会话优先路由到上一次分配的目标节点只有当该节点负载过高时才路由到别处。这样既不牺牲整体负载均衡又能大幅提升连续对话场景的命中率。4.5 千卡集群的全局调度器当集群规模到千卡单靠网关分布式转发就不够了。千卡集群需要一个全局调度器它维护一张“模型分片到物理GPU”的映射表做什么操作呢比如新服务上线时自动挑选空闲GPU组创建推理实例GPU故障时把该实例上的请求迁移到备用实例异构GPU混部时根据算力差异调整流量权重在线评估各实例的负载必要时自动横向扩容。这个调度器可以基于Kubernetes实现也可以基于自研组件。但核心不是调度器本身用什么而是它能不能实时感知集群里几万个分布式指标并且在几秒内完成决策下发。千卡集群和百卡集群管理规模上的差别是跳跃性的故障率也随之上升调度器必须有自动应对机制。5. 实操记录从单卡推理到集群化部署5.1 单卡实测一张典型加速卡跑Qwen3量级模型先记录单卡实测。我用一块K100级别的推理加速卡显存大约48GB跑Qwen3-8B INT8模型以及27B量级的Qwen3模型。先说结论8B模型单卡能跑但并发一起来性能下滑明显27B模型单卡必须开量化否则连加载都费劲。8B模型的实测大概是这样单并发生成速度约90 tokens/s首Token延迟200ms左右看起来很不错。一旦并发到8路总吞吐量大概到150 tokens/s首Token延迟上升到2秒。看起来还挺正常对吧但用户体感就是卡、慢、不跟手。于是我把批处理参数调大更新了连续批处理的调度窗口并发8路的情况下总吞吐量提升到200以上延迟却没有明显恶化。单卡调优的结论是不要只顾单并发指标要拿典型并发场景来调batch size和显存利用率参数。5.2 多卡并行从数据并行到张量并行单卡测完开始上多卡。一开始最直接的做法是数据并行每张卡都放一份完整模型各自独立处理不同请求。优点是实现简单缺点是模型权重重复占用显存27B模型一张卡放不下数据并行就失效了。27B模型用INT8量化后还要约27GB加上KV Cache单卡放不下。我们改用张量并行把模型的层内矩阵切分成多块每张卡只持有模型权重的一部分计算时用AllReduce汇总。TP4启动命令大概是这样vllm serve Qwen3-27B \ --tensor-parallel-size 4 \ --gpu-memory-utilization 0.9 \ --max-model-len 32768 \ --dtype float16 \ --quantization awq这里我刻意说明一下TP4意味着每张卡只承担约1/4权重计算和显存但每一步都要做多卡通信。所以上一节说的片间互联很关键没有NVLink或RDMATP4的通信开销会直接把收益吃光。5.3 从几台机器到千卡的演进路线从几十台迁移到千卡规模我实践下来的步骤是这样的第一步实现实例模板化。把推理实例做成可快速克隆的最小单元包含固定的启动参数、模型版本、环境依赖能够一条命令拉起。这一步不做好千卡规模下每扩容一轮都是灾难。第二步统一网关和调度策略。把负载均衡逻辑从业务代码里抽离出来做成独立网关服务支持动态配置、会话亲和和实时负载感知。同时要在这一步引入全局调度器让新增和故障摘除都自动化。第三步建立可观测体系。千卡集群必须统一收集GPU显存、利用率、网络收发、队列长度和生成质量指标任何一个指标缺失都可能让故障排查变成大海捞针。我习惯至少保留最近一个月的指标历史用于事后回溯每一次性能波动。第四步灰度与压测。新版本模型或引擎上线时先在少部分实例上灰度压测流量同时打到新旧两套集群上做对比。只有性能差异在可接受范围内才允许全量发布。6. 常见问题与排查技巧实录6.1 显存OOM查单卡还是查并发推理服务OOM最常见的原因不是模型太大而是并发放得太开KV Cache把显存挤爆了。如果启动时设置了--gpu-memory-utilization 0.9那剩下的10%也会在突发并发下被打穿解决办法是按实际并发容量重新计算显存分配。我自己排查OOM的顺序是先看当前GPU实际占用区分是模型权重占满还是KV Cache占满如果是KV Cache占满就去查最大并发参数同时下调利用率配置如果是权重都放不下那只能换更大显存卡或缩减模型量化位数。6.2 网络拥塞明明RDMA却像乌龟爬RDMA网络部署后性能反而不如以太网这种情况不少见。原因基本都是无损网络没有真正配置好PFC流控策略失效发生微拥塞时丢包重传重传又加剧拥塞。排查方法是看交换机端口上的CNP拥塞通知包计数如果计数持续上涨说明无损网络配置有问题。我遇到过一次最后查出来是Leaf交换机上某个端口的PFC优先级映射配置反了低优先级流量反而获得了高优先级的缓冲。这类问题靠应用层调优没有意义网络配置必须专项自查。6.3 负载不均明明均衡器已经尽心尽力已经做了负载感知调度还是出现某个节点GPU跑满、其他节点空闲这种情况往往是模型分片方式惹的祸。同一个模型如果开了TP8请求必然同时占用8张卡只要有一个分片卡住整个TP组就无法交付。这时候你看到的不是单节点负载高而是一个TP组集体卡死。解决思路有两个一是降低TP并行度增加PP或DP维度分散风险二是在调度器层面识别TP组状态一旦某组内的任一GPU异常立刻标记整组不可用并摘除。6.4 推理质量莫名其妙下降集群规模上来后打过量化、改了调度、加了缓存复用结果模型输出质量似乎变差了一点。这种情况先查两件事一是回答时是否因为KV Cache复用导致上下文串味也就是不同会话间的Cache复用逻辑存在Bug二是量化方式是否适配当前引擎版本指令集和算子实现不同局部结果可能偏差。我个人经验集群规模越大越要把“在线评测”作为发布流程的固定环节每天挑一部分线上流量和基准输出做一致性比对一旦偏差超过阈值立刻报警回滚。写在最后的经验谈折腾了一圈下来我最深的体会是大模型推理集群的复杂度远远超过很多人最初的想象。单卡调优靠手气多卡调优靠参数千卡调优靠体系。从nano-vllm里学到的机制理解到真实集群里的调度和排障每一环的技术选型和实操经验都是叠出来的。如果你正准备从单卡迈向多卡甚至千卡我的建议是先别急着上大集群花时间把单卡性能的极限摸清楚把推理引擎的关键参数吃透然后小规模验证网络和负载均衡方案最后再规模化扩展。这个过程没有捷径但每一步走扎实了后面遇到的坑会少很多。
返回列表