ARTICLE DETAIL

资讯详情

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

跨模型自动扩缩容:共享LLM服务的资源博弈之道

跨模型自动扩缩容:共享LLM服务的资源博弈之道 最近读到一篇很有意思的论文题目叫《Cross-Model Autoscaling for Shared LLM Serving》翻译过来就是“共享 LLM 服务的跨模型自动扩缩容”。它跟我之前研究的单模型推理优化路线完全不同关注的是一个更高层次的工程问题当一个推理服务集群里同时跑着几十个甚至上百个大模型、每个模型的流量又毫无规律地波动时自动扩缩容到底应该怎么做。这篇论文适合三类人读一是手里维护着多个模型推理服务的平台工程师二是做 GPU 资源调度和成本优化的人三是对 LLM 推理系统架构感兴趣的读者。全文没有任何花哨的模型结构改进就是实打实的资源博弈方法论读完非常解渴。先说一个很反直觉的结论在共享 LLM 服务场景下单模型视角的自动扩缩容做得再好整体利用率也上不去。原因很简单——你占着坑他也占着坑谁都不愿意让。而论文把扩缩容从一个“某个模型自己的事”变成了“集群级的资源博弈”这里面可挖的东西就多了。1. 它解决的痛点单模型扩缩容为什么不够用1.1 共享LLM服务里真正的阻力不是“算力不够”很多团队一开始做 LLM 推理服务的时候思路是“一个模型一个集群”或者“一个模型一个固定资源池”。模型少的时候没问题模型一多问题全来了。我先画个场景假设你有 20 个模型每个模型按峰值负载申请了 4 张 GPU总共就是 80 张 GPU。可实际上每个模型的平均负载可能只有峰值的 20% 到 30%。这意味着 80 张 GPU 里真正被用到的可能还不到一半。这不是算力不够是“用的不匀”。有人会说那就按平均负载申请呗峰值来了靠 HPAHorizontal Pod Autoscaler扩容不就行了理论上可以但你一旦做了就会发现HPA 的指标拿的是每个模型自己的 QPS、GPU 利用率和显存使用量它根本不知道集群里其他的模型此刻是否也在抢 GPU。于是经常出现这样的局面模型 A 在半夜流量暴涨它自己的 HPA 疯狂把副本从 3 拉到 20直接把集群里所有空闲显存和算力吃掉与此同时白天高峰期的模型 B 发现扩不动容了只能硬扛延迟或者拒绝请求。这就是共享服务“拆开玩”的必然结果。每个模型都按自己最保守的估计去向集群要资源集群却没有一个统一的视角来仲裁谁该给多少。论文里提到的跨模型自动扩缩容核心解决的就是这个仲裁问题。1.2 单模型扩缩容的局部最优陷阱我前两年做推断服务的时候也掉进过这个陷阱。当时维护三个模型每个模型都有自己的弹性策略基于 K8s HPA 配置了一堆指标QPS、GPU util、平均延迟。看起来完全自动化了结果三个模型在同一个物理集群上互相抢资源谁也不让谁。问题出在三个地方。第一指标本身有滞后性。HPA 默认的指标采集周期是 15 到 30 秒从指标变化到副本调整又要几十秒等 Pod 拉起来初始化和模型权重加载加起来又是几十秒到几分钟。大模型的流量突刺往往在几十秒内就能打满整张卡单模型扩缩容根本没时间反应。第二局部最优不等于全局最优。每个模型的扩缩容逻辑都只考虑“自己够不够”不考虑“别人撑不撑得住”。从单个模型看扩到 10 个副本确实把延迟打下来了但从集群看这 10 个副本挤占了其他模型的位置总体收益是负的。第三LLM 推理的资源模型是二维的不是一维的。GPU 利用率高不代表显存还有余量显存够用也不代表算力不冲突。KV Cache 的增长让显存占用成为一个动态变量单模型的 HPA 往往只看显存的静态申请根本不考虑 KV Cache 带来的弹性变化。论文把这个问题拆成了两个层次一个是“负载预测”即未来几分钟某个模型到底需要多少资源另一个是“资源分配”即集群里的 GPU 显存和算力如何在多个模型之间动态分配。跨模型自动扩缩容的整个框架本质上就是围绕这两层做的。1.3 论文给出的新视角跨模型自动扩缩容论文的核心思想用一句话概括不要为每个模型单独决定扩缩容而是让集群作为一个整体根据全局的负载预测来动态调整每个模型的资源配额。具体来说它把扩缩容问题建模成“在资源总量固定的前提下每个时刻为每个模型分配多少 GPU 算力和显存预算使得整体服务质量最优”。这里面有约束条件总显存不能超过集群物理显存总算力不能超过集群算力每个模型的延迟或吞吐要有底线保障。优化目标可以是拒绝率最低也可以是加权资源利用率最高或者是在满足 SLO 的前提下 GPU 数量最少。这个视角的威力在于它可以做“跨模型的资源置换”。比如模型 A 是文本分类模型显存占用高但算力需求低模型 B 是生成式模型显存占用中等但算力很吃。如果它们在同一个 GPU 上调度就可以做到显存和算力的互补利用整体资源效率远超各自独占一张卡。这不是简单的 bin-packing 问题。因为模型之间的资源需求不是固定的——KV Cache 会随请求增长batch size 会随流量变化所以论文把问题描述成一个在线优化问题每一步都需要根据最新预测做出决策。这也是“自动”二字的真正含义不是配置好阈值就不管了而是要有一套机制去持续感知、预测、决策和调整。2. 核心机制拆解负载预测、显存预算与调度决策2.1 负载预测器用混合时间尺度滚动预测替代单点阈值跨模型自动扩缩容的前提是“预知”。论文里没有用那种很重的深度学习模型去做流量预测而是设计了一套轻量级的混合预测器用不同时间尺度的历史窗口来捕捉流量模式。为什么非要分尺度因为 LLM 服务的流量有两个典型的周期性一个是以小时为单位的“上下班峰谷”另一个是以分钟甚至秒钟为单位的“突发脉冲”。如果只用一个窗口你很难同时捕捉这两种节奏。短窗口能感知到突发但噪音很大容易导致扩缩容震荡长窗口平滑了噪音但反应太慢等它发现涨了流量已经过去了。论文采用的方式是对每个模型维护一个短时间窗口的预测值和一个长时间窗口的基线值然后按一定权重组合。短窗口负责捕捉突刺长窗口负责稳定基线再用一个滑动平均去平滑。我在实际工程里试过类似的思路用一个简单的指数加权移动平均就能打掉大部分抖动但升级成混合窗口之后对资源预留的准确率提升非常明显。这里有一个关键细节预测器输出的不是“某个模型的负载”而是“每个模型未来一段时间内的资源需求分布”。它要能回答“模型 A 未来 5 分钟的请求量会有多大概率超过当前配额”这种概率性问题。论文用历史分位数来估计这个概率当某个模型的预测需求超过当前配额的概率超过一定阈值时才触发扩缩容决策。这种方式能天然消除误判和抖动。2.2 显存与KV Cache预算池化跨模型共享的隐藏核心LLM 推理里的显存占用分为两部分一部分是模型权重固定大小另一部分是 KV Cache随并发请求动态增长。很多团队在做扩缩容的时候只盯着权重这个固定值完全忘了 KV Cache 才是真正的“吸血鬼”。论文把显存预算建模成一个全局资源池每个模型从池子里申请预算而不是各自绑定物理卡。当模型 A 的流量下去之后它应该主动释放一部分 KV Cache 预算还给资源池模型 B 流量上来时再从资源池里申请。这样做的一个额外好处是GPU 上的显存碎片会被压缩整体能容纳的模型数量和并发请求量都会上升。为了让这套机制落地论文里没有用虚拟化或容器层面的显存隔离而是直接在推理引擎层面做了预算控制。每个模型的推理实例被限制在一个“显存预算区间”内下限保证它能正常服务当前负载上限防止它把整个 GPU 吃光。当某个模型的 KV Cache 占用即将触及预算上限时调度器会在两种策略里选一个要么回收这个模型的其他资源给它更多显存预算要么对它做并发限制挡住一部分新请求。从工程角度看这个设计的价值非常大。它让“跨模型资源池化”不再是一句口号而是每个模型实例随时可以量化和调整的实际指标。我在自己的服务上总结出来的经验是KV Cache 预算是所有扩缩容决策里最不能拍脑袋的指标因为它的增长速度跟请求长度、batch size、模型层数都有关系必须动态测量。2.3 调度决策引擎小步调优 批量置换预测做完了显存预算也量化了接下来最关键的一步是“怎么调”。论文的调度决策引擎采用了两级结构。第一级是“小步调优”每次只调整一个模型的资源配额幅度控制在 10% 到 20% 以内。这样做的好处是稳定性极高不会因为一次激进的调整导致大规模的资源迁移也不会让正在处理的请求突然被打断。对于大部分时间点来说小步调优已经足够因为流量的变化本身就是渐进的。第二级是“批量置换”当某个模型的预测负载突然暴涨单靠小步调优已经无法满足时调度器进入批量置换模式。它会把多个不怎么活跃的模型资源同时释放一次性分配给暴涨的模型。这种模式有点像高速公路的应急车道——平时不启用但真堵起来必须快速让特种车辆通过。我特别想聊一下调度决策里的目标函数。论文的优化目标不是简单的“平均资源利用率最大化”而是“在满足每个模型 P99 延迟指标的约束下最小化需要占用的 GPU 总数”。这个目标函数非常符合生产环境的真实诉求你不是想看到一张卡跑到 100% 利用率而是想用最少的卡让所有模型都达标。平均利用率只是一个中间指标真正的 KPI 是 GPU 数量和 SLA 达标率的乘积。2.4 冷启动与弹性扩容的博弈任何自动扩缩容方案都逃不开冷启动问题。LLM 模型动辄几十 GB从容器启动到模型权重全部加载到显存再做完 warmup通常需要 30 秒到几分钟。你预测得再准如果扩容动作本身需要三分钟才能生效那预测窗口拉得再短也没有意义。论文对冷启动的处理策略是“分层预留”把副本分成热副本、温副本和冷副本三个层次。热副本已经加载好模型权重只等着接流量温副本资源已经分配好但模型还没加载完接到扩容信号后可以直接启动加载冷副本是纯粹的可用资源池被调度器视为弹性余量。这套分层机制让我想起以前做 Java 服务时搞的“预热连接池”逻辑是一样的让成本最高的初始化动作尽量提前做把代价转移到低峰期。对于 LLM 推理来说模型加载是最大的成本所以跨模型扩缩容必须尽可能减少“从零加载模型”的次数。论文里提到的做法是当需要扩容一个模型时优先选择已经被其他模型释放的内存和显存复用已有的资源碎片而不是启动全新实例。从零加载永远是最差选择。这个思路在工程上落实下来就是一句话宁可让 GPU 有一点余量也别把所有资源都塞满因为塞满之后新的模型实例就要等冷启动那才是真正的大麻烦。3. 评估方法与实验结论怎么看3.1 四个关键指标别只盯着GPU利用率读论文最容易犯的错是只看作者给了什么指标不看指标背后的意义。这篇论文的实验评估用了几组指标我挑四个最重要的拆开讲。第一组是 P50 和 P99 延迟。共享服务里P50 影响的是用户体感P99 影响的是 SLA 达标率。跨模型扩缩容的难点在于你无法牺牲任何一个模型的 P99 来满足其他模型的扩容需求所以论文里把 P99 是否达标作为调度决策的硬约束。第二组是请求拒绝率。多模型共享集群时如果不能及时扩容拒绝率会飙升。论文把拒绝率控制在非常低的水平这主要靠的是预测器提前 2 到 5 分钟发出预警而不是靠事后补救。第三组是 GPU 利用率。注意这里统计的不是单卡利用率而是集群整体利用率并且会把显存利用率和算力利用率分开统计。因为 LLM 推理里经常出现“显存爆了但 GPU 算力闲置”或者“算力打满了但显存还有很多空余”的情况只看一个指标会掩盖真实瓶颈。第四组是扩缩容响应时间。从“预测到需要扩容”到“实际扩容完成”之间的时间差决定了方案能否应对突发流量。论文在这块做了分层统计预测时间、决策时间、实例拉起时间、流量切换时间。这四段时间中实例拉起时间通常是最长的也是优化空间最大的。3.2 与基线方案的对比HPA为什么不够用论文里对比了两个基线一个是刚才说的 HPA另一个是带有“每个模型独立资源池”的预留方案。实验结果非常直观固定资源池方案在流量波动时GPU 利用率大概在 30% 到 45% 之间波动而跨模型自动扩缩容方案能把利用率提到 60% 到 80% 区间同时保持 P99 延迟稳定。为什么 HPA 会明显落后原因就是我在开头说的HPA 不具备集群视角。它只能看到每个模型的独立副本数是否满足需求看不到全局的资源博弈。当两个模型同时需要扩容时HPA 的表现是“谁先触发谁先抢”缺乏优先级仲裁。而论文的调度器会基于实时预测和目标函数判断哪个模型的扩容收益更高把稀缺资源分配给更需要的一方。另一个细节是论文比较了“带 KV Cache 预算管理”和不带预算管理的差异。结果发现仅加了一层显存预算池化就能让 GPU 利用率提升 10 到 15 个百分点。这说明跨模型自动扩缩容的大部分收益其实来自“资源可以互相借用”而不是来自更精确的流量预测。3.3 实验数据告诉我们的三个趋势从论文给出的实验结果里我能读出三个工程上很重要的趋势。第一个趋势是模型的流量相关性越低跨模型扩缩容的收益越大。如果 20 个模型都集中在白天高峰流量那你做跨模型调度也救不了因为所有模型都在抢同一批资源但如果模型的流量分布在时间上错开比如有些模型在凌晨上线有些在傍晚流量很高那么共享池的收益就会被放大。所以论文里的负载数据用的是真实的多模型流量分布相当分散实验收益才那么明显。第二个趋势是请求长度越长、模型规模越大的场景KV Cache 预算池化的收益越显著。大模型的 KV Cache 占用成倍增长如果没有预算控制一个长文本请求就能让整张卡的显存立刻告急。论文的预算管理在这里起到了“削峰填谷”的作用。第三个趋势是扩缩容的“频繁程度”并不是越高越好。论文实验里设置了决策周期5 秒、30 秒、60 秒三档发现 30 秒决策周期在综合表现上最优。为什么因为 5 秒决策周期会让调度器在流量噪声里来回调整造成资源抖动60 秒又反应太慢突发流量打进来来不及处理。这个观察非常重要我在实际部署里也发现过度敏感的扩缩容逻辑往往会引发“扩容完立刻缩容”的震荡白白消耗资源。4. 从论文到生产工程落地建议与最小实现路径4.1 可以直接借鉴的三个设计论文里的设计不一定都能直接搬到生产环境但有三样东西是可以立刻抄的。第一样是“预测 决策”分离的架构。负载预测模块和调度决策模块不要耦合在一起。预测器输出的是“每个模型未来时间段内的资源需求分布”调度器只负责根据这个分布做决策。这样做的最大好处是你可以先上线一个简单的预测器比如滑动平均跑通了再升级成更复杂的模型不需要重构调度器。第二样是 KV Cache 预算上报机制。让每个模型实例周期性地把“当前 KV Cache 占用”“显存总占用”“请求并发数”上报到中心调度器。上报频率建议 10 到 30 秒一次太频繁会增加开销太稀疏又会让调度器反应迟钝。这个机制完全可以在现有推理引擎上通过一个边车进程实现不用改引擎内部。第三样是“分层副本”的弹性池设计。热副本始终保持运行温副本预留但未加载冷副本作为弹性余量。这套设计会让你的 GPU 资源看起来“浪费”了一部分但它在突发流量下的稳定收益远超这点浪费。实际上你可以在业务低峰期把热副本降到最低数量把多出来的资源归入冷副本池这样成本损失几乎为零。4.2 需要自己补课的三个环节论文可以给你思路但生产落地时会有三个环节需要自己补课。第一个环节是推理引擎的指标采集接口。论文里的显存预算控制是直接对推理引擎下手的但你用的可能是 vLLM、TGI、TensorRT-LLM 这类开源引擎它们的显存管理接口各不相同不一定支持动态设置 KV Cache 上限。你需要做一层适配要么打补丁要么在网关层做并发限流用外部手段控制显存增长。我个人更推荐先用网关层限流兜底再逐步深入引擎层改造。第二个环节是服务网格或网关的流量切换能力。跨模型扩缩容的最后一步是把流量从旧副本切换到新副本这个过程不能断流也不能让请求卡死。你需要灰度切换、连接 draining 和优雅停机这三件套。这块纯粹是工程活论文里也没有展开但没做好的话前面预测和调度都白搭。第三个环节是多模型间的优先级定义。论文的目标函数是“在 P99 达标下最小化 GPU 数”但你没有实时 P99 数据怎么办你需要自己定义一套优先级体系哪些模型的 P99 是强约束哪些模型允许在资源紧张时降级。没有这套体系调度器面对资源不足时就会陷入“谁都不让谁”的僵局。4.3 一条可参考的最小实现路径如果你看完论文想快速验证一下跨模型自动扩缩容的思路我建议你按下面这条路径来不要一上来就做大而全的系统。第一步采集指标。先在推理网关或服务网格上采集每个模型的 QPS、P50/P99 延迟、GPU 利用率和显存占用落到一个时序数据库里。这一步通常一周能搞定前提是你的监控体系已经比较健全。第二步实现一个简单的预测器。不用上什么深度学习就用指数加权移动平均加一个分位数估计预测每个模型未来 5 分钟的负载区间。关键是输出“概率”而不是“值”这样调度器才能基于置信度做决策。第三步在调度层实现一个“准入控制”模块。当某个模型的预测负载超过当前配额且置信度高于阈值时它可以从全局空闲资源池申请资源如果资源池不够则触发低优先级模型的缩容。这一步先不做自动执行可以先出告警让人工确认等逻辑打磨成熟了再切自动模式。第四步验证和调参。至少跑两周的流量对比观察 GPU 利用率、P99 延迟和拒绝率的变化。重点调三个参数预测窗口大小、置信度阈值、决策周期。窗口太长反应慢太短噪声大阈值太高永远不触发太低疯狂震荡决策周期 30 秒左右通常是一个不错的起点。5. 避坑清单与实践心得5.1 自动扩缩容最容易踩的四个坑第一个坑是只看平均负载不看分位数。我见过不少团队拿“GPU 平均利用率”当扩缩容指标结果平均利用率只有 40%但 P99 时段能冲到 95%。等扩容完高峰已经过去了白白多跑了几小时机器。建议关注 P95 或 P99 时段的负载曲线而不是平均负载。第二个坑是对 KV Cache 预估不准。有些模型输入特别长并发稍微一高KV Cache 立刻吃光显存。如果你只按模型权重 固定 batch size 估算显存很容易在运行到一半时 OOM。建议在网关层加一层并发限制按当前 KV Cache 占用动态调整最大并发数。第三个坑是扩容完立刻缩容。这类震荡在决策周期过短的方案里非常常见。解决办法有两个一是加“冷却时间”扩容后至少稳定 N 分钟再允许缩容二是加“滞回区间”扩容阈值和缩容阈值之间留出空隙比如负载超过 80% 才扩容低于 50% 才缩容。第四个坑是忽略冷启动对实验结论的影响。论文实验里的模型可能已经做了权重缓存或热加载优化但你的环境未必具备这个条件。如果你的模型加载需要 3 分钟那么预测窗口至少得干到 5 分钟以上否则预测再准也没时间执行扩容。5.2 论文没说透但工程上躲不开的细节第一个细节是模型权重与 KV Cache 的“共卡”约束。论文的显存预算池化看起来很美但实际上模型 A 的权重和模型 B 的 KV Cache 如果落在同一张卡上它们之间是物理隔离的不能随意混用。你需要在调度器里维护一张“卡级视图”而不是只维护集群级的总量视图。第二个细节是“跨模型导流”对 prefix cache 的影响。有些 LLM 服务会缓存 prompt 的 prefix KV以加速系统提示词重复的请求。但如果你为了让模型 B 更快扩容把模型 A 的部分流量导走模型 A 的 prefix cache 可能会失效导致接下来的请求全部需要重新计算延迟反而上升。这是我实际遇到过的问题非常隐蔽。第三个细节是 GPU 的显存碎片问题。长期跑多个模型的 GPU 上会出现显存碎片新旧副本共存时尤其严重。建议定期做有计划的驱逐和资源整理否则跨模型调度到后期会发现“总显存够但碎片化到一块卡都整不出来”。5.3 我读这篇论文的最大体会我读这篇论文最大的收获不是那几个百分比提升而是它把“自动扩缩容”的视角从“单模型自治”抬到了“集群级资源博弈”。过去我调试 HPA 参数总是纠结于“这个模型的 CPU 阈值设多少”现在我会先问“整个集群里的资源应该怎么在模型间买进卖出”。做共享 LLM 服务就像开一个大食堂每个模型都是不同的菜品。你不能因为番茄炒蛋高峰期排队就把整个后厨都给它那样红烧肉和清蒸鱼就停工了。真正要设计的是“档口之间的备菜互借机制”哪个菜排队太长就从其他菜品那边借点人力而不是让每个菜都养一整套后厨。最后分享一个小实操建议如果你正在做多模型共享的 GPU 集群不用急着上整套跨模型扩缩容系统。先做一件事——给每个模型加一层可动态调节的 KV Cache 显存预算接口然后改成按全局资源池申请显存。光是这一步我实测就能让集群整体吞吐提升一到两成。把这一步跑顺了再考虑负载预测和调度决策你会发现自己对扩缩容的理解已经完全不一样了。
返回列表