AI计算基础设施的演进:资源调度走向动态复用
在大规模AI集群中,提高资源利用率的手段通常从资源空闲情况开始:一张GPU还有多少显存和算力可以分给其他任务?
当在线推理服务和Agent应用逐渐增多,这个问题又多了一个时间维度。一个Agent会话可能持续数小时,真正执行代码的时间却很短;一个模型需要长期准备好对外提供服务,但实际请求活跃的时间也可能只占一小部分。资源被占用,不一定意味着它正在产生有效计算。
沿着这些问题继续看,会发现AI计算基础设施正在发生一条比较清晰的变化:资源管理逐渐摆脱静态绑定,开始根据工作负载的实时状态调整资源形态和占用周期。
这条演进包含两个方向:
- 细化空间分配粒度:从整卡分配发展到显存、算力切分,以及按请求动态创建MIG分区;
- 缩短空闲占用时间:保留会话、进程和模型状态,在等待期间释放CPU、Memory或GPU。
2026年9月7日-9月9日 KubeCon China的几场分享覆盖了这条演进路径。
- HAMi提出将整卡细化为可共享的显存与算力;
- Dynamic MIG方案让硬件分区跟随请求创建;
- OpenKruise Agents方案将工作负载生命周期拆分,会话状态和agent运行时解耦;
- llm-d Fast Model Actuation提案继续拆分模型进程与GPU分配关系。
四类方案连接起来,可以看到资源复用的范围正在扩大:从处理一张卡内部的闲置算力,再处理设备布局,随后进入会话和模型的状态管理。本文围绕这条演进路线,进行相关技术总结和思考。
一、第一步:细化GPU分配粒度
1. 显存与算力切分
合合信息在《How Intsig Serves Billions of Document Scans》主题分享中给出了一个典型场景:业务的小模型只需要2GiB显存,却占住了一张40GiB GPU算力。导致集群中的GPU都被分配后,卡上仍有大量空闲显存;但是由于单卡分配的限制,新提交的任务只能排队等待前面执行的任务释放资源。
这里缺少的资源不在物理算力层,而在k8s资源调度层:资源的感知和分配都是整卡维度,无法天然地将卡内剩余空闲容量继续分配给其他任务。
为解决这一层的问题,HAMi把一张GPU抽象成可分配的显存容量和算力份额,支持按显存容量和算力份额分配 PU资源,使多个任务能够共享同一张GPU。例如,一个任务可以申请2个vGPU,每个vGPU包含10GiB显存和30份算力:
resources:
limits:
nvidia.com/gpu: 2
nvidia.com/gpumem: 10240
nvidia.com/gpucores: 30
这条资源链路由三个组件完成:
| 组件 | 主要职责 |
|---|---|
| HAMi Scheduler | 根据显存、算力需求和调度策略选择节点及物理GPU |
| vGPU Device Plugin | 向kubelet注册资源,并将调度结果转换成容器侧设备配置 |
| HAMi-Core | 拦截CUDA/NVML调用,执行显存限额、算力控制和用量统计 |

2. 算力超卖与显存超卖:提高部署密度
按显存和算力切分后,多个任务可以共享一张GPU。但当申请份额之和超过GPU卡维度的容量时,新任务仍会排队。进一步分析,存在已有任务的计算高峰不重叠,或模型在两次请求之间长期闲置的情况。如果能做到算力超卖和显存超卖能力,让同一张卡容纳更多任务,就能利用时分复用来填充算力。
HAMi采用的方式是将单卡可分配份额从100设为120,让四个各申请30份算力的任务同时落在一张卡上。物理处理能力没有增加,这种放置依赖任务的计算高峰错开。gpucores: 30是调度与节流的输入,不能直接换算成独占30%的SM,也不保证获得整卡30%的吞吐;HAMi默认允许任务借用空闲算力,开启强制限制后才会持续节流。若四个任务同时进入高负载,吞吐与延迟就会受到影响。HAMi官方文档和GPU Partitioning实验对算力份额的行为有更详细的说明。
显存有硬容量限制,超卖需要为暂时用不到的数据迁移到其他存储介质。HAMi Enterprise相关方案会将长时间无请求的模型权重从GPU显存换到主机内存,腾出的显存交给其他活跃模型;原模型再次收到请求时,再把权重换回GPU。这样可以部署更多模型,但要付出PCIe传输和恢复等待的成本。若多个模型同时变得活跃,换入换出也可能抵消部署密度提高带来的收益。这是个关键的trade off。

