尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

大模型推理集群架构设计:从单卡到千卡的并行、调度与负载均衡实战

大模型推理集群架构设计:从单卡到千卡的并行、调度与负载均衡实战 最近常有人问我一个问题一台24GB显存的卡本地部署27B级别的开源大模型量化之后跑起来也挺快为什么一接到真实的生产请求就拉胯问的人多了我觉得有必要把从单卡推理到千卡集群这条路上的东西系统写一写。先说结论单卡推理和千卡推理集群表面上是“卡的数量”不同实际上是两种完全不同的工程问题。前者考验的是显存和推理引擎的调优能力后者考验的是通信、调度、负载均衡、故障转移和可观测性。很多人用单卡实验的思维去做千卡集群结果堆了一堆卡吞吐反而上不去P99延迟高得没法看。这篇文章就沿着“为什么单卡不够用 - 并行策略怎么选 - 集群三层架构怎么搭 - 负载均衡真正难在哪 - 落地要盯什么”这条线把推理集群架构设计里真正值得花时间的点讲透。适合正在做大模型部署、推理服务化、或者准备从单机走向多机的工程师参考。1. 为什么单卡推理撑不到“能用”的天花板不只是显存1.1 “能跑”和“能扛”是两回事先压测再谈架构我见过很多团队的第一步是拿一张消费级显卡跑通模型推理速度20到30 tokens每秒体感还行于是直接套一个Web服务上线。结果并发一上来第一个用户还在等生成长文第二个用户的prefill已经把GPU占满第三个用户直接排队超时。这不是模型的问题也不是代码的问题是压根没搞清“单请求速度”和“系统吞吐”之间的差距。先做一个最小实验26B到32B这个量级的模型用4-bit量化后权重大约18GB可以塞进24GB显存。单请求、短上下文、短输出的情况下单卡确实能动速度甚至不差。但当你把它推上生产同一个模型 的KV Cache 是按“并发序列数 × 上下文长度”线性增长的。量化只压缩了权重KV Cache却不能被量化压缩太多长上下文场景下显存会迅速爆掉。更关键的是GPU在做prefill阶段处理用户输入时是计算密集型做decode阶段逐token生成时是显存带宽密集型两者对资源的需求完全不同。单卡只有一份算力、一份带宽同时服务十个请求时必然互相抢资源。所以我给团队的建议永远是先跑通再压测再谈架构。单卡环境下至少要验证四个数字——单请求首字延迟TTFT、单请求生成速度tokens/s、并发10个请求时端到端吞吐、以及显存是否够承载预期的最大batch。如果你发现并发一到5就跌到个位数或者总在排队那就该考虑多卡了。1.2 单卡被卡住的三个硬指标算力、显存带宽、KV Cache很多人以为单卡推理的上限只取决于显存够不够装模型权重这是误解。推理过程有三个硬指标任何一个都会成为瓶颈。第一是算力主要卡住prefill阶段。Prefill要对用户输入的所有token做一次完整的前向计算输入越长需要的矩阵乘法越多。同一张卡处理256 token的输入和处理8000 token的输入prefill时间完全不是一个量级。第二是显存带宽主要卡住decode阶段。自回归生成每个token都要把整个权重矩阵从显存读一遍做矩阵乘所以生成速度约等于“显存带宽 ÷ 模型权重体积”。拿H100举例3.35TB/s的带宽跑一个27B的int4模型理论带宽极限也就180 tokens/s左右实际打折之后远低于这个数。第三是KV Cache容量。假设每个token的KV Cache约0.5KB8K上下文就是4MB64个并发用户同时跑就是256MB看起来不多。但如果模型是70B级别权重已经占了大部分显存KV Cache再膨胀很快就会OOM。另外还有一个隐形问题显存碎片。频繁的申请和释放KV Cache块会让显存碎片化可用显存明明很多却申请不到一块连续内存。这也是为什么vLLM这类带PagedAttention的推理引擎在长尾流量下比原生transformers库稳定得多它把KV Cache按固定大小的块管理像操作系统分页一样把碎片问题降到最低。1.3 单卡到多卡的决策线什么时候该看集群综合上面这些约束我总结了一个简化版的决策线供参考信号单卡方案多卡/集群方案模型权重不适合单卡显存量化/拆层牺牲精度或速度张量并行或流水线并行并发10个请求吞吐严重下跌限制并发、缓存复用数据并行多副本负载均衡分发长上下文场景频繁OOM缩短上下文、压缩KV Cache多卡分摊KV Cache需要7x24高可用SLA无冗余断卡即断服多节点故障转移、优雅下线要不要上集群标准不是“模型有多大”而是“业务模型有没有多用户并发、有没有长上下文、有没有SLA要求”。如果只是本地个人使用单卡加上量化完全够没必要为了“跑得更快”去上多卡分布式那是给自己找麻烦。可如果是面向多个业务方的大模型服务从单卡到多卡是必然一步因为单卡物理上就扛不住并发和可用性。2. 并行策略不是随便拆张量并行与流水线并行怎么选2.1 张量并行把一次矩阵乘法劈成两半当模型太大一张卡放不下时最常见的做法是张量并行Tensor ParallelismTP。思路很直白把每一层的权重矩阵按行或按列切到多张卡上每张卡只算自己负责的分片算完通过AllReduce把结果合并起来。TP的好处是显存压力分摊了单卡不用装下整个模型而且每一步计算都能利用多卡算力。但代价是通信极其频繁每次矩阵乘都要同步一次。层数越深、hidden size越大通信量越大。所以TP依赖高速卡间互联在单机NVLink环境下很舒服一旦跨机走网线通信延迟会立刻变成瓶颈。实践中如果你要TP并行先确认你的卡之间有NVLink或等效的高速互联再思考TP几。很多人不加验证直接TP8跨两台机器结果每生成一个token都卡在网线上性能惨不忍睹。2.2 流水线并行按层切分用微批次填满空闲流水线并行Pipeline ParallelismPP是另一种拆法按模型层数把网络切成几段每一段放一张卡。第1张卡算完前几层把中间结果传给第2张卡继续算。它解决的核心问题是“单机都装不下整个模型”而不是算力不足。PP在推理场景里有一个天然问题一个请求在某一时刻只会在某一层上计算其他层对应的卡是空闲的。虽然可以用micro-batch把多个请求切成小块流水推进但流水线气泡bubble依然存在而且通信是点对点串行的延迟比TP更敏感。所以我的经验是能TP就TPPP只在模型大到单机都装不下、或者跨机NVLink不可用时才考虑。TensorRT-LLM和vLLM对TP支持都很成熟PP更多出现在训练集群和超大模型推理里。2.3 单机多卡与多机之间的“隐形边界”通信成为新瓶颈很多第一次做集群的人会犯一个错误以为千卡集群就是把几百台8卡机器堆在一起然后让一个模型用上所有卡。实际上在普通组网条件下大规模跨机TP不是最佳选择。看一眼通信量就知道为什么。以TP4为例每个decode step都要做一次全规约AllReduce数据量跟hidden size、层结构相关通常每batch几MB到几十MB。单机NVLink带宽是数百GB/s跨机RoCE或IB也就是200到400Gbps换算下来低了将近一个数量级。如果一个模型跨两台8卡机做TP16每次step的allreduce都要经过网络交换机延迟和带宽双重拖累。因此在推理集群里主流方针是“局部TP全局DP”每台8卡机内部TP8把一台机器看成一个模型副本多台机器之间做数据并行Data ParallelismDP同一个模型跑多个副本由负载均衡把请求分散到不同副本上。这样卡间通信只发生在一台机器内部网络只承担请求分发和结果回传集群扩展半径一下子变大了。2.4 为什么“模型分片固定在某几台机器”负载均衡才有的放矢到这里“千卡负载均衡”的核心矛盾就出来了并不是任何一台机器都能服务任何请求一个模型副本被固定分配在某个TP组内请求要路由到对应的机器组。所以在大模型推理集群里负载均衡天然被“模型副本”限制着路由网关要先按模型维度分流再在多个同模型副本之间分配流量。同时这里的负载均衡和传统Web负载均衡有个本质区别传统Web请求通常是几毫秒级、无状态、后端处理时间基本均一LLM请求是秒级甚至分钟级、携带长上下文、后端处理时间高度不确定。这就意味着单纯轮询或者按连接数分发根本不靠谱我们必须为LLM专门设计一套更聪明的路由策略这是后面几章的重点。3. 千卡集群的架构骨架路由网关、调度器与推理引擎三层各管什么3.1 路由网关层不要只做nginx轮询传统负载均衡器比如Nginx的默认轮询在大模型场景下会踩三个坑。第一它不知道后端副本的排队长度一个副本已经队列塞满它照样往里发。第二它不感知GPU健康状态一张卡出现了HBM错误但进程还没挂它照样引流。第三它不知道大模型服务的“前缀缓存”机制同一个system prompt的请求如果被打散到不同副本每个副本都要重新prefill一大段浪费算力。所以做千卡推理集群网关这一层必须带一点“智能”。常见的做法是基于vLLM暴露的指标做自定义路由查每个副本当前排队的请求数或者查每个副本最近一分钟的GPU利用率和平均生成速度然后按“负载最少”的原则分发。如果用的是Kubernetes环境还可以借助Service Mesh或者自研的轻量网关来接管这部分逻辑。网关层的另一个职责是协议适配。LLM推理普遍使用OpenAI兼容的流式接口一整段大响应要通过HTTP流持续推给客户端。网关必须要能处理长时间连接、正确的超时策略以及流式响应的转发不能像普通HTTP反向代理那样因为后端迟迟未返回而提前切断连接也不能因为客户端断开就把后端的生成任务直接掐掉最好能优雅地取消并把资源释放出来。3.2 调度层连续批处理和抢占到了调度器这一层问题就从“请求发给谁”变成“请求在GPU上怎么插队”。传统推理做法是把一批请求组成固定batch等这批全部算完再处理下一批这个方案对LLM是灾难。因为每个请求生成长度不一样短的早早就结束了长的还要跑半天固定batch会让整批都在等最长的那一个。现在主流方案是连续批处理continuous batching一个序列生成结束立刻从等待队列拉一个新的请求进来把GPU的batch填满。vLLM的调度器就是干这个事的它的等待队列FCFS先来先服务同时支持抢占。当一个长序列占住太多KV Cache而新来的短请求需要及时响应时调度器可以把长序列的KV Cache换出swap到CPU内存或标记重算recompute把算力让给优先级更高的请求。调度器还需要处理prefill和decode的交错。prefill计算量大但只做一次decode计算量小但要持续很多步。如果prefill和decode完全串行一个输入很长的请求进来会拖慢所有正在decode的请求。vLLM的chunked prefill机制可以把一次prefill切分成多个小块插在decode步骤的空隙里执行从而降低首字延迟的长尾。这里可以套用一个简单的排队论视角如果把每个模型副本看成一个服务窗它的服务速率不是固定的而是取决于当前batch大小和序列长度。负载均衡要做的事本质上就是让所有副本的利用率尽量均匀避免某个副本ρ接近1而其他副本闲着。记住一个规律当平均利用率超过0.8以后响应时间的增长速度会远超流量增长速度所以不要等到副本被塞满才扩容。3.3 推理引擎层vLLM多副本部署的正确姿势在千卡集群里推理引擎层一般是一组同构的vLLM服务实例每个实例绑定一个TP组。推荐的做法是每台8卡机跑一个TP8的vLLM实例用Docker或K8s进程隔离对外暴露同一条OpenAI兼容的API网关把同一个模型的流量分散到这些实例上。配置vLLM时有几个参数直接影响负载均衡效果。max_num_seqs决定引擎内部最多能并发多少序列超过这个数的新请求会进入等待队列。很多人喜欢把这个参数调得很大觉得并发越高越好但别忘了GPU显存是有限的。每个序列的KV Cache要占显存如果max_num_seqs设太大显存会爆设太小GPU利用率上不去。通常要结合压测结果调先按业务平均输入输出长度估算KV Cache上限再除以单序列预计KV Cache占用得到安全并发数。gpu_memory_utilization控制KV Cache最多能用多少显存推荐不要直接设成0.95留一点余量给模型权重和临时计算。多副本还会带来一个前缀缓存命中率问题。vLLM会缓存已计算的KV Cache相同前缀的请求如果每次都落在同一个副本第二次请求的prefill时间可以省掉一大截。但网关如果随机分发同一个system prompt的请求会平均打散到所有副本每个副本都各自存了一份前缀缓存命中率反而上不去。解决办法是网关在做路由时按系统提示词或用户会话的哈希值做一致性哈希让同一类前缀尽量固定到同一副本。这个优化在长prompt场景下效果非常明显有时能把TTFT直接降到原先的一半。3.4 千卡规模的真实物理布局从8卡机到训练舱聊完三层架构再看物理布局。一个典型的千卡推理集群通常由一百多台8卡服务器、计算网络RoCE或IB、管理网络和共享存储组成。从模型视角看一个70B模型FP16大约需要140GB显存做TP8需要每张卡拥有80GB以上显存也就是至少A100/H100级别如果同时要支撑较高并发就不能只部署一个副本而要部署多个TP8的副本让它们分担流量。举个例子用80张H100部署一个70B模型可以把这80张卡划分为10个TP8的副本每个副本是一个vLLM实例。网关在10个副本之间做负载均衡调度器在每个副本内部做连续批处理。如果业务有多个不同模型比如一个70B对话模型、一个7B分类模型那就按模型分别规划副本组GPU资源通过K8s实例池统一调度。千卡规模绝不是“一张卡一个模型”而是“一批卡一组TP副本多组副本共用资源池”这是和单卡思维差异最大的地方。4. 负载均衡背后真正难的点长尾效应、慢节点治理与故障转移4.1 一次真实的P99事故复盘加权轮询是怎么被慢节点坑的前几年我负责过一个推理集群的压测用的就是最简单的加权轮询四个副本每个副本权重一样流量均匀分发。结果压测跑到一半P99从2秒飙到15秒单副本吞吐却显示一切正常。排查了半天才发现四副本中有一个副本所在的物理机被另一个训练任务占用了GPU该副本每秒钟产出的token数比其他副本低了一半。可轮询算法不感知这个变化依然按1:1:1:1发流量。所有打到慢副本上的请求全部排队队列越排越长长尾延迟爆炸。这个事故让我彻底明白LLM推理的后端天然是异质的。即使是同型号GPU由于所在机器上其他任务干扰、PCIe链路质量、显存温度导致的降频实际服务能力随时在变。负载均衡必须从“静态权重”转向“反馈驱动”至少做到按每个副本的活跃请求数或排队长度加权。自研网关里可以定时拉取vLLM的指标接口拿到num_requests_running和num_requests_waiting再去计算分给每个副本的流量比例。慢节点在指标上会迅速表现为高waiting低running把它的权重调低之后整体P99立刻回落。4.2 为什么LLM请求的“开销”不好估计prefill与decode不对称传统Web后端一个请求的开销通常可以用平均处理时间来估算负载均衡器据此分发即可。LLM请求却很难做这种估算因为预算请求开销需要知道三个参数输入长度、输出长度、当前KV Cache命中情况。输入长度决定prefill计算量输出长度决定decode总步数这两者差异极大——一个请求可能输入几十个token也输出几十个token另一个请求可能输入几千个token并生成长文。更麻烦的是LLM是流式生成没跑到最后一个token谁都不知道它到底要生成多少。所以现实中的负载均衡要采用启发式加权把请求的预估开销定义为“输入token数 当前队列里待处理token总数 预估输出长度”。网关在分发时优先把请求给到权值最小的副本。至于预估输出长度可以用历史平均长度或者模型固定默认值虽然不精确但比重试一万次的轮询好得多。实践中也可以用一种更简单的策略每个副本保持最大队列长度上限超过上限的请求直接返回429让客户端退避重试依靠客户端退避把流量天然分散开。这个方法不优雅但很有效。4.3 千卡规模下的故障模式你不是在对付单卡是在对付一群“随时掉队”的卡单卡挂了影响面很小千卡集群里故障是常态。GPU会报Xid错误NVLink会降速HBM会出现CE错误但不立即宕机网络偶发丢包机架电源波动这些都是我在生产环境真实遇到过的。所以千卡集群必须把“故障转移”当成一等公民而不是事后补救。健康检查要分两层。第一层是硬件层依靠DCGM采集GPU温度、显存ECC错误、NVLink带宽等指标低于阈值就触发节点告警。第二层是模型层定期向每个副本发一个短小的推理请求如果连续几次超时或返回错误就把该副本标记为不健康从负载均衡池摘除。摘除动作还要区分“立即下线”和“优雅下线”如果是进程已经崩溃只能立即下线如果是硬件告警但服务还能撑着那就先停止分配新请求等当前正在跑的请求排空之后再下线避免一批请求中途断流。重试机制里隐藏着一个很常见的雪崩陷阱。假设网关对超时请求重试3次集群在负载较高的时刻出现小范围超时每个失败请求变成4个请求重新打进来流量瞬间翻倍更多请求超时形成正反馈。踩过这个坑之后我的做法是重试次数严格限制最多1次重试前加随机延迟jitter并且只对幂等请求重试。对vLLM返回的429或503不要硬重试要让调用方退避后重来。4.4 调度与弹性伸缩高峰期来临前不要把新副本当“救火队员”大模型服务的新副本不是秒级就绪的。拉取镜像、加载几十GB权重、执行预热推理整个冷启动过程往往需要几分钟。如果等QPS打上来才开始扩容新的副本还没就绪这一轮高峰已经过去了。因此必须做预测性扩容而不是被动扩容。我的做法是根据历史流量曲线和当前网关队列情况做两层扩容当天级或小时级形态比较稳定时提前在高峰前半小时把副本数扩到位当网关平均排队长度超过阈值时再做一次快速扩容哪怕新副本只能赶上下一个高峰也能避免更长时间的排队。缩容同样讲究策略先把该副本从负载均衡池摘除让它把当前队列跑空再销毁进程。不要直接kill否则正在生成的请求全部被打断。5. 落地硬件选型与可观测性千卡集群不能“盲飞”5.1 算力底座H100、A100与国产加速卡的选型思路硬件选型上推理场景和训练场景的侧重点不一样。训练更看重峰值算力推理更看重显存带宽、显存容量和卡间通信能力。以H100和A100为例A100的显存带宽约2TB/sH100约3.35TB/s同代SXM版本都要强于PCIe版本。如果业务主要跑长文本生成显存带宽直接决定decode速度带宽翻倍比算力翻倍更值钱。纯推理集群并不需要清一色最高端卡。对7B量级模型A100或国产等效卡跑数据并行副本完全够只有超大模型和超大并发才需要H100级别的大显存高带宽。选国产加速卡时要重点评估三件事一是推理框架vLLM/TensorRT-LLM的支持程度二是算子兼容性尤其是量化算子和自定义attention实现三是通信库的成熟度。很多国产卡单卡跑模型没问题一上多卡进行AllReduce通信性能立刻崩这种卡做千卡集群会非常痛苦。5.2 网络拓扑与卡间通信对扩展半径的影响前面已经强调过“局部TP全局DP”的思路这里再补充网络拓扑层面的判断。机内通常有NVLink号称数百GB/s跨机走RoCE或IB最高400Gbps转化为字节就是50GB/s左右和NVLink不是一个数量级。因此模型并行分片尽量不要跨机数据并行副本才能跨机。如果模型太大一台机器放不下不得不跨机共享一个模型那优先选择流水线并行而非跨机张量并行。PP只在层间传输中间激活值通信频率比TP低受网络延迟的影响相对小。更进阶的做法是使用支持NVLink Switch的多机互联方案让跨机TP也走NVLink但这种硬件成本很高通常只在超大模型训练或旗舰推理集群里出现。普通千卡推理集群把网络焦点放在“网关到各副本的数据分发”就够了模型内部的通信尽量限制在单机范围内。5.3 监控大盘必须盯的五个指标TTFT、TPOT、排队长度、缓存命中率、GPU利用率千卡集群不能靠命令行一张卡一张卡去看必须有一块全链路监控大盘。我实际用的几个核心指标如下指标含义典型告警阈值作用TTFT P95用户发出请求到收到第一个token的延迟超过3秒告警反映排队和prefill效率TPOT P95每个输出token的平均耗时超过业务容忍值告警反映decode阶段吞吐副本排队长度vLLM等待队列中的请求数超过容量80%告警触发扩容或调整路由Prefix cache命中率KV Cache前缀命中比例低于期望值告警反映路由策略好坏GPU利用率/显存带宽实际算力和带宽占用持续90%以上告警避免过载和降频其中TTFT和TPOT是从用户侧看的排队长度是从调度器侧看的缓存命中率是从优化侧看的。不要只盯GPU利用率因为GPU利用率高不一定代表服务做得好也可能是在低效地等待。我见过GPU利用率95%但P99延迟爆炸的情况因为利用率高出自于排队请求反复重算而不是有效的token产出。所以两套指标必须搭配看。5.4 开源工具链组织实操从网关到监控的最小闭环最后给一个已经在生产环境跑通的最小工具链组合自研轻量网关处理路由、健康检查、超时重试 vLLM带OpenAI兼容接口每个TP副本一个实例 Kubernetes负责调度和副本生命周期 Prometheus与Grafana负责指标采集和展示 DCGM exporter负责GPU硬件指标。采集链路是这样的vLLM本身暴露/metrics接口里面有vllm:num_requests_running、vllm:num_requests_waiting、vllm:cache_hit_rate_total等指标网关把接收到的TTFT和TPOT埋点上报给PrometheusDCGM exporter采集每张卡的功耗、温度、显存错误。Kubernetes根据Prometheus里“副本排队长度”的指标做弹性伸缩。这套组合的好处是全部开源资料多自定义扩展也方便。上集群前先做一次小规模压测规模可以只占最终集群的十分之一但必须包含网关、调度、vLLM副本、监控全链路。重点关注P99曲线和排队长度曲线这两个指标基本决定你是否能把集群容量安全地跑到80%以上。我在实际操作中的体会是千卡集群的瓶颈多数时候不在模型算法上而在流量调度和故障处理这些“脏活”上。先花时间把网关路由从静态轮询换成反馈驱动再给副本配置好优雅下线和有限重试最后把TTFT和排队长度变成告警项整体稳定性会提升一个档次。这个顺序比一上来就堆显卡、调并行参数要重要得多。
返回列表