跨模型自动扩缩容:破解共享LLM服务GPU利用率与突发流量难题
1. 这篇论文在捅什么马蜂窝如果你做过LLM推理基础设施大概率经历过这样的场景集群里几十张GPU卡铺了七八个模型看起来一派繁荣但你把利用率报表拉出来一看长期在30%上下晃悠。为什么这么低因为每个模型都按自己的峰值来配置资源可它们的峰值从来不会同时来。更闹心的是突发流量。线上一个模型QPS瞬间涨了三倍扩容任务提交了模型权重加载要几分钟等新replica真正能接流量的时候用户已经排队排到超时了与此同时另一个模型流量掉到了谷底replica还占着一整块GPU缩容动作要是不小心把它的缓存全丢了下一波流量回来又得重新冷启动成本更高。这种高峰饿死、低谷浪费的问题在共享LLM服务场景下是常态靠人肉运维盯监控根本盯不过来。这篇Cross-Model Autoscaling for Shared LLM Serving论文做的就是给多模型共享的GPU集群加一套跨模型自动扩缩容机制。总体的思路我读下来可以概括成一句话不再把每个模型当孤岛单独扩缩容而是站在全局视角统一预测所有模型的负载变化把给哪个模型加副本、从哪个模型减副本变成一个整体优化问题。论文覆盖了从请求预测、资源分配、调度执行的完整链路对正在做大模型平台、推理服务、成本优化的人来说很有参考价值。下面我按自己的理解把论文的核心思路拆开讲并结合实际落地中的经验做一些补充。这篇解读默认你对LLM服务的基本概念比如replica、GPU显存、SLO有一定了解但我会尽量把每个关键环节讲到能直接拿来用的程度。2. 为什么单模型自动扩缩容不够用了2.1 从单模型到多模型的复杂度跃迁单模型的autoscaling在业界已经非常成熟了。vLLM、TGI、TensorRT-LLM这些推理引擎都带或兼容标准的缩扩容机制采集QPS、GPU利用率、排队长度等指标超过阈值就加副本低于阈值就减副本。这套逻辑单独跑一个模型的时候没什么问题因为它的隐含前提是资源无限我只是决定要不要加副本。但资源在那里还有个巨大的隐含假设——模型之间是独立的。一旦到了共享LLM服务场景多个模型部署在同一批GPU上资源就是有限的。这时候你面对的问题从要不要加副本变成了同样一张GPU卡给A模型用还是给B模型用。这个转变的复杂度是数量级的。举个例子A模型负载涨了20%B模型负载不变。如果集群里没有空闲GPU你只有两个选择一是把某个模型的replica缩掉腾出GPU二是让低负载模型和A模型共享GPU。选择一是杀谁的博弈问题选择二是共享到什么程度才会互相干扰的工程问题。任何一个都不是简单阈值能解决的。2.2 论文归纳的四类核心挑战论文把跨模型扩缩容的难点归纳为四个方面我实际做下来确实都踩过模型异构性。7B模型和70B模型对资源的消耗完全是两个世界。小模型跑高并发吞吐能到几千token每秒大模型串行处理单请求可能占几十GB显存。它们的显存占用、吞吐上限、冷启动时间都不一样用同一套扩缩容策略就是灾难。负载动态性。LLM服务的流量是突发叠加周期凌晨低谷、白天高峰只是最粗的规律。真实情况是时间段内还有多个波峰比如某个新功能上线带来一波脉冲流量某个渠道投放带来持续性爬坡。没有预测能力扩缩容永远都是在追着流量跑。扩缩容成本高。这是LLM服务和普通微服务最不一样的地方。普通Web服务起一个新pod只要几秒LLM要加载模型权重7B模型算轻的70B模型从拉取权重到引擎预热可能要小十分钟。缩容也不是没成本KV cache丢了就得重新 prefill下一波流量回来性能直接打折扣。跨模型共享约束。模型之间共享的不只是GPU算力还有显存、CPU内存、磁盘和网络带宽。扩A模型的时候它多占的显存可能挤掉B模型影响的不仅是B的容量还可能触发B的OOM。这种全局约束单模型扩缩容根本感知不到。2.3 和现有常见方案的对比现在生产环境里比较常见的几种做法和论文的方案放在一起看就很直观方案基本思路核心问题静态资源池每个模型固定分配一批GPU按峰值配置GPU利用率长期偏低模型间无法借调单模型独立伸缩每个模型各自配autoscaler独立扩缩资源争抢高峰时各自扩容互相挤兑排队限流控制不扩缩容靠排队和限流扛住过载请求时延爆炸SLO频频违约论文方案全局预测跨模型协调的决策与调度实现复杂但能逼近全局资源最优论文的目标非常明确不是让单个模型的扩缩容变得更聪明而是让集群里所有模型一起的整体效率最高这就跟现有的各种单模型方案拉开了代差。3. 论文核心方案的整体设计3.1 一个终端到终端的闭环架构论文提出的系统架构是四层闭环观测层、预测层、决策层、执行层。我逐渐把这个结构展开。观测层负责实时采集每个模型的指标不光是QPS还包含平均输入输出token数、缓冲区排队长度、GPU算力利用率、显存占用率这些细粒度数据。这些指标不只是给决策层看的更重要的是它们会成为预测模型的特征。预测层是整套方案的大脑底座要做的事情是对未来一个时间窗口内每个模型的负载做预测预测粒度一般精确到每个模型未来5到15分钟的QPS和请求平均token数。决策层把预测结果变成资源分配方案。它要回答的核心问题是未来这个窗口里每个模型应该各有多少个replica分别部署在哪几台GPU上。这本质上是一个动态资源规划问题我在下面4.3节详细展开那个优化模型。执行层负责把决策结果落地成真实的扩缩容动作。在Kubernetes集群里就是创建/删除Pod、调整Deployment副本数、必要时做Pod的抢占和重调度。这四个层级必须紧密配合。预测层预测不准决策层再聪明也白搭决策层算出来的方案如果不能精确执行整个系统就退化成了带预测的盲人摸象。3.2 预测层不搞花活先把时序拆好预测层是论文里我觉得最值得借鉴的一块。它没有一上来就搞大模型或复杂深度学习网络而是把每个模型的QPS序列先做了经典分解——拆成趋势项、周期项和残差项三部分。拆解之后趋势项用一个简单的指数滑动平均就能捕获周期项用周期性分解方法提取真正需要模型拟合的只剩下残差项。论文用一个轻量级的神经网络去拟合残差。这个做法的聪明之处在于把天气这种难预测的东西分解成季节、趋势、波动之后神经网络只需要学那些无规律的波动学习难度大大降低预测稳定性和泛化能力反而更好。我实际做过类似的事。最早我们直接拿原始QPS序列喂给LSTM训练的时候loss挺好看一上线遇到突发流量预测数值就崩了落后真实值几个窗口。改成先分解、再预测残差的结构后突发部分的支持情况明显改善。这背后的原因是简单的QPS中周期性、趋势性占了90%以上的能量如果你让模型在一堆冗余特征里自己找规律它很容易过拟合到无关的模式上如果你预处理掉了那90%的可预测部分模型只需要用很小的容量去学剩余10%的波动反而能学到真东西。预测层另一个重要设计是预测不确定性估计。论文没有只输出一个均值而是同时输出一个置信区间。这很关键因为在做扩容决策时你需要的是最坏情况下的QPS而不是平均情况下的QPS。你按均值的预测去规划容量遇到波动马上打脸你按95分位预测去规划容量可能又过度扩容。置信区间给决策层留了调参空间——对SLO敏感的模型用90分位对成本敏感的模型用中位数。3.3 决策层把资源分配变成可量化的优化问题决策层的优化表达式读起来不复杂核心是在所有模型的replica资源总量不超过集群GPU总容量的硬约束下最大化一个目标函数。目标函数通常是SLO达标率和资源成本或资源利用率的加权组合。拆开来看决策层必须建模三个东西。第一个是单模型的性能模型。给定一个模型的replica数和请求负载估算它能不能满足SLO比如P95尾部时延低于一个阈值。这不是拍脑袋定的需要离线压测获取。论文用了一个分段函数低并发时性能随负载线性变差超过某个拐点后开始急剧恶化动态地对应了GPU算力和KV cache的瓶颈。第二个是显存模型。LLM推理的显存由两部分构成模型权重占的固定部分和KV cache占的动态部分。动态部分跟并发请求数、上下文长度强相关。决策层必须估算如果给A模型加一个replica新增的显存需求是多少如果这个replica放在一台已经有B模型的GPU上B模型被挤掉的KV cache份额是否会让B的SLO违约。这个挤兑效应就是跨模型自动扩缩容和单模型自动扩缩容最根本的区别。第三个是扩缩容的成本模型。每次扩缩容动作都有开销扩容要等模型加载缩容要损失已缓存的KV状态。决策层在计算要不要执行某个动作时会把这一部分成本也纳入考虑。如果一个动作带来的收益还不如成本那就不如不动。3.4 执行层把决策变成现实时魔鬼在细节里论文执行层有几个细节让我很共鸣。扩容要分批。决策算出要加8个replica它不会一次性下发8个创建请求而会分两到三批执行。这样做是为了平滑内存、网络、模型仓库的压力。缩容优先级有讲究。当集群没有空闲GPU、必须通过缩容某个模型来腾资源时论文建议优先缩容SLO富余量最大的模型也就是当前负载距离SLO违约还有很大余量的模型而不是简单地缩容负载最低的模型。这一点其实很反直觉但逻辑是对的SLO富余量大的模型对资源减少最有耐受度缩它风险最小。执行层必须处理决策过期的问题。决策层基于预测窗口做了未来15分钟的决策但真实流量可能在5分钟后就变了。论文的做法是每个动作都带一个有效期超过有效期的动作必须被回收或重新评估。这个细节对落地很重要否则你会看到一个很普遍的坑预测的容量调整命令执行到一半流量已经变向了旧指令还在傻傻地把replica往上涨。4. 落地实操从论文到生产环境的关键细节4.1 预测窗口怎么选不是越长越好第一个问题就是预测窗口时间。窗口太短比如1分钟决策层来不及执行扩缩容动作窗口太长比如1小时预测精度急剧下降决策基本等于猜谜。从我经验来看预测窗口的下限必须大于最慢模型的重路由耗时。假设你集群里最大的一个模型从发起扩容到真正开始接流量需要6分钟那预测窗口至少要10分钟留出4分钟的决策和执行余量。如果窗口小于这个数你会发现扩容永远在事后补救。更好的做法是分两层预测。短窗口1到3分钟用来捕捉快速波动可以做快速的小幅度调整长窗口10到30分钟用来判断趋势可以提前准备资源在GPU池里预热。我自己落地时就是这样一个双层预测结构短窗口管急性病长窗口管慢性病。4.2 SLO指标QPS不直接排队长度才直接很多人做自动扩缩容时喜欢把QPS作为核心指标。但实测下来QPS作为扩缩容触发条件有一个问题QPS涨了不一定说明该扩容了。如果请求的token长度都变短了QPS涨了但GPU算力需求没涨多少反过来如果请求的上下文长度都变得很长QPS没涨但每个请求的时间翻倍了算力需求暴涨。所以论文建议以端到端的排队时间和时延作为SLO指标而不是直接用QPS。实际落地时我一般这样组合排队长度或者P50/P95的端到端时延作为SLO是否健康的核心指标QPS和token吞吐作为特征输入给预测层让模型自己学习它们之间的关系。扩缩容的触发条件不设成QPS 某阈值而是设成预测的未来排队长度 某阈值。这样做的效果是面对长请求的突发也能准确触发而不是对高QPS短请求做无谓扩容。4.3 K8s环境下的落地改法别直接用HPA如果你的集群是Kubernetes一个常见的诱惑是直接给每个模型配置HorizontalPodAutoscaler接入自定义指标让它自己扩缩容。这在单模型场景没问题但在共享多模型场景下是行不通的——HPA每次只考虑一个Deployment它看不到全局GPU池的状态更不会做为了给A模型腾GPU而主动缩B模型这种跨Deployment的协同决策。论文方案落到K8s上需要自己写一个中央控制器我拆成三个子模块reloader负责读指标和做预测planner负责用优化模型计算目标replica数executor负责操作deployment。executor跟K8s API交互时有几个细节要注意新replica要等待ready后再接流量可以用readinessProbe控制缩容动作最好通过删除Pod的方式、而不是直接改replica数把Pod杀掉这样才能配合Pod的优雅终止流程让正在处理的请求排空。GPU资源的表达也是个坑。K8s默认的nvidia.com/gpu这种整卡调度粒度太粗如果你希望多个模型共享同一张GPU比如用MIG或者K8s设备插件的vGPU能力就需要自己实现资源配额和显存的约束管理。论文里假设一个模型实例至少独占一张GPU这是为了简化模型但真实生产里很多7B小模型跑不满一张卡上MIG可大幅提升利用率代价是性能隔离变差。你需要在共享度和隔离性之间做平衡我的建议是延迟敏感的模型独占卡吞吐型的小模型可以共享卡。4.4 实测踩过的坑这套方案落地过程中我踩过的坑大概可以整理成一张避坑清单现象排查思路解决办法预测总是滞后于突发流量检查预测窗口是否小于模型启动时间加长预测窗口或提前做容量预热扩容后SLO仍违约看新replica是不是还没接流量就被旧流量冲垮新replica预热后再接流量分批扩容缩容后流量反弹导致再次扩容缩容策略过于激进没有预留SLO余量用置信区间高百分位做判断缩容幅度设置上限跨模型扩缩容动作频繁触发决策层没有设置动作滞后hysteresis加冷却时间和最小调整步长减少抖动MIG共享时一个模型喷发影响其他模型隔离不足算力和显存两者都被挤占延迟敏感模型独占卡并限制共享模型的并发数值得一提的还有模型冷启动的预热缓存。对缩容决策来说KV cache是有价值的资产如果能做到把replica保留但不接流量scale to zero之后还保留最后的cached state下一次扩容会快很多。这个不在论文的主体范围内但确实是我在生产环境里见过最多收益的一个优化点。5. 读完这篇论文我的一些真实体会这篇论文最值得学习的地方不是某一个具体算法而是它把共享LLM服务的自动扩缩容从一个运维问题变成了一个有明确目标函数、有约束条件、有预测和决策支撑的工程问题。这种做法本身就很对因为LLM服务的基础设施迟早要从人肉看监控走向自动决策跨模型协调是必然要过的坎。以我个人的落地经验来看如果要从论文走向生产环境最值得先做的是预测层和决策层的最小可行性版本先用历史数据做负载分解预测每个模型未来10分钟的负载区间再基于集群当前显存和算力空闲情况输出推荐的replica数调整方案供运维人员确认后执行。这种半自动模式其实比直接全自动更靠谱因为你自己可以先积累一批决策样本观察模型的建议是否合理等信心够了再逐渐放开全自动执行。这套系统并不需要一次到位能先把从预测到建议打通价值就已经很大了。