图源:Wave GPU页面。页面给出的A10G/KServe测试中,模型总承诺显存为29,000MiB,GPU显存为23,028MiB,其余5,972MiB由主机内存承载;图中的模型块大小仅作示意。
两种超卖方式的实现和适用条件可以放在一起看:
| 能力 | 解决方法 | 适用条件 |
|---|---|---|
| 算力超卖 | 通过deviceCoreScaling放大单卡可调度算力容量。例如倍率为1.2时,账面容量由100份变为120份,可容纳四个各申请30份算力的任务。 | 显存能够容纳多个实例,任务计算峰值错开;物理处理能力不变。 |
| 显存超卖(HAMi Enterprise) | 将一段时间无请求的模型权重从GPU显存换出到主机内存,请求到达后再换回GPU,实例保持存活。 | 模型访问有明显的空闲时段,并能接受权重换入带来的恢复开销。 |
因此,共享方案落地时至少需要同时观察:
- 分配显存与实际显存使用;
- 算力配额、GPU利用率和业务延迟;
- 同卡任务的负载峰值是否重叠。
合合信息的实践主要体现在任务选择和放置方式上:
- 小模型优先资源切片、大模型保留整卡的运营策略;
- 采用Binpack减少半卡碎片的分配策略;
- 将高低负载任务错峰排布。
这些策略共同说明,切分只是资源复用的起点,调度仍需理解工作负载特征。
HAMi完成了演进中的第一步:把“是否有空闲GPU”细化为“卡内还有多少可分配显存和算力”。软件共享提高了空间利用率,同时也带来性能干扰和运行时配额执行问题。需要更强隔离时,资源管理会进一步进入硬件分区层。
二、按请求创建MIG实例
1. Profile与Placement分别表示什么
MIG支持从硬件层把一张GPU划分为多个相互隔离的设备。但启用MIG模式,与在卡上创建可供任务使用的MIG设备,是两步操作。HAMi能够做到先启用MIG模式,按需创建MIG设备。理解后面的按需创建,需要先区分三个概念。
- Profile描述分区规格。以
1g.10gb为例,1g表示使用一个GPU计算切片,10gb表示该实例获得的显存容量。Profile同时约束SM、显存切片、缓存等硬件资源。 - Placement描述该Profile在物理切片布局中的合法位置。相同Profile可能有多个起始位置,但不能与已经存在的MIG实例重叠。
- MIG实例是按某个Profile、在某个Placement实际创建出来的硬件分区。实例创建完成后,容器才能获得对应的MIG设备。
同一种Profile也可以在不同位置创建出多个MIG实例。NVIDIA的MIG概念文档指出,已创建实例的物理位置会影响后续还能创建哪些实例。
上文的1g.10gb是H100等型号支持的Profile。下面这张NVIDIA B200支持的Profile与Placement示意图列出B200硬件允许的布局组合。图中每行Config是一种可能的整卡布局,不代表GPU已经按这一行创建了实例;可用Profile和合法位置由硬件限定。

2. 从预设布局转向按请求创建
预切方案会先选定一张卡的布局,创建好相应的MIG实例。这个布局可以混用多种Profile。以NVIDIA Device Plugin的mixed模式为例,节点把已有MIG实例按规格上报为nvidia.com/mig-1g.10gb、nvidia.com/mig-2g.20gb等资源;Pod申请某种规格,kubelet从现成实例中分配一个MIG设备。Pod结束后,实例留在卡上供下一个Pod使用。若所需规格的实例都被占用,其他规格即使闲置,也不能直接充当这个请求。通过MIG Manager重新配置布局可以改变规格组合,但会涉及GPU工作负载的清理和恢复。
《Dynamic MIG with HAMi》讨论的是另一条链路:卡先进入MIG-ready状态,无需预先创建一套固定的MIG实例供Pod领取。以HAMi v2.10的实现为例:
- Device Plugin通过NVML发现硬件支持的Profile和合法Placement,把集群策略允许的规格提供给HAMi Scheduler;此时上报的是可创建能力,还没有创建对应的MIG实例。
- Pod通过
nvidia.com/gpu申请设备数量、通过nvidia.com/gpumem给出显存下限,并选择MIG模式。Scheduler结合卡上已有实例的占用位置,选择满足需求的Profile与空闲Placement,在绑定Pod前记录预留。 - kubelet调用Allocate时,Device Plugin才在预留位置创建可供容器使用的MIG设备,并将其MIG UUID提供给容器。
- Pod结束后,Device Plugin通过周期性对账回收对应的MIG实例。其他Pod持有的实例保持原样,释放的位置可以用于后续请求。
例如,同一张空卡上的前两个Pod分别被分配到2g和1gProfile,卡上会逐个出现对应实例;持有2g实例的Pod结束后,只回收它占用的那部分。后续若有合法位置,空出来的空间可以创建另一种规格,无需清空整卡并切换预设布局。这里的nvidia.com/gpumem是所需Profile的显存下限,容器获得选中实例的完整显存,与前一章HAMi-Core的软件显存限额不同。HAMi的Dynamic MIG实验展示了这种分配结果。
这里的Dynamic指实例在Pod分配时创建、Pod结束后回收。它没有改变硬件支持的Profile和Placement,也不会为了新请求搬动运行中的实例。
3. 动态创建仍然会遇到布局碎片
以A100-40GB的合法Placement为例,3g.20gb的起点只有0和4。若卡上已有一个2g.10gb实例占住位置0、另一个1g.5gb实例占住位置4,空闲切片的总量看似足够,两个合法起点却都无法使用。请求所需规格的Pod只能等待其他实例被回收。

图源:《Dynamic MIG with HAMi》,第8页。
这与多卡节点上的GPU碎片很相似:总量只能回答“还剩多少”,布局才能回答“能否组成请求需要的形态”。Dynamic MIG没有消除碎片,它让碎片成为调度时可以观察和决策的状态。
调度判断至少需要包含三部分:
可创建实例 = Profile满足需求
∩ 存在合法Placement
∩ Placement与当前实例布局不冲突
Profile、Placement与当前布局共同决定真实容量。仅上报剩余显存或空闲切片数量,会高估大规格实例的可创建能力。
Dynamic MIG将调度对象从已创建的MIG实例,扩展到当前硬件允许创建的实例。它适合请求规格比例经常变化、预切布局容易失配的场景;规格长期稳定时,预切混合布局也可以很好地工作。到这里,资源动态化仍集中在空间维度,工作负载运行期间会一直持有硬件分区。Agent类任务的大量等待时间,使时间维度成为下一步需要处理的问题。
三、让Agent会话与执行资源分开
1. 会话仍在,Sandbox可以暂停
一个Agent会话可能先执行代码,随后等待用户输入,过一段时间又被定时任务唤醒。会话一直存在,实际计算却集中在几个短暂的窗口。若Sandbox始终Running,等待期间也会占用CPU和Memory;直接删除Pod,又要解决工作空间、运行依赖和会话上下文的恢复问题。
《Hibernate and Evolving: Taming OpenClaw with OpenKruise Agents》分享中把需要留下的Agent状态与可以回收的计算资源放在一起讨论。对应到实现,至少要回答两个问题:什么时候可以暂停,以及暂停后哪些状态还能回来。

2. 从业务空闲到Sandbox暂停
OpenKruise Agents提供两种触发方式。pauseTime设定一个到期时间,到点后即使Agent仍在工作也会暂停,适合有明确使用期限的会话。另一种方式是周期性执行Probe,只有业务持续报告空闲达到thresholdDuration,Controller才将Sandbox设为暂停。自动暂停规则中,Probe的status=True只表示命令成功执行,业务状态在输出的message里,再由messageRegex匹配。Probe失败或超时不会触发这条空闲暂停路径。

暂停触发后,Sandbox的CPU和Memory可以归还集群,但保存了多少状态取决于策略:
| Pause策略 | 暂停时保留的内容 | 恢复时需要注意 |
|---|---|---|
| 默认策略 | 将rootfs持久化到Sandbox使用的存储卷 | 文件可以恢复,不等于进程内存和连接仍在 |
| Stop | 只保留PVC中的数据 | 未写入PVC的rootfs修改会丢失 |
| Snapshot | 将rootfs保存为快照 | 仍需检查应用状态与外部连接 |
设置spec.paused: true后,Sandbox会进入暂停流程,并在暂停完成后释放CPU和内存。默认策略可以保留rootfs中的文件,但正在处理的请求会中断,WebSocket等长连接在唤醒后也需要重建。因此,应在请求结束、长连接断开后再暂停。唤醒时还需重新分配资源;如果集群容量不足,恢复可能失败。
恢复同样需要提前设计。无法预测的用户请求可以经Sandbox Gateway触发唤醒,等待Sandbox就绪后再转发;已知下一次定时任务的时间,则可以在暂停前记录任务时间,并依据leadTime提前恢复。OpenKruise分享,第17页

图源:OpenKruise分享,第17页。原图将部分入口流量触发唤醒能力标为规划中,不能理解为所有接入方式已经可用。
3. 实例缩到0后,下一次请求如何回到原会话
另一场《Can Stateful AI Agents Scale to Zero?》把问题推进到会话入口:当执行实例已经缩到0,它无法再通过自身的CPU或QPS指标发出扩容信号,也接不到下一次请求。分享提出扩展Knative Activator,在入口识别Session、查找绑定、暂存请求并触发唤醒。这是针对有状态Agent的扩展方案,不能直接当作原生Knative或OpenKruise已经交付的一条完整链路。

图源:《Can Stateful AI Agents Scale to Zero?》,第4页。上图直接截自原PDF,展示了分享提出的扩展方案。
假设会话S完成一次工具调用后进入等待。Runtime可以回收,但S的身份、工作空间和未完成任务仍要有可恢复的记录。下一次请求到达时,入口先识别S,找到它的状态,领取或创建Runtime,恢复工作空间与任务进度;只有恢复后的实例通过Ready检查,请求才能继续交给原会话。这里至少有三处状态交接不能省略:
- 保存什么:会话上下文、工作空间和任务进度需要分别确定持久化位置。rootfs快照能保存文件,不会自动保存进程内存,也不能说明上一次外部操作是否已经成功。
- 如何找到:Session要有独立于Pod的稳定身份,入口还要能查到它与Runtime的绑定。Pod消失后,只靠原Pod地址或临时路由表无法恢复这层关系。
- 何时放行:入口需要在唤醒期间等待并设置超时;恢复失败、资源不足或状态校验失败时,应返回明确结果。Runtime启动不等于原会话已经可以继续执行。
这三点是根据分享提出的入口与会话分离思路所做的工程归纳。Warm Pool可以缩短Runtime准备时间,但仍需完成状态装载和会话绑定;池中预留的Sandbox也会继续占用资源。OpenKruise的Warm Pool设计处理的是准备容量,与会话连续性属于不同环节。
Agent休眠是否划算,要把回收的CPU/Memory时长与恢复成本一起看。误判空闲、唤醒失败、恢复后重复执行外部操作,比单纯的恢复耗时更影响一个长会话能否可靠地继续。
四、让模型进程与GPU分配分开
1. 空闲模型可以释放显存,Pod却还占着GPU
推理平台如果部署了多种模型服务,其实可以进一步分析业务流量特征。如果让长尾模型始终驻留GPU显存,算力会被低频请求占住;但把它们的Pod直接缩到0,下次请求又要重新经过冷启动流程(容器启动、Python模块加载、权重读入、Kernel预热和CUDA Graph Capture)。llm-d的Fast Model Actuation(FMA)尝试在两者之间保留可复用的运行环境。
FMA使用vLLM的Level 1 Sleep Mode:模型权重从GPU卸载到CPU内存,KV Cache内容丢弃,vLLM进程继续存在。下一次唤醒同一模型时,权重可以搬回GPU,但原来的KV内容不会恢复。vLLM还提供Level 2,连权重也丢弃;它是引擎提供的另一种休眠级别,不能算作这里FMA的Hot恢复路径。
只调用引擎的sleep接口,集群仍无法复用这张卡。显存使用下降了,Pod声明的GPU却还在Kubernetes资源调度的账本中。要把GPU重新分配给其他任务,需要在模型休眠时释放GPU申请,同时保留vLLM进程。
2. Dual Pods怎样完成这次交接
在Kubernetes里,Pod是调度和资源核算单位;MaaS场景中,平台实际要调度的是模型服务实例。FMA的Dual Pods设计用两类Pod分别表达活跃模型的GPU需求和承载它的推理进程:
| Pod | Kubernetes看到的资源需求 | 实际职责 |
|---|---|---|
| server-requesting Pod | 声明活跃实例所需的GPU,参与原生调度和设备分配 | 运行轻量requester,报告获配设备;不运行vLLM |
| server-providing Pod | 声明CPU和主机内存,GPU请求为0 | 运行vLLM;在Launcher方案中,还可保留多个模型实例 |
扩容时,requesting Pod先经scheduler和kubelet取得节点与GPU。Dual Pods Controller(DPC)读取分配结果,在同一节点寻找可唤醒的实例,或让providing Pod创建新实例,并把实际服务的Ready状态转发给requester。providing Pod能够使用requester获配的GPU,依赖FMA专门传递设备结果并配置CUDA_VISIBLE_DEVICES;普通Pod把GPU请求改为0,不会自动获得设备访问能力。设备分配与就绪转发说明
下面以Launcher方案为例,虚线表示GPU资源在requesting Pod名下核算:
flowchart LR
S["业务扩容"] --> R["server-requesting Pod<br/>声明GPU需求"]
K["scheduler + kubelet"] -->|"分配节点与GPU"| R
R -->|"注解关联模型需求"| D["Dual Pods Controller"]
D -->|"查询获配GPU"| R
R -->|"返回GPU UUID"| D
Q["Launcher-population Controller"] -->|"预置Pod"| P["server-providing Pod<br/>Launcher与vLLM实例"]
D -->|"绑定、唤醒或创建实例"| P
P -->|"实例就绪状态"| D
D -->|"转发服务Ready"| R
K -->|"探测requester Ready"| R
R -. "GPU资源核算" .-> G["物理GPU"]
P -->|"执行推理"| G
缩容的顺序同样重要。DPC通过finalizer暂缓requesting Pod删除,先使对应vLLM实例休眠或退出,再解除绑定并完成删除。此时GPU资源再在调度系统中释放,providing Pod和其中的休眠进程可以留下。若先释放账本里的GPU,旧实例还在执行,新任务就可能被分到同一设备。Dual Pods删除顺序
以同一张GPU上的模型A、B为例:A服务结束后,A的实例进入休眠,对应requesting Pod释放GPU;B的新requesting Pod获配这张卡后,DPC再唤醒B的实例。A、B的进程可以同时保留在Launcher里,但切换的是两个实例的活跃状态和GPU分配,不是让同一个vLLM实例反复装载不同模型。
这里还有一层设计的调整:早期Direct Provider由providing Pod直接运行一个vLLM实例;Launcher方案在providing Pod内保留预加载模块的父进程,再创建多个vLLM子实例。Launcher文档描述的是后一种结构。DPC处理实际推理需求,Launcher-population Controller按策略维持Launcher Pod池;Launcher进程本身不是第三个Kubernetes控制器。
3. Hot Start、Warm Start、Cold Start定义:取决于还能复用多少状态
requesting Pod取得GPU后,DPC在获配节点上选择激活路径:
| 路径 | 可以复用 | 还要完成 |
|---|---|---|
| Hot Start | 目标模型的休眠实例和CPU中的权重 | 唤醒实例、将权重搬回GPU、重新准备KV空间 |
| Warm Start | 已运行且预加载模块的Launcher | 创建目标模型实例、加载权重并完成初始化 |
| Cold Start | 没有合适的Launcher | 先创建Launcher Pod,再创建和初始化实例 |
Hot Start、Warm Start、Cold Start描述的是运行环境和模型状态的复用程度,与vLLM的Level 1、Level 2并非一一对应,而是与资源复用状态有关。即使需要按LRU淘汰Launcher里的旧实例,只要还能复用这个Launcher,新实例仍走Warm路径;只有Launcher也要新建时才进入Cold。Dual Pods激活路径
这也限定了FMA的收益。Hot Start命中率取决于目标模型的休眠实例是否还在获配节点上,保留权重需要主机内存,休眠实例还会留下少量GPU内存占用。Warm Start虽然省去Launcher准备,仍可能花较长时间加载权重;镜像、编译和本地权重缓存是否命中又会改变实际耗时。
评价模型切换时,需要把DPC激活、Pod Ready和首个成功请求分开测量。项目的fma_actuation_seconds记录的是requester容器启动到就绪转发完成的时间,不能直接代表用户看到的首请求时延。GPU释放后有多少请求走Hot Start,业务延迟是否仍满足要求,决定了这套机制能否真正提高有效复用。
五、释放后的资源能否真正复用
回到开头的问题,这几类方案能复用的空闲资源并不相同:
| 方案 | 空闲出现在哪里 | 需要验证什么 |
|---|---|---|
| HAMi共享 | 已分配GPU内尚未用满的显存、算力,以及任务高峰错开的时间空隙 | 更多任务同卡后,单位GPU完成的请求量能否提高,业务延迟能否守住 |
| Dynamic MIG | 未预切的卡内空间,或MIG实例回收后腾出的位置 | 是否存在合法Placement,不同规格请求的等待时间是否缩短 |
| Agent休眠 | Sandbox等待期间仍占用的CPU和Memory | 资源回收后,能否重新获得资源并恢复会话所需的状态 |
| FMA | 模型暂时没有请求,requesting Pod仍持有GPU分配 | 模型休眠、requesting Pod释放后,GPU能否交给其他实例,原模型恢复要多久 |
HAMi让任务共享卡内显存和算力,算力超卖还依赖计算高峰错开。Dynamic MIG按请求创建硬件实例,但能否创建仍受Profile和Placement限制。Agent休眠回收等待期间的CPU和Memory;FMA保留vLLM进程与CPU中的权重,并在模型休眠后删除requesting Pod,归还GPU申请。
评估效果时,先看空出的资源有没有被其他任务使用,再看原任务返回时能否重新取得资源并满足延迟目标。同卡共享还要计入性能干扰。某一刻的空闲GPU数量看不到Agent回收的CPU和Memory,也无法反映模型切换的恢复成本。
参考资料
- How Intsig Serves Billions of Document Scans: GPU Virtualization at Scale with HAMi
- Dynamic MIG with HAMi: From Static Slices to Elastic GPUs
- NVIDIA Multi-Instance GPU User Guide: Concepts
- Hibernate and Evolving: Taming OpenClaw with OpenKruise Agents
- OpenKruise Agents: Automatic Pause and Resume
- Can Stateful AI Agents Scale to Zero?
- vLLM Sleep Mode
- llm-d Fast Model Actuation
- llm-d FMA: Dual Pods Design