一作论文
📄 论文原文:ICDCS 2026 — Maestro PDF
问题背景
传统 LLM 推理面对的是独立的一问一答请求。但现在越来越多的应用把多个 agent 组成协作工作流:比如旅行助手里有"需求分析 agent"、"机票搜索 agent"、"酒店推荐 agent"、"行程整合 agent",它们之间有 DAG 依赖,一个用户请求触发十几次甚至几十次 LLM 推理调用(称为 stage)。
这带来了三个新挑战:
- 输出长度剧烈波动:工具调用输出几十 token(JSON),用户交互输出几百上千 token。KV 缓存需求差异巨大,固定分配要么浪费要么 OOM。
- 多模型共存的内存压力:不同 agent 使用不同模型,一块 GPU 需要同时驻留多个模型权重加上所有请求的 KV 缓存。
- 混合延迟要求:交互式 stage 要低延迟,批处理 stage 要高吞吐。不区分优先级就会造成队头阻塞。
系统设计
核心思路:不把 LLM 请求当黑盒,利用 agent 上下文做前瞻性预测,指导内存管理和调度。
为什么需要预测输出长度?
LLM 推理的输出长度直接决定两件事:KV Cache 大小(每多输出一个 token,KV cache 就多存一组 key/value 向量)和decode 耗时(每步 decode 读 KV cache + 矩阵乘,token 越多耗时越长)。而在 LLM-MAS 场景下,不同 agent 的输出长度差异巨大——工具调用几十 token(JSON),用户交互几百上千 token。如果在请求开始前不预测,就无法做资源规划(给多少 KV 显存)和调度排序(谁先谁后),要么浪费要么 OOM。
预测流水线:两个 GBDT 模型串联,BERT 负责提取语义特征
prompt 文本
│
┌───────────┴───────────┐
▼ ▼
MiniLM 编码 结构化特征提取
(轻量 BERT, 33M) (role / 工作流位置 /
384 维向量 调用索引 / 工具可用性)
│ │
▼ │
PCA 降维 384→32 维 │
(保留 ~85% 方差) │
│ │
└───────────┬───────────┘
│
▼
┌──────────────────────┐
│ 第一阶段:LightGBM │ 二分类:会触发工具调用吗?
│ 分类器 │ AUC = 0.9625
│ (GBDT) │ 输出连续概率 p̂_tool
└──────────┬───────────┘
│ p̂_tool(经 isotonic regression 校准)
▼
┌──────────────────────┐
│ 第二阶段:LightGBM │ 回归:输出多少 token?
│ 回归器 │ MAE = 165, R² = 0.78
│ (GBDT) │ 对 log(1+L) 建模
└──────────┬───────────┘
│
▼
预测 token 数
这里有一个容易被误解的地方:论文图 6 中 BERT/MiniLM 紧邻着 "Classification" 画线,但它不是分类器本身,而是语义特征提取器。MiniLM 把 prompt 文本编码为 384 维向量 → PCA 降到 32 维 → 作为特征之一喂入 LightGBM 分类器。真正的分类决策是 LightGBM(GBDT)做的,和第二阶段回归器用的是同一种算法。
第一阶段分类器输出的是连续概率 p̂_tool(经 isotonic regression 校准),而非 0/1 离散值。这个概率作为第二阶段回归器的输入特征之一,让回归器知道"当前 stage 有多大概率是工具调用模式"。
特征工程
结构化特征(表格特征,直接可用):
- agent 角色:当前 stage 是搜索/推荐/整合/... agent,one-hot 编码
- 工作流位置:节点在图中的入度、出度、深度,反映该 stage 在 DAG 中的位置和依赖关系
- 调用索引:当前 stage 在工作流中是第几个被调用的——靠前的 stage 通常输出较短(中间步骤),靠后的 stage 输出较长(汇总结果)
- 工具可用性:该 agent 挂了多少工具、工具类型——工具多的 agent 更可能触发工具调用(短输出),纯文本 agent 更可能生成长输出
语义特征(prompt 文本 → 向量 → 降维):
- 编码:用 MiniLM(微软的轻量 transformer,约 33M 参数)将 prompt 文本编码为 384 维向量
- 降维:PCA 从 384 维 → 32 维,保留约 85% 方差
降维有两个目的:384 维对 LightGBM 来说维度过高容易过拟合(训练集 4 万条样本,特征维度太高模型会记样本而非学模式),以及语义编码中部分维度是噪声(MiniLM 在通用文本上预训练,LLM agent prompt 的某些语义差异对输出长度预测无用)。消融实验:去掉语义特征,AUC 从 0.9625 降到约 0.93,证明语义信息确实提供了结构化特征无法捕捉的信号——同一个 agent 角色同一个工作流位置,不同的 prompt 内容会导致不同的输出长度。
训练技巧
1. Log 变换处理长尾分布:输出 token 数不是正态分布——绝大部分请求 50-500 token,偶尔有 2000+ 的极端值。直接回归 MSE 会被极端值主导。做法是回归器在 log 空间学习 y' = ln(1+y),推理时 exp 反变换。
2. Isotonic Regression 校准:LightGBM 输出的概率 p̂_tool 不一定校准良好(预测 0.7 不代表 70% 概率真的触发工具调用)。Isotonic regression 用保序回归在验证集上拟合一条校准曲线,让概率值对齐真实频率。校准后的概率作为回归器特征更可靠。
3. 非对称 Loss 偏向高估:回归器 loss 对低估的惩罚 > 高估的惩罚。低估 → KV 分配不够 → OOM → 请求被杀(灾难性后果);高估 → 暂时多占一点显存 → 后续可回收(可接受代价)。配合安全裕度 ρ ∈ [0.1, 0.3],实际 KV 分配 = 预测值 × (1+ρ)。
为什么必须两阶段?一阶段直接回归为什么不行?
输出长度呈双峰分布:工具调用集中在几十 token(窄峰),用户交互分散在几百到上千 token(宽峰)。单一回归器面对双峰数据只能取折中——预测值落在两峰之间,对哪个峰都不准。
两阶段的核心思路是"先识别模式,再在模式内预测":分类器先判断"这个请求属于工具调用模式还是用户交互模式",回归器在给定模式约束下做精确预测。消融实验证明:去掉分类器头,MAE 从 134 上升到 142(越高越差),验证了"先分后回归"的价值。
预测信号如何驱动下游组件
| 组件 | 消费方式 | 为什么这样用 |
|---|---|---|
| KV 显存分配 | 预测值 × (1+ρ) → 初始物理页映射量 | decode 过程按需追加映射页,不是一次性分配完;预测短则初始少映射,后续不够再追加 |
| SRTF 调度 | 预测 token 数 ÷ 解码速度 → 剩余执行时间 → 排队优先级 | 短作业先跑减少队头阻塞;交互式 stage 排批处理前面;纯预测(不依赖已执行时间)让新到达的短 stage 可以插队 |
| 准入控制 | 检查剩余物理显存 ≥ 预测 KV 需求 | 不够则拒绝该 stage,避免 OOM 连锁反应;配合安全裕度保证高估侧有缓冲 |
三者之间有安全裕度 ρ 做缓冲——预测不可能 100% 准确(R²=0.78),偏高一侧留出余地,配合动态扩容和优雅降级,实际 OOM 率压到 0.1% 以下。
模型状态管理:五种状态按层级流转——
- Running:权重在 GPU,可立即执行推理
- Sleeping:权重移到 CPU,但 GPU 上保留 CUDA Graph 和 JIT 内核缓存(约 0.5GB),重新激活省 5-8 秒
- CPU-resident:权重完全在 CPU 内存
- Disk-resident:权重在本地 NVMe
- Remote:权重在远程存储
层级化 LRU 逐级淘汰,最热的模型留 GPU,最冷的逐步退到远端。
KV 缓存管理:CUDA VMM 虚拟内存超配——40GB 物理 GPU 上分配 122GB 虚拟地址池(3 倍超配)。关键在于虚拟地址和物理页分离,按需映射物理页。三层防护:(1) 虚拟 vs 物理分离,不会同时达峰;(2) 准入控制——每个 stage 检查剩余物理页是否够;(3) 映射失败时拒绝 stage 而非崩溃。五级降级策略保证极端情况也不会 OOM。
内存核算:M_kv + M_res ≤ M_total,安全裕度 ρ ∈ [0.1, 0.3],偏向高估以避免低估导致 OOM。
基于预测的剩余执行时间排队(SRTF),优先执行快要完成的工作流。交互式和批处理 stage 分开排队。Stage 边界抢占——只在两次 LLM 调用之间切换,不打断正在解码的请求。
节点选择:适应度评分 S(N,T) = A(N,T) − λ·T_ready − μ·C_deg,综合模型就绪延迟和降级代价。
核心结果
Maestro 高频问答
低估远比高估危害大:(1) KV 缓存方面,低估导致预分配不够,解码到一半 OOM,请求被杀;高估只是暂时多占。(2) SRTF 调度方面,低估剩余时间导致长作业排到队首,造成队头阻塞;高估则长作业排后面,影响较小。所以设计安全裕度 ρ 偏向高估。
三层防护:(1) 122GB 是虚拟地址空间,物理页按需映射,不会同时分配满;(2) 每个 stage 进来先做准入控制,检查剩余物理页是否够预测需求;(3) cuMemMap 返回失败时拒绝该 stage 而非崩溃。多 agent 的 KV 使用弹性大,统计上不会同时达峰,类似内存超卖的思路。
四层存储:GPU → CPU → Disk → Remote。五种状态多出一个 Sleeping——权重在 CPU,但 GPU 上保留 CUDA Graph 和 JIT 内核缓存(约 0.5GB),重新激活省 5-8 秒。Sleeping 横跨 GPU 和 CPU 两层。设计原因:模型切换频繁时,CUDA Graph 的重建开销可观。
Token 级抢占需要和解码引擎深度集成,还要做 KV 缓存迁移,工程复杂度极高。Stage 边界抢占只需更新元数据,实测效果已足够:交互排队从 11 秒降到 2 毫秒。超长解码阶段可作为 future work。
三级回退:(1) per-role 数据不足时回退到全局模型;(2) 结构化特征(工作流位置、工具可用性)本身就有信号;(3) post-execution profiling 增量更新,几轮执行后适应新角色。
S(N,T) = A(N,T) − λ·T_ready − μ·C_deg。默认 λ = μ = 1(毫秒量级)。交互式 stage 增大网络延迟权重。用 robust min-max 归一化(5/95 分位数裁剪),防止异常值主导。验证集上选定后跨负载固定。
比如一个旅行助手 Agent:用户说"帮我规划去东京的行程",系统会依次调用:需求分析 Agent(解析意图)→ 机票搜索 Agent(调工具查航班)→ 酒店推荐 Agent(查酒店)→ 行程整合 Agent(汇总输出)。每个 Agent 背后是一次 LLM 推理调用(称为 stage),一个用户请求可能触发十几次甚至几十次 LLM 调用。这些 stage 之间有 DAG 依赖关系,不同 Agent 可能使用不同模型,输出长度差异巨大——工具调用返回几十 token 的 JSON,用户交互输出几百上千 token。
LLM 推理的输出长度变化极大:工具调用输出几十 token(JSON 格式),用户交互输出几百上千 token。输出长度直接决定 KV Cache 大小和 decode 时长。固定按最大长度预留→显存严重浪费(利用率极低);按平均长度预留→一旦超了就 OOM。核心难点是必须在请求开始前就预测输出长度来分配资源,但这个预测天然不准。Maestro 的做法是:预测 + 安全裕度(偏向高估)+ 动态扩容(decode 过程中按需追加物理页)+ 优雅降级(真不够时抢占低优先级 stage),而不是依赖完美的预测。
注意区分两个角色:语义特征提取用的是 MiniLM(本身就是 BERT 系的 DL 模型),但分类和回归的决策模型用的是 LightGBM。这样设计的原因:(1) 推理延迟:语义编码只需要做一次 MiniLM 前向(离线也可预计算),但分类/回归在每次调度决策时都要跑。LightGBM 单次推理 < 1ms,DL 分类器(如 MLP/Transformer)需要 10-100ms,在调度关键路径上不可接受;(2) 数据形态:LightGBM 的输入是结构化特征 + 已降维的 32 维语义特征,属于典型的表格数据。GBDT 在这种异构特征上通常优于或持平 DL,且不需要大量调参;(3) 可解释性:LightGBM 直接输出特征重要性,方便分析"agent 角色 vs 工作流位置 vs 语义特征"各自对预测的贡献。论文实验中对比了 MLP(单阶段)、dual-tower Transformer 融合模型等 DL baseline,LightGBM 在 AUC 和延迟上综合最优。
分为两大类:结构化特征包括——agent 角色(one-hot 编码,如"搜索 agent"/"推荐 agent"/"整合 agent")、工作流图中的位置(入度/出度/深度)、当前 stage 在所属工作流中的调用索引(第几个被调用的)、工具可用性(该 agent 可调用的工具数量和类型)。语义特征:用 MiniLM(一个小型 transformer 模型,参数量约 33M)对 prompt 文本做编码,得到 384 维向量,再通过 PCA 降到 32 维(保留约 85% 方差)。PCA 降维有两个目的——减少特征维度避免过拟合,以及去掉语义编码中的噪声分量。消融实验显示:去掉语义特征 AUC 从 0.9625 降到约 0.93,证明语义信息确实提供了结构化特征无法捕捉的信号。
这是所有预测驱动系统都要面对的核心问题,Maestro 做了三层防护:(1) 偏向高估——训练时对低估加更大惩罚(非对称 loss),让预测值倾向偏高。低估导致 OOM(请求直接被杀)的代价远大于高估(暂时浪费显存),设计安全裕度 ρ ∈ [0.1, 0.3];(2) 动态扩容——KV 内存在 decode 过程中按页增长(类似 PagedAttention 的思路),不是一次性分配完。如果实际输出超过预测,运行时可以追加映射物理页(只要物理显存池还有剩余);(3) 优雅降级——如果物理内存真的耗尽(极端情况),选择抢占/暂停优先级最低的 stage 释放空间,而不是让整个服务崩溃。配合这三层防护,预测准确率 R²=0.78 看起来不高,但实际 OOM 率 < 0.1%。
这个问题需要分清两个层面:(1) 预留(reservation)≠ 实际使用。传统方案为每个请求预分配最大 KV 物理空间,即使实际输出很短也占着不放——这是真正的物理显存浪费。CUDA VMM 让虚拟地址远大于物理显存,但物理页按需映射,真正减少的是物理 HBM 占用;(2) 67.2% 降低的是预留的 HBM 物理显存,不是虚拟地址空间。通过输出长度预测来决定实际映射多少物理页——短请求只映射少量物理页,长请求映射更多,而不是所有人都按最坏情况分配。统计复用的前提是多 Agent 的 KV 峰值不重叠(某个 agent 在输出长文本时,其他 agent 可能正在工具调用或空闲),如果所有请求同时输出长文本确实还会 OOM,但实际 trace 中这种概率极低,且有准入控制兜底。
不只对比了 EDF。Maestro 的实验对比了 EDF、SRTF(无预测版本,纯按已执行时间排序)、FCFS(先到先服务)、Karma(LLM 推理服务最近的调度工作)。关键在于 Maestro 的核心贡献不是调度算法本身(SRTF 是经典算法),而是把预测信号引入 LLM-MAS 场景并设计了弹性显存机制来利用这些预测。实验设计的目的:EDF → 证明传统实时调度在 LLM-MAS 场景下失效(无法区分长短 stage);SRTF(无预测)→ 证明纯 SRTF 因为不知道剩余时间只能按已执行时间估计,在双峰分布下偏差大;Maestro → 证明预测信号能显著提升 SRTF 的效果。对比不是为了证明"我的排序算法更好",而是证明"预测信号有价值"。
这是不同层面的优化,两者是互补而非替代关系:vLLM/TGI 优化的是单节点内推理引擎的 batching 和 KV 管理(PagedAttention 解决内部碎片、continuous batching 提高单模型 GPU 利用率)。Maestro 解决的是多节点、多模型、多 Agent 工作流层面的调度问题——一个用户请求涉及十几个 Agent stage、用多个不同模型、分布在多块 GPU 上,需要全局视角决定"哪个 stage 放哪块 GPU、哪个模型该常驻、KV 显存怎么跨请求复用"。Maestro 可以和 vLLM 配合使用:节点内用 vLLM 做推理引擎优化(PagedAttention、continuous batching),节点间用 Maestro 做全局调度和显存管理。事实上我们的原型实现就是基于 vLLM 做的,分级权重缓存和 CUDA VMM 超配是在 vLLM 之上的额外优化。
问题背景
多团队共享 GPU 集群的核心矛盾:
- 配额闲置:某个团队暂时没有训练任务时 GPU 空转浪费,实测集群平均利用率只有 40%。
- 配额不够:另一个团队赶 deadline 想多用几块卡,却因超配额被拒。
固定配额简单但浪费严重,完全共享利用率高但无法保障 SLA。问题本质:在保障每个租户配额的前提下,把闲置资源借给需要的人,原主需要时及时收回。
额外问题:即使 GPU 被分配出去了,很多训练任务在 I/O 或 CPU 预处理阶段 GPU 是空闲的。两个任务合用同一块 GPU 可以提升利用率,但会互相干扰——抢占 SM 和显存带宽,搞不好两个任务都变慢。
系统设计
统一控制信号——配额保障度 QAD,同时驱动三个子系统:
| 部分 | 含义 | 记忆 |
|---|---|---|
分子 A_i^G(t) | 已经分配给租户的 Guaranteed GPU | 已经兑现多少 |
分母 min(q_i,D_i^G(t)) | quota 与当前 Guaranteed demand 取小 | 此刻应该兑现多少 |
比值 Q_i(t) | 当前保障兑现率 | 已给 / 该给 |
边界:没有 Guaranteed demand 时 Q_i(t)=1;Best-effort 借用不计入分子,所以 QAD 位于 [0,1],不会因为借卡大于 1。完整数字例子见“QAD 记忆模型”。
空闲 GPU 可被其他租户借走跑低优先级任务。原主提交新任务导致 QAD 下降时,按 QAD 优先级回收——最欠缺的租户最先被满足。和固定配额的区别:闲置资源不浪费,但需要时保证能收回。
Per-tenant gradient boosting regressor 预测作业剩余运行时间(MAPE 31.84%,R² = 0.7286)。调度排序采用词典序:
先按 QAD 升序(优先欠缺的租户),再按预测运行时间升序(短作业优先)。
抢占牺牲者选择:代价基抢占效率
综合释放资源量 \(R_j\)、剩余时间 \(\hat{T}(j)\) 和抢占代价 \(C_p(j)\)(已完成进度的浪费 + checkpoint 保存时间)。
Random Forest 预测两个任务共享同一块 GPU 时的性能保持率(R² = 0.902)。特征来自硬件计数器(SM activity、memory bandwidth),而非模型架构,保证跨框架泛化。只有预测保持率高于动态容忍阈值时才允许合用。运行时持续监控,实际性能下降超过容忍度时立即驱逐低优先级伙伴。
整个系统实现为 Kubernetes scheduler plugin,覆盖 Filter → Score → Reserve → PostFilter → Permit 五个扩展点,端到端调度延迟 < 50ms。
核心结果
核心定位
DeepShare 的 Kubernetes 实现拆成轻量 Controller 与实时 Scheduler Plugin 两层:
- Controller:把
TenantQuotaCRD 和作业 class annotation 整理为租户 quota 元数据。 - Scheduler Plugin:维护瞬时/平滑 QAD 和队列,执行排序、放置、colocation 准入与抢占。
面试Controller 管静态权益元数据,Scheduler Plugin 管实时 QAD 控制环。
论文不覆盖 Gang Scheduling,因此不引入 PodGroup / minAvailable;但 Permit 仍用于等待 CPU/Memory in-place resize 生效,不要把两种用途混在一起。
5-10 分钟中文论文讲解稿
这版适合面试时完整介绍,目标是让面试官听完后清楚知道:
- 这篇论文解决什么问题;
- 为什么这个问题重要;
- DeepShare 的核心思想是什么;
- QAD 是什么;
- DRA、预测调度、colocation 分别做什么;
- Kubernetes 实现大概怎么落地;
- 实验效果说明了什么。
你可以按这个版本背,也可以根据面试时间压缩。
开场:论文定位
我介绍的这篇论文是 DeepShare: Assurance-Driven Resource Management for Multi-Tenant GPU Clusters。它主要研究的是 多租户 GPU 集群中的资源管理问题。
简单来说,这篇论文想解决的问题是:
在多个团队共享一批 GPU 的情况下,如何既保证每个租户的 quota 和 QoS,又尽可能提高 GPU 利用率、降低作业排队时间。
1. 背景和问题
现在很多 AI 平台或者云平台都会有多租户 GPU 集群。比如不同团队、不同项目共用一批 GPU。为了公平,平台通常会给每个租户分配一个 quota,比如 A 团队 32 张 GPU,B 团队 16 张 GPU。
但是实际使用中会有一个矛盾。
如果我们严格按照 quota 静态隔离资源,那么就会出现资源浪费。比如 B 团队当前没有任务,它的 16 张 GPU quota 是空闲的,但 A 团队有很多任务在排队。如果系统不允许 A 使用 B 暂时空闲的 GPU,那么集群整体利用率就会下降。
反过来,如果系统允许 A 临时借用 B 的 GPU,又会出现另一个问题:当 B 后面提交了 Guaranteed 作业,需要拿回自己的 quota 时,资源可能已经被 A 的作业占住了。如果系统不能及时回收资源,就会破坏 B 的 QoS。
所以这里的核心矛盾是:
静态 quota 会降低利用率,过度共享又会破坏 QoS。
论文认为,现有系统的问题不只是某一个调度策略不好,而是 quota 管理、作业调度、抢占回收和 GPU 共享之间缺少一个统一的控制信号。
比如:
- 调度器可能只看作业优先级;
- quota 模块只看租户有没有超过 quota;
- 抢占模块只看哪个作业优先级低;
- colocation 模块只看 GPU 是否空闲或者干扰是否低。
这些模块如果各自决策,就很难同时保证 QoS 和利用率。
2. DeepShare 的核心思想
DeepShare 的核心思想是引入一个统一指标,叫 QAD,Quota Assurance Degree,也就是 配额保障程度。
它用来衡量:
一个租户当前 Guaranteed 资源需求中,有多少已经被满足。
也就是说,QAD 不是简单看一个租户用了多少 GPU,而是看它 应该被保障的资源有没有被保障到。
论文中 QAD 的作用是连接三个关键模块:
- Elastic Quota Regulation,也就是弹性 quota 调节 / DRA;
- Predictive Scheduling,也就是基于预测的调度;
- Interference-Aware Colocation,也就是干扰感知的 GPU 共享。
这三个模块都围绕 QAD 来做决策。
可以简单理解为:
QAD 低,说明租户保障不足,系统应该优先恢复它的 Guaranteed 作业;QAD 高,说明租户保障充分,系统可以更积极地允许资源借用和 GPU 共享。
3. QAD 是什么?
QAD 的直观定义是:
QAD = 已经兑现的 Guaranteed GPU / 当前应该兑现的 Guaranteed GPU
更具体一点,瞬时 QAD 可以理解为:
如果租户当前没有 Guaranteed demand:
QAD = 1
否则:
QAD = 当前已分配的 Guaranteed GPU / min(租户 quota, 当前 Guaranteed demand)
这里分母用 min(quota, demand) 很关键。
举个例子,一个租户 quota 是 32 张 GPU。
如果它当前只需要 8 张 GPU,那么系统只需要保障它 8 张。只要它拿到 8 张,QAD 就是 1,而不是 8/32。
如果它当前提交了 100 张 GPU 的需求,但 quota 只有 32,那么系统只承诺保障 32 张,不会因为它提交了 100 张就认为系统欠它 100 张。
所以 QAD 避免了两个问题:
- 租户不能通过提交超大 demand 来放大资源缺口;
- 租户当前需求小于 quota 时,也不会因为没用满 quota 而被错误认为保障不足。
论文还对 QAD 做了平滑处理,因为瞬时 QAD 会因为短任务完成、突发任务到来、资源释放等事件频繁波动。
平滑公式是:
Q̃_i(t) = λ Q_i(t) + (1 - λ) Q̃_i(t - 1)
默认 λ = 0.3。
也就是说:
当前平滑 QAD = 30% 当前瞬时 QAD + 70% 上一轮平滑 QAD
这样系统不会因为短期波动频繁重排队列或者抢占 Best-effort 作业,但如果一个租户持续保障不足,平滑 QAD 仍然会逐步下降,从而提高它的恢复优先级。
不要混:Q_i(t) 是瞬时观测,真正进入排序和 colocation 控制的是 EMA 平滑后的 Q̃_i(t)。
4. 模块一:Elastic Quota Regulation / DRA
第一个模块是 DRA,弹性 quota 调节。
它解决的是:
怎么允许租户借用别人暂时不用的资源,同时保证这些资源之后能被回收。
DeepShare 把作业分成两类:
Guaranteed 作业
Best-effort 作业
Guaranteed 作业是 quota 内应该被保障的作业。它们会计入租户的 quota,并且在调度时优先级更高。
Best-effort 作业是机会型作业。它们可以使用集群中暂时空闲的 GPU,或者其他租户当前没有用到的 surplus capacity,但它们是可回收的。
这里的关键是:
Best-effort 可以借资源,但不能破坏 Guaranteed QoS。
当某个租户 Guaranteed 需求回来,导致它的 QAD 降低时,系统会优先回收 Best-effort 作业占用的资源。
所以 DRA 的核心逻辑是:
有空闲资源时,提高利用率;
Guaranteed 保障不足时,回收借出去的资源。
这就是 DeepShare 同时提升利用率和保证 QoS 的基础。
5. 模块二:Predictive Scheduling
第二个模块是 预测调度。
论文正文使用 per-tenant gradient boosting regressor 预测作业剩余运行时间。这个预测信息主要有两个用途。
第一个用途是 队列排序。
DeepShare 的排序不是简单 FIFO,也不是单纯短任务优先,而是:
Guaranteed 优先于 Best-effort;
同一类作业里,平滑 QAD 低的租户优先;
QAD 接近时,预测运行时间短的作业优先。
也就是:
先恢复保障不足的租户,再用短任务优先降低平均排队时间。
这点很重要。预测运行时间只是第二排序键,它不能覆盖 QAD。也就是说,一个已经保障充分的租户,不能仅仅因为它的作业更短,就排到一个保障不足的租户前面。
第二个用途是 抢占代价估计。
如果需要回收 Best-effort 资源,系统不应该随便杀任务,而要考虑:
- 这个任务已经运行了多久;
- 剩余运行时间大概多长;
- 是否有 checkpoint;
- 重启成本多高;
- 抢占它能不能真正释放足够 GPU;
- 抢占后能不能提升低 QAD 租户的保障程度。
所以这里是一个 cost-aware preemption,而不是简单 priority-based preemption。
6. 模块三:Interference-Aware Colocation
第三个模块是 干扰感知的 GPU colocation。
它解决的是:
很多 GPU 作业并不能一直打满一张 GPU,如果让它们完全独占 GPU,会造成利用率浪费;但如果随便共享,又可能互相干扰,破坏 QoS。
GPU 共享的干扰来源很多,比如:
- 显存容量;
- 显存带宽;
- SM 算力;
- L2 cache;
- PCIe / NVLink;
- CPU dataloader;
- 网络通信。
所以 DeepShare 不只是看 GPU 有没有空,而是预测两个作业放在一起会不会产生过大 slowdown。
论文中提到使用 random forest 模型预测 colocation 干扰。如果预测干扰低于阈值,才允许 colocation。
而且这个阈值不是固定的,会受到 QAD 影响。
如果某个租户 QAD 很低,说明它的 Guaranteed 资源已经保障不足,那系统会更保守,避免它的作业受到共享干扰。
如果租户 QAD 较高,说明保障比较充分,系统可以更激进地允许 colocation,提高 GPU 利用率。
所以 colocation admission 是:
干扰感知 + QAD 感知
而不是单纯基于利用率。
7. Kubernetes 实现怎么落地?
论文说 DeepShare 是 Kubernetes-native,也就是它不是重新造一个集群系统,而是集成到 Kubernetes 生态里。
论文实现拆成:
Controller + Scheduler Plugin
轻量 Controller 负责配置态:
- reconcile
TenantQuotaCRD; - 读取 Guaranteed / Best-effort class annotation;
- 生成 per-tenant quota metadata。
Scheduler Plugin 负责实时控制环:
- 在内存中维护瞬时/平滑 QAD 和两级队列排序;
- Filter:检查节点 GPU 是否足够、是否允许 colocation;
- Score:使用 RF 干扰预测和动态 retention 门槛选择位置;
- Reserve:更新下一周期 GPU claim,避免 double booking;
- PostFilter:当 Guaranteed 作业调度失败时,选择低代价 Best-effort 作业进行抢占。
- Permit:等待 CPU/Memory in-place resize 反映到 Pod 状态。
这里有一个关键点:
Controller 管配置态,Scheduler Plugin 管 QAD 和所有实时放置决策;QAD 可从 informer cache 中的运行 Pod 重建,不需要每轮写回 CRD。
8. 实验结果
论文做了两类实验。
第一类是 trace-driven simulation,基于 23,859 个作业的 trace。
结果显示:
- 平均 GPU 利用率达到 70.58%;
- 比 Lucid 高 29.5%;
- 排队延迟降低 46%;
- per-tenant QoS compliance 达到 93%。
第二类是在 16-GPU Kubernetes 集群上的部署实验。
结果显示:
- Job Completion Time 降低 34%;
- 吞吐和资源利用都有明显提升;
- 说明系统不只是模拟有效,在 Kubernetes 原型上也有实际效果。
论文还做了 ablation study。
比如:
- DRA 能降低排队延迟;
- predictive scheduling 能进一步优化调度顺序;
- interference-aware colocation 对降低排队延迟也有明显贡献;
- DRA 和 colocation 结合后效果更好。
这说明 DeepShare 的收益不是来自单个技巧,而是来自:
QAD 统一控制下,资源借用、预测调度和干扰感知共享的协同。
9. 论文贡献总结
我理解这篇论文的核心贡献有三个。
第一,提出了 QAD 这个连续的租户保障指标。它不是简单 quota,也不是简单资源使用率,而是衡量租户当前 Guaranteed 需求被满足的程度。
第二,用 QAD 把多个原本分散的资源管理决策统一起来,包括 quota 借用和回收、队列排序、抢占、colocation admission 和 QoS reporting。
第三,做了一个 Kubernetes-native 的资源管理系统,把 DRA、预测调度和干扰感知 colocation 结合起来,在保证 tenant QoS 的同时提高 GPU 利用率。
DeepShare 的核心机制可以概括为:
DeepShare 不是单纯追求更高 GPU 利用率,也不是单纯做静态 quota 隔离,而是用 QAD 这个统一指标,在多租户 GPU 集群里动态平衡 QoS 保障和资源效率。
10. 面试时的收尾版本
我认为这篇论文最有价值的地方在于,它抓住了多租户 GPU 集群里的核心矛盾:资源空闲时希望共享,提高利用率;资源紧张时又必须恢复租户 quota 保障。DeepShare 用 QAD 把这个矛盾形式化,然后用 DRA 解决资源借用和回收,用预测调度降低排队和抢占成本,用干扰感知 colocation 提高共享效率,同时通过 Kubernetes Scheduler Framework 落地。
所以这篇论文的核心不是某一个单点调度算法,而是一个围绕租户资源保障的统一资源管理框架。
先把完整公式记对
| 符号 | 含义 | 记忆问题 |
|---|---|---|
i | 第 i 个租户 | 在看谁? |
q_i | 平台承诺给租户的 Guaranteed GPU quota | 最多承诺多少? |
D_i^G(t) | 时刻 t 租户当前提出的 Guaranteed GPU 需求 | 现在想要多少? |
A_i^G(t) | 时刻 t 已经分配并运行的 Guaranteed GPU | 现在实际兑现多少? |
min(q_i, D_i^G(t)) | 平台此刻真正应该保障的 GPU 数 | 现在该兑现多少? |
A_i^G(t):已经给到的 Guaranteed GPU;分母 min(q_i,D_i^G(t)):当前应该给到的 Guaranteed GPU;两者相除就是保障兑现率。为什么分母一定是 min(quota, demand)
分母不是 quota,也不是 demand,而是“当前应保障量”
- 当
demand < quota:租户只申请了 4 张,即使 quota 是 8,平台此刻也只欠它 4 张;分母取 demand。 - 当
demand > quota:租户申请了 12 张,但平台只承诺 8 张;分母取 quota。 - 因此租户既不会因为暂时没用满 quota 被判定为“受损”,也不能靠提交超大需求压低 QAD、抬高恢复优先级。
记忆口令:想要多少 D、承诺多少 q,二者取小才是系统此刻“该给多少”。
用一个数字例子把边界钉死
假设租户 A 的 quota 为 q_A = 8 张 GPU:
| 场景 | D_A^G | A_A^G | 分母 | QAD | 含义 |
|---|---|---|---|---|---|
| 暂时没有 Guaranteed 作业 | 0 | 0 | 特殊分支 | 1 | 没有未兑现的保障,不算欠它 |
| 只需要 4 张,目前给了 2 张 | 4 | 2 | min(8,4)=4 | 0.5 | 当前保障只兑现了一半 |
| 只需要 4 张,目前给满 4 张 | 4 | 4 | min(8,4)=4 | 1 | 当前需求已完全保障 |
| 需要 12 张,目前给了 4 张 | 12 | 4 | min(8,12)=8 | 0.5 | 承诺的 8 张只兑现了一半 |
| Guaranteed 给满 8 张,另有 4 张 Best-effort | 12 | 8 | min(8,12)=8 | 1 | 借来的 4 张不进入分子,QAD 不是 1.5 |
最容易答错的边界
论文中的 A_i^G(t) 只统计 Guaranteed allocation;Best-effort allocation 不进入分子,因此不会把 QAD “冲高”。在 DeepShare 的定义和准入约束下,Q_i(t) ∈ [0,1]:1 表示应兑现的保障已经满足,低于 1 才表示存在 deficit。
瞬时 QAD 和调度用 QAD 不要混
一个看快照,一个做控制
| 量 | 回答的问题 | 用途 |
|---|---|---|
Q_i(t) | 这一时刻保障兑现了多少? | 瞬时观测值 |
Q̃_i(t) | 这个租户是否持续处于保障不足? | 队列排序、回收优先级、colocation 收紧 |
EMA 是为了过滤短作业完成和突发到达造成的亚秒级抖动。论文设置 50ms 调度周期和 λ=0.3,持续 deficit 大约 350ms 就能体现 90% 的稳态影响。
QAD 怎么驱动 DeepShare
QAD 是租户级的配额保障兑现率。分子 A_i^G(t) 是当前已经分配的 Guaranteed GPU,分母 min(q_i,D_i^G(t)) 是平台此刻真正应该保障的 GPU 数:需求小于 quota 时只保障实际需求,需求超过 quota 时最多保障 quota。如果当前没有 Guaranteed demand,就把 QAD 定义为 1,因为没有未兑现的权益。Best-effort 借用不计入分子,所以 QAD 落在 0 到 1。系统再对瞬时 QAD 做 EMA 平滑,用平滑值优先恢复欠保障租户,并收紧它们的 GPU 共享。
因为租户当前可能只需要 quota 的一小部分。若 quota 是 8、需求只有 4、实际已给 4,用 allocation/quota 会得到 0.5,错误地认为租户受损;DeepShare 用 min(quota, demand) 后得到 1,表示当前需求已完全兑现。
常见误区
| 错误记法 | 正确理解 |
|---|---|
| QAD = 总 GPU 使用量 / quota | 分子只算 Guaranteed allocation,不算 Best-effort |
| 分母永远是 quota | 分母是 min(quota, 当前 Guaranteed demand) |
| 没有需求时 QAD = 0 | 没有未兑现保障,论文显式定义为 1 |
| 借到额外资源后 QAD > 1 | 借用量不进入分子,QAD 保持在 0 到 1 |
| 运行时间短的作业永远优先 | 先按平滑 QAD 恢复欠保障租户,再用预测时间优化局部顺序 |
总体架构
三类组件分别管什么
| 组件 | 核心状态 | 关键职责 | 不负责什么 |
|---|---|---|---|
| Quota Controller | TenantQuota、作业 class annotation | reconcile 租户 quota 与 Best-effort cap 元数据 | 不做节点放置,不维护实时 QAD |
| Scheduler Plugin | 队列、瞬时/平滑 QAD、节点视图、预测结果 | 排序、Filter、Score、Reserve、PostFilter、Permit | 不负责 MPS 进程和 DCGM 采样 |
| Node-local DaemonSet | MPS client、DCGM counters、degraded pair | GPU 共享、干扰监控、异常上下文清理 | 不决定租户优先级 |
QAD 在哪里维护
QAD 是 Scheduler Plugin 的内存状态
Scheduler Plugin 从 informer cache 里的运行 Pod 推导 A_i^G(t)、D_i^G(t) 和 quota 元数据,计算瞬时 Q_i(t),再维护 EMA 平滑值 Q̃_i(t)。这样排序、colocation 和抢占看到的是同一份实时状态。
论文没有把每一轮 QAD 写进 TenantQuota.status。发生 leader failover 后,新 leader 可以从运行 Pod 重建瞬时 QAD,并用首轮值 warm-start EMA,避免额外持久化和热路径写放大。
Kubernetes 对象如何表达
TenantQuota CRD:保存权益配置,不保存实时控制环
apiVersion: deepshare.io/v1
kind: TenantQuota
metadata:
name: team-a
spec:
gpuQuota: 8
bestEffortMultiplier: 2
gpuQuota对应q_i,即 Guaranteed GPU quota。bestEffortMultiplier对应η,限制机会型作业的借用上限。- 作业通过
deepshare.io/class: guaranteed|best-effortannotation 声明服务类别。
metadata:
annotations:
deepshare.io/class: guaranteed
spec:
schedulerName: deepshare-scheduler
containers:
- name: train
resources:
limits:
nvidia.com/gpu: 4
Scheduler Framework 五个扩展点
| 扩展点 | DeepShare 中的作用 |
|---|---|
| Filter | 筛出有空闲 GPU,或满足 CPU、内存、显存、Best-effort cap 和共享条件的节点 |
| Score | 用 RF 干扰预测和双边 retention 门槛排序候选位置 |
| Reserve | 把 GPU claim 写入下一调度周期的集群视图,避免 double booking |
| PostFilter | 没有可行 GPU 时运行代价感知的 Best-effort victim 选择 |
| Permit | 只有触发 CPU/Memory in-place resize 时等待 Pod 状态反映新资源量;不是用来做 Gang Scheduling |
QAD 是 50ms 调度周期内持续变化的热状态,排序、共享和抢占都要同步消费。若 Controller 计算后再写 CRD,既增加 API Server 写压力,也引入控制环延迟和一致性窗口。放在 Scheduler Plugin 内存里能直接复用 informer cache,并在 leader 切换后重建。
一次调度周期怎么走
两级队列不要记成两个 Controller
队列符号和职责
| 队列 | 含义 | 做什么 |
|---|---|---|
Q_i^G / Q_i^B | 租户 i 的 Guaranteed / Best-effort 队列 | 按 quota 与 cap 做租户级 admission |
Q^G / Q^B | 集群级 Guaranteed / Best-effort 队列 | 按平滑 QAD 和预测剩余时间决定放置顺序 |
Guaranteed 作业只有在 U_i^G + R_j ≤ q_i 时进入集群 Guaranteed 队列。Best-effort 作业只有在没有剩余 Guaranteed 作业能通过独占或安全合用落点,并且 U_i^B + R_j ≤ ηq_i 时才进入候选集。
集群级排序采用词典序:先区分 Guaranteed / Best-effort,再按 (Q̃_i ↑, T̂(j) ↑) 排序。QAD 是第一键,所以运行时间预测误差不会让保障充分的租户跨过保障不足的租户。
QAD 在调度路径中的输入输出
输入:已兑现与应兑现
A_i^G(t):当前已经分配的 Guaranteed GPU,Best-effort 不计入。min(q_i,D_i^G(t)):当前应兑现的 Guaranteed GPU。Q_i(t):瞬时兑现率;Q̃_i(t):EMA 平滑后的控制信号。
输出:同一个 Q̃ 驱动三类决策
- 恢复排序:
Q̃越低,租户越欠保障,越先调度。 - 共享收紧:任一租户
Q̃低时,提高所需 throughput retention 门槛;极端时停止创建新 colocation。 - QoS 报告:用连续的保障度观察长期 deficit,而不是只看“是否超 quota”的二值状态。
注意:QAD 不直接无条件触发删除 Pod。GPU 抢占由 Guaranteed 作业 placement failure 触发,PostFilter 再用代价模型选 Best-effort victims。
五个扩展点怎么串起来
| 顺序 | 扩展点 | 关键动作 |
|---|---|---|
| 1 | Filter | 检查空闲/单 resident GPU、CPU/内存/显存 headroom 和 Best-effort cap |
| 2 | Score | 比较 RF 预测 retention,优先低干扰候选 |
| 3 | Reserve | 在下一周期视图中预占 GPU,防止并发调度 double booking |
| 4 | PostFilter | 无可行节点时执行 cost-aware victim selection |
| 5 | Permit | 仅在 CPU/Memory resize 已发起时等待 Pod.Status.Resources 更新 |
故障恢复与热路径
- Plugin 以多副本 Deployment 运行,通过 Lease 选主。
- QAD 可从 informer cache 的运行 Pod 推导;新 leader 用首轮瞬时 QAD warm-start EMA。
- 抢占表达为 Pod deletion,由 API Server 幂等 reconcile,不需要自定义补偿事务。
- 调度端到端延迟低于 50ms,其中特征提取、队列记账和受限候选打分合计低于 25ms。
每个租户先在自己的 Guaranteed / Best-effort 队列做 quota admission;通过后进入对应的集群级队列。集群级排序先保证 Guaranteed 优先,再用平滑 QAD 让欠保障租户先恢复,只有在保障程度相近时才用预测剩余时间做短作业优化。QAD 因此负责跨租户公平,runtime prediction 只负责局部效率。
DeepShare 高频问答
DRF 用 dominant share 在多资源之间追求 max-min fairness;QAD 则衡量单个租户当前 Guaranteed 权益的兑现率。QAD 的分子只算 Guaranteed allocation,Best-effort 借用单独记账,因此 QAD 位于 0 到 1,不用 QAD>1 表示超额资源。QAD 还能同时驱动租户恢复排序、colocation 准入和 QoS 报告,而 DRF 主要回答公平分配问题。
JCT = 排队时间 + 执行时间。执行时间由计算量决定,对所有调度策略相同。调度只能影响排队部分。当执行时间占 JCT 主要部分时,排队大幅改善只带来 JCT 小幅改善。这恰好说明调度的优化空间集中在排队环节。
K8s Extended Resource admit 后不能修改。GPU 共享通过 NVIDIA MPS 在驱动层做多路复用,设 per-client 内存限制。每块 GPU 部署一个 MPS control daemon(DaemonSet 方式)。CPU 和内存可通过 InPlacePodVerticalScaling 动态调整,但 GPU 分配必须在调度时确定。
三个原因:(1) 推理延迟——RF 推理 < 1ms,满足实时调度预算;对比 GAN-based 方法需要 50-200ms。(2) 精度足够——R² = 0.902。(3) 硬件计数器特征跨框架泛化,不需要针对每种模型架构重新训练。
大约 8% 高峰时段过载:按 QAD 升序优先最欠缺租户;最坏 QAD = 0.72,过载消退后 3.2 个周期(约 160ms)恢复到 ≥ 0.95。Best-effort 排队延迟增加 2.1 倍,Guaranteed 仅增加 14%,体现服务分级。
实现细节高频问答
论文实现中,Scheduler Plugin 在内存里维护瞬时 Q_i(t) 和平滑 Q̃_i(t)。原始状态来自 informer cache 中的运行 Pod,因此故障切主后可以重建,并用首轮瞬时 QAD warm-start EMA,不需要把每轮 QAD 写回 CRD。Controller 只把 TenantQuota 和作业 class annotation 整理成 quota 元数据,不承担实时 QAD 控制环。
Controller 管配置态,Plugin 管决策态。Controller reconcile TenantQuota CRD 和 deepshare.io/class annotation,形成租户 quota、Best-effort cap 和作业类别元数据;Scheduler Plugin 维护实时队列与 QAD,完成排序、Filter、Score、Reserve、PostFilter 抢占和 Permit 等待 resize。这样实时信号和所有放置决策留在同一个调度控制环里。
Controller 是异步 reconcile 配置态的组件,不拥有单次 scheduling cycle 的节点快照、候选打分和 assumed state。DeepShare 的 QAD、队列排序、干扰准入和抢占必须和 Filter / Score / Reserve / PostFilter 处在同一个实时控制环里,所以由 Scheduler Plugin 完成;Controller 只提供 quota 与 class 元数据。
Scheduler 仅在没有可放置的 Guaranteed 作业、且租户 Best-effort 用量满足 U_i^B + R_j ≤ η·q_i 时考虑 Best-effort。Guaranteed 作业放置失败后,PostFilter 才按低代价策略选择 Best-effort victims;所以 QAD 负责决定谁更急需恢复,真正触发 GPU 抢占的是 placement failure。本质:可借、单独记账、需要时可回收。
不需要讲 PodGroup、minAvailable、等待全部 worker 到齐或整组回滚。论文的五个扩展点是 Filter / Score / Reserve / PostFilter / Permit;其中 Permit 只在 CPU/Memory in-place resize 发起后等待 Pod 状态更新,不用于 Gang Scheduling。如果以后支持多 worker 训练,才需要给 Permit 增加 PodGroup 级等待语义。
论文原文延伸问答(基于 IEEE Cluster 2026 原稿)
下面这组问题对应面试官真正会按论文细节追问的角度:参数选取、消融、敏感性、对比 baseline、工程边界。回答全部出自论文正文与 §V 实验。
λ=0.3、调度周期 50ms,物理意义是什么?论文 §III-A 给的解析:在 50ms 调度周期下,持续偏差在大约 350ms 内累积到稳态值的 90%,几何收敛速率为 \((1-\lambda)\)。这个区间能 过滤亚秒级抖动(短任务结束、突发请求),同时让真正的"持续 under-service"快速被发现。λ 再调大会被短任务完成的抖动带飞,调小则恢复信号迟滞。
论文 Eq.1 显式规定 \(Q_i(t)=1\) 当 \(D_i^G(t)=0\)。这是为了 "暂时不用 quota ≠ 被亏待":定 0 会让空闲租户被错误识别为最受损者并抢回资源;同时分母用 min(q_i, D_i^G(t)) 又防止租户通过虚报巨大 \(D_i^G\) 压低 QAD、抬高恢复优先级。这两条共同实现"既不奖励虚假 demand,也不惩罚临时空闲"。
这里问的是干扰预测器,不要和运行时间预测混在一起。论文 §III-C 的考虑包括:(1) sub-millisecond 推理,可以放在 Kubernetes scheduler 关键路径上;(2) RFE 选出的主特征是 SM Active (44.5%)、co-run SM Active (20.6%)、mem copy util (12.3%),与干扰来源相符且可解释;(3) 输入是 DCGM 硬件计数器,跨 framework / model 更容易泛化。它预测共享吞吐保持率,\(R^2=0.902\)。31.84% MAPE 和 \(R^2=0.7286\) 属于另一个 per-tenant gradient boosting 运行时间预测器,不能拿来证明 Random Forest 的准确率。
定义:
分子 R_j·T̂(j) 是"如果抢占这个 victim,能回收多少 GPU-时";分母 1+α·C_p(j) 惩罚已经被抢占过多次的 Pod,避免同一作业被反复打断。SelectVictims 按 \(E_j\) 降序贪心选取直到释放约束 Eq.3 满足,复杂度 O(n log n)。这是对原 NP-hard 选 victim 子问题的近似。论文 sensitivity 给默认 α=0.5、β=0.3,区间 α∈[0.3,0.8]、β∈[0.1,0.6] 都接近最优。
会,所以论文叠了一层在线检测:DCGM 周期采样实际 retention \(\hat{\rho}=t_{shared}/t_{excl}\),连续 3 个采样窗口 \(\hat\rho<\rho_{tol}\) 就把这一对标 degraded,下一周期把 Best-effort 伙伴抢占。固定窗口规则相比 CUSUM 等顺序检测的好处:检测延迟有界 + 每对只维护一组计数器,落到调度器里行为更可预测。一对 GPU 上发生干扰漂移时不会拖到 Guaranteed 任务才被发现。
论文公式:
\(\gamma=0.5\) 让压力亚线性增长,短促 demand burst 不会立刻把所有 colocation 一刀切关掉;最大值再被任一租户的"欠服务度" k - Q̃ 放大,欠服务越严重门槛越高。Sensitivity 显示 \(\rho_{min}=0.7\) 是甜点:0.5 时 GPU 利用 71.2% 但平均放慢 18%,反而 JCT 倒挂;0.9 时干净但只剩 55.3% 利用率。
Venus 23,859 jobs 上采用按租户训练的 gradient boosting regressor。总体 MAPE 为 31.84%,\(R^2=0.7286\);历史提交 ≥50 的老租户 MAPE<25,新租户落到集群级 fallback 模型,MAPE<60。冷启动不会阻断调度,只是时间排序不那么准。Figure 4 在随机 2000 jobs 上对照 real vs prediction;即使长尾作业误差较大,也不会覆盖 QAD 主排序,因为 \(\hat{T}(j)\) 只是 secondary key。
nvidia.com/gpu 是 K8s Extended Resource,论文怎么绕开"准入后不可修改"?论文 §IV-B 明确:GPU 数确实改不了,所以 DeepShare 不动 GPU 数;要释放资源时走两条路。
(1) CPU/Memory 走 Pod resize subresource:control plane 必须启用 InPlacePodVerticalScaling,VPA 推荐基础上额外保留 max(10%, 0.5 core) CPU 和 max(10%, 256 MB) memory headroom,避免压缩后 OOM。
(2) GPU 抢占走删 Pod / 重建:通过 PostFilter 选 victim 后由 API server 删除 Pod,新 Pod 重新进入 scheduler。这是为什么论文必须在 §IV 里强调依赖 K8s v1.35 的新 subresource。
论文 §V-D 给出量化:Venus peak-hour 中约 8% 周期会进入过载。Algorithm 1 按 \(\tilde{Q}_i(t)\) 升序排队,近似 max-min fair recovery。可观测后果:
· 单租户最差 \(\tilde{Q}_i=0.72\);
· spike 之后 3.2 个 cycle (~160ms) 恢复到 \(\tilde{Q}_i\ge 0.95\);
· Best-effort 排队延迟 2.1×,Guaranteed 仅 +14%——这就是"服务差异化"在论文里的实际兑现。
物理 16-GPU testbed(§V-E Figure 11):
· DRA 单独 vs Hard:makespan −23%、JCT −18.5%、queue −36%;
· DRA + Colocate vs Hard+Colocate:makespan −32%、JCT −34%、queue −66%;
· DRA + Colocate vs DRA-only 再省 31% 排队(Figure 10),整体 throughput 1.48×。
仿真消融(Figure 7):去掉 runtime prediction 排队 +18.4%,去掉 interference awareness 排队 +30.1%——结论是 colocation 的贡献 > runtime prediction,但两者必须由 QAD 兜住才不会反过来伤害 SLA。
论文 §V-C 直接解释了:JCT = queueing + execution,execution 部分各策略基本一样,所以平均 JCT 改善被稀释。真正能差异化的是排队侧——论文给出 queueing −46%(1067s vs 1976s)、P95/P99 tail JCT −23%、idle GPU time −71%(vs Lucid)/ −96.8%(vs FIFO)。面试时讲"为什么 JCT 看起来涨幅有限"是高频反向追问,要答:DeepShare 主战场是 排队公平性 + tail-latency,平均 JCT 不是核心指标。
§V-G 明文承认四条:
(1) 干扰预测器在 16 个 DL 模型族(CV/NLP/RL/recommender) 上训练,未见架构(如新型 MoE)可能要重训;硬件计数器为输入提供一定泛化。
(2) 物理 testbed 只有 16 GPU,结论稳妥外推到 部门级集群(数十至低三位数 GPU),更大规模需要重新评估。
(3) 异构加速器(如 H100、TPU、国产卡)需要重新 profiling 并重训 RF 干扰模型。
(4) 论文未覆盖 多 node 分布式训练 / Gang Scheduling 场景,generalize 到 LLM 大集群训练需要补 PodGroup + Permit 扩展点(可主动补充作为面试加分)。
论文 §VI Related Work 总结:
· Tiresias:MLFQ 排序但无 runtime knowledge;DeepShare 加了运行时间预测和 QAD。
· Lucid:最强非侵入式 sharing baseline,但干扰模型简单(DeepShare 干扰 \(R^2=0.902\) 显著更准)+ 静态阈值(DeepShare 用 \(\rho_{tol}\) 动态调)。
· Gavel:max-min fair throughput 但假设 GPU 独占,没法 colocate。
· HiveD:静态 cell 分区给保证,不弹性,恰好是 DRA 要解的问题。
· Optimus / ElasticFlow:在线 runtime prediction 但无 QAD,会让短任务覆盖租户公平性。
论文卖点是把 quota assurance + interference colocation + runtime prediction 三者用单一 \(\tilde{Q}_i(t)\) 信号闭环,前述任何一篇都只解决其中一两块。
先记住这条七步主线
背景冲突 → 现有缺口 → QAD → 弹性借用 → 预测调度 → 干扰感知合用 → 实现与结果
正常语速讲 4~5 分钟;面试官打断后,再进入公式、预测器或 Kubernetes 实现细节。
两个预测模块先彻底分开
| 维度 | 运行时间预测 | 干扰预测 |
|---|---|---|
| 回答的问题 | 这个作业还要运行多久? | 两个作业放在同一张 GPU 上会慢多少? |
| 论文模型 | Per-tenant gradient boosting regressor | Random Forest |
| 输入 | 租户历史作业;新租户使用 cluster-wide fallback | DCGM 硬件遥测,如 SM activity、显存带宽、L2、PCIe、Tensor Core、功耗等 |
| 输出 | 预测剩余运行时间 T̂(j) | 预测吞吐保持率 ρ̂ = t_shared / t_excl |
| 调度用途 | QAD 之后的第二排序键;估计抢占收益与代价 | Filter / Score 阶段判断能否合用以及放到哪张 GPU |
| 安全边界 | 预测不覆盖 QAD;错了主要影响效率,不改变租户保障顺序 | 动态阈值准入;运行时连续 3 个窗口异常就驱逐 Best-effort 伙伴 |
| 论文结果 | MAPE 31.84%,R² = 0.7286 | R² = 0.902,推理延迟为亚毫秒级 |
记忆口诀:运行时间预测解决时间顺序,干扰预测解决空间放置;前者是 Gradient Boosting,后者才是 Random Forest。
论文边界:原文给出了运行时间预测器的按租户训练方式、冷启动 fallback 和准确率,但没有展开它的具体特征向量。面试时不要自行补成“也使用 DCGM 特征”;DCGM 硬件计数器属于干扰预测器。
1. 背景:固定配额和资源共享存在天然矛盾
我想介绍一下 DeepShare,这是我们面向多租户 GPU 集群设计的、以配额保障为核心的资源管理系统。
它的背景是,企业里的 GPU 集群通常由多个团队共享。平台会给每个租户一个 quota 来保证公平,例如 A 团队 32 张卡、B 团队 16 张卡。但是各团队的需求具有明显的突发性:B 当前没有任务时,如果它的 16 张卡仍被静态保留,A 的作业即使在排队也不能使用,集群利用率会很低;如果允许 A 借用,B 的 Guaranteed 作业回来时,又必须及时拿回自己的资源,否则 quota 只是纸面承诺。
GPU 内部还有第二层浪费。很多训练作业受数据加载、CPU 或通信阶段影响,并不会一直打满 SM 和显存带宽。把两个作业放在同一张 GPU 上可以提升利用率,但盲目合用会产生不可控干扰,反而拖慢 Guaranteed 作业。
因此核心矛盾是:既想通过跨租户借用和卡内合用提升利用率,又必须把租户的配额保障真正兑现出来。
2. 动机:现有方法分别优化局部,却没有统一保障语义
现有工作往往只解决其中一个局部问题:固定 quota 能保证隔离但浪费资源;短作业优先能降低平均等待,却可能让某些租户长期得不到保障;GPU sharing 能提高利用率,却不一定知道当前能否承受干扰。
所以我们的判断是,问题不只是缺少一个更复杂的调度算法,而是 quota 借用、队列排序、抢占回收和 GPU 合用之间,缺少一个统一的反馈信号。系统需要随时回答:哪个租户当前最欠保障?
3. 核心设计:用 QAD 表示配额兑现程度
DeepShare 引入 QAD,也就是 Quota Assurance Degree:
分子 A_i^G(t) 是已经分给租户 i 的 Guaranteed GPU 数量;分母 min(q_i, D_i^G(t)) 是系统此刻真正应该保障的 GPU 数量,也就是 quota 和当前 Guaranteed demand 中较小的一个。直观上就是:已经兑现多少 / 此刻应该兑现多少。
如果租户没有 Guaranteed demand,QAD 直接定义为 1,因为“暂时没用 quota”不等于“被系统亏待”。Best-effort 借来的卡不计入分子,所以 QAD 的范围是 0 到 1,不会因为借用资源大于 1。系统还用 EMA 平滑瞬时 QAD,避免短任务完成或突发请求造成频繁抖动。
4. QAD 统一驱动三个机制
第一,弹性配额借用 DRA。租户没有用满 quota 时,闲置 GPU 可以借给其他租户运行 Best-effort 作业;原租户的 Guaranteed demand 回来后,如果资源不足,系统就回收这些可借用资源。这样 quota 从静态分区变成了“可借但必须能还”的保障承诺。
第二,QAD-first 的预测调度。调度器先按平滑 QAD 升序选择租户,保障不足的租户先调度;只有在 QAD 相同或接近时,才使用预测剩余运行时间让短作业优先。抢占时也会结合可释放的资源、剩余时间和抢占代价选择 victim。因此,预测负责优化效率,QAD 负责守住公平性。
第三,QAD-aware 的干扰感知合用。系统预测两个作业共享 GPU 后的吞吐保持率,并结合当前资源压力和租户 QAD 动态调整准入阈值。租户越欠保障,系统对它受到的干扰越保守;保障充分时,才更积极地合用 GPU。
5. 两个预测模块分别怎么做
运行时间预测模块:我们观察到租户的提交具有重复性,78% 的用户会反复提交特征和时长相近的作业,因此论文正文采用 per-tenant gradient boosting regressor,利用每个租户自己的历史作业学习其工作负载规律,输出预测剩余运行时间 T̂(j)。历史不足的新租户使用 cluster-wide fallback model。它有两个用途:一是在 QAD 之后作为第二排序键,降低平均排队时间;二是在抢占时帮助判断一个 victim 还剩多久、现在打断是否划算。Venus 23,859 个作业上的 MAPE 是 31.84%,R² = 0.7286。历史提交不少于 50 次的租户 MAPE 小于 25%,冷启动 fallback 的 MAPE 小于 60%。原文没有进一步列出该模型的具体特征向量,所以面试时不要自行补成 DCGM 特征。
干扰预测模块:这里使用的是 Random Forest。输入不是模型名字,而是 DCGM 采集的硬件遥测,例如 SM activity、显存带宽、L2、PCIe、Tensor Core、DRAM throughput 和功耗等;输出是两个作业合用时的吞吐保持率 ρ̂。采用硬件计数器有两个好处:一是跨框架、跨模型更容易泛化;二是 Random Forest 可以在 scheduler 关键路径上实现亚毫秒级推理。论文中该模型的 R² = 0.902。
预测本身不是安全保证,所以 DeepShare 还做了运行时闭环。DCGM 会持续监控实际保持率;如果连续 3 个采样窗口低于容忍阈值,就把这对合用标为 degraded,并在下一调度周期驱逐 Best-effort 伙伴,优先保护 Guaranteed 作业。
6. 工程实现和实验结果
工程上,我们把系统实现成 Kubernetes 的轻量 Controller 加 Scheduler Plugin。Controller 负责 TenantQuota 和作业类别等静态元数据;Plugin 维护实时 QAD 和两级队列,并在 Filter、Score、Reserve、PostFilter、Permit 等扩展点完成合用准入、放置、资源预留和抢占。
在 Venus 23,859 个作业的 trace-driven 实验中,DeepShare 把 GPU 利用率从 39.64% 提高到 70.58%,相对 Lucid 提升 29.5%;平均排队时间相对 Lucid 降低 46%。消融实验中,移除运行时间预测后排队时间增加 18.4%,移除干扰感知后增加 30.1%。在 16-GPU 物理集群上,完整方案相对 Hard+Colocate 将 makespan 降低 32%、JCT 降低 34%、排队时间降低 66%,租户周期的 QoS 合规率达到 93%。
7. 收尾:这项工作的核心贡献
所以我认为 DeepShare 最关键的贡献,不是单独提出一个预测器或一个共享策略,而是把配额保障变成一个可观测、可反馈的 QAD 控制信号,再让弹性借用、时间调度和空间合用围绕同一个目标闭环。最终实现的是:资源空闲时敢于共享,租户保障不足时能够及时、可解释地收回来。
面试官打断时,用这四句保住主线
- 背景:固定 quota 保公平但浪费,动态共享提利用率但可能还不回来,也可能引入干扰。
- 核心:QAD = 已经兑现的 Guaranteed GPU / 此刻应该兑现的 Guaranteed GPU。
- 设计:QAD 同时控制资源借用与回收、队列排序与抢占、GPU 合用准入。
- 预测器:Gradient Boosting 预测剩余时间、优化先后顺序;Random Forest 预测共享干扰、优化放置位置。
因为它们的决策对象、数据和错误后果都不同。运行时间预测面向单个作业和租户历史,回答“还要多久”,主要影响队列顺序和抢占收益;干扰预测面向作业对和硬件遥测,回答“放在一起会慢多少”,直接决定共享准入。拆开后可以独立训练、独立回退,也能分别设置安全边界。
不会直接破坏租户公平性,因为调度是词典序:先比较平滑 QAD,再比较 T̂(j)。预测错误只会让同一保障层级内的短作业排序不够理想,不能让一个高 QAD 租户越过一个低 QAD 租户。也就是说,QAD 是安全主键,运行时间只是效率次键。
预测只负责准入,运行时监控负责兜底。系统持续用 DCGM 观察实际吞吐保持率,连续 3 个窗口低于动态阈值就降级这对合用,并抢占 Best-effort 伙伴。这个“离线预测 + 在线纠偏”闭环,比只相信模型输出更适合生产调度系统。
最重要的判断是把预测放在保障机制之下,而不是让预测结果直接定义公平性。QAD 负责表达租户权益是否兑现,两个预测器只在不越过这条边界的前提下优化时间和空间效率。这样即使模型存在冷启动、分布漂移或预测误差,系统仍然有可解释的保障顺序和在线回退路径。
容易说错的六个口径
| 不要这样说 | 正确说法 |
|---|---|
| 两个模块都是 Random Forest | 运行时间是 per-tenant gradient boosting;干扰预测才是 Random Forest |
| 短作业优先决定全局顺序 | QAD 是第一排序键,预测运行时间是第二排序键 |
| 预测干扰低就一定安全 | 还要经过动态阈值,并由连续 3 个窗口的在线监控兜底 |
| 借得越多,QAD 可以大于 1 | Best-effort 借用不进入 QAD 分子,QAD 位于 0 到 1 |
| QAD 一下降就立即杀掉 Best-effort | 先按保障顺序尝试放置;Guaranteed 无法放置时才进入抢占回收 |
| Controller 实时计算和维护 QAD | Controller 管 quota 元数据;Scheduler Plugin 维护实时 QAD 控制环 |
问题背景
GPU 集群中同时存在两类负载:
- 训练任务:长时运行(几小时到几天),资源需求波动大(前向/反向/通信阶段 GPU 利用率交替高低),对延迟不敏感但不能被随便杀(checkpoint 周期长,重启代价大)。
- 离线 LLM 推理:相对短时(几分钟到几十分钟),对延迟有一定 SLO 要求,资源需求在 prefill 阶段高、decode 阶段低。
核心矛盾:
- 资源互补:训练在通信/数据加载阶段 GPU 空闲,decode 阶段 SM 利用率低,可以互相填补空隙。
- 干扰风险:如果直接放一起,两者争用 SM、显存带宽,可能导致训练 JCT 暴增或推理 SLO 违约。
- 缺乏隔离机制:NVIDIA MPS 能做算力划分,但不能动态调整、不能处理显存竞争;MIG 是静态划分,灵活性不够。
ElastiCo 的核心问题:如何让训练和推理安全共置,且推理可弹性进出(原主要求资源时推理能退),不需要修改用户代码。
三项核心机制
训练和推理对 GPU 资源的使用模式不同:
- 训练:主要消耗 SM 算力 + 显存(存权重、梯度、优化器状态),对 SM 比例敏感但可容忍一定的 SM 缩减。
- 推理:主要消耗显存(权重 + KV Cache),prefill 阶段突发算力,decode 阶段算力需求低。
资源形态变换的核心思想是:根据两个任务当前阶段动态调整资源分配比例,而不是固定切分。具体来说:
- 利用 CUDA MPS 的 per-client SM 限制做算力比例动态调整(通过 CUDA_MPS_ACTIVE_THREAD_PERCENTAGE 环境变量动态设置)。
- 利用 CUDA VMM 的显存预留/提交机制做显存弹性管理——推理权重和 KV Cache 按需映射,训练需要时可回收。
- 当训练进入 I/O 或通信阶段(GPU 空闲窗口),主动增加推理的 SM 配额;训练进入计算阶段时,收缩推理 SM 配额。
和静态 MIG 切分的区别:MIG 是物理分区,切完后算力和显存比例固定;MPS + VMM 是逻辑隔离,可以毫秒级调整。
影子定价借鉴经济学中的影子价格概念——给每个资源(GPU 上的 SM、显存)定一个动态"价格",反映该资源在当前时刻的稀缺程度。
定价模型:
- 价格信号:基于训练任务的当前 GPU 利用率和显存使用量计算——利用率越高、显存越紧张,SM 和显存的影子价格越高。
- 弹性调整:当影子价格低(训练空闲)时,允许推理使用更多资源,定价低;当影子价格高(训练繁忙)时,推理缩容,定价高。
- 准入控制:推理任务的"价值"(SLO 优先级 × 剩余工作量)必须大于当前影子价格才能启动共置,否则等待或放到空闲 GPU。
本质上是把资源分配问题转化为一个基于动态价格的市场清算问题:价格随供需变化,供需平衡时实现最优共置。比固定阈值更灵活——高优推理在价格高时仍可进入,低优推理在价格低时才进入。
和 DeepShare 的干扰感知有相似之处,但针对训推共置场景做了特殊优化:
- 特征工程:不仅采集硬件计数器(SM activity、mem bandwidth、L2 hit rate),还采集训练任务的阶段信号(forward/backward/communication 阶段),用阶段信息辅助干扰预测。
- 干扰模型:训练一个轻量级性能模型,预测"训练任务在阶段 S、推理任务在阶段 T、SM 比例为 x"时,两者的 slowdown。
- 动态准入与驱逐:实时监控实际 slowdown,超过训练容忍阈值(如 10%)时暂停/驱逐推理;低于阈值时继续运行。
- 推理保护:推理任务有自己的 SLO 预算(如 TTFT < 500ms),当干扰导致推理 SLO 有违约风险时主动缩容推理的 batch size 而非杀掉。
关键区别:DeepShare 的合用主要是训练+训练共置,两个任务地位对等;ElastiCo 是训练+推理,训练是"主"、推理是"客",主客之间有优先级不对称性——推理可以被暂停/驱逐/缩容,但训练不应该被杀。
核心结果
Kubernetes 实现
ElastiCo 实现为 Kubernetes 原生中间件,核心组件:
- ElastiCo Controller:管理共置对(co-location pair)的生命周期、影子定价计算、准入决策。监听 Pod 事件,识别训练 Pod 和推理 Pod。
- Node Agent(DaemonSet):部署在每个 GPU 节点上,负责:(1) 通过 DCGM 采集 GPU 硬件指标;(2) 动态调整 MPS SM 比例;(3) 通过 CUDA VMM ioctl 管理显存映射;(4) 监控实际 slowdown 并上报 Controller。
- Scheduler Plugin:扩展 Score 插件,优先把推理 Pod 调度到有空闲窗口的训练 GPU 节点上;Filter 插件检查节点是否满足推理的最小资源需求。
零侵入:用户不需要修改训练或推理代码。通过 MPS 环境变量 + CUDA VMM API + cgroup 限制在运行时层面实现隔离和弹性。
和 DeepShare 的关系
| 维度 | DeepShare | ElastiCo |
|---|---|---|
| 解决场景 | 多租户之间的配额管理与资源借用 | 同一 GPU 上训练与推理的共置 |
| 核心信号 | QAD(配额保障度) | 影子定价(资源稀缺度) |
| 合用对象 | 训练 + 训练 | 训练 + 推理 |
| 优先级 | Guaranteed > Best-effort,对等租户之间 | 训练为主、推理为客,不对称优先级 |
| 资源隔离 | MPS 静态 SM 限制 | MPS 动态 SM + VMM 弹性显存 |
| 驱逐策略 | 杀 Best-effort Pod | 推理可暂停/缩容/驱逐,训练不杀 |
两者可以组合使用:DeepShare 在集群层面做多租户配额治理,ElastiCo 在节点层面做训推共置优化。
ElastiCo 高频问答
"形态"强调的不是简单地把 GPU 切成固定比例,而是根据不同类型任务的资源使用特征,动态改变资源的"形状"——即 SM 算力和显存的分配比例。训练任务在计算阶段需要更多 SM、在 IO 阶段不需要;推理在 prefill 需要突发 SM、decode 阶段 SM 空闲。固定切分(如 MIG 50/50)无法利用这些互补窗口。ElastiCo 通过 MPS 动态调整 active thread percentage 实现 SM 弹性,通过 CUDA VMM 按需映射/取消映射物理页实现显存弹性,组合起来就是资源形态随负载动态变化。
QAD 是租户级保障指标,回答"这个租户被欠服务了多少",用于跨租户优先级排序;影子定价是节点级资源价格信号,回答"当前这张 GPU 的资源有多稀缺",用于推理任务的共置准入决策。QAD 驱动"谁先调度",影子定价驱动"能不能共置、共置多少"。两者在不同层级运作。
ElastiCo 不会驱逐训练任务。训练是"主"角色,在 GPU 上有常驻权。被驱逐/缩容的始终是推理任务。推理任务因为是离线推理(非在线服务),SLO 是分钟级而非毫秒级,被驱逐后可以:(1) 暂停(保留 KV Cache 在 CPU 内存),等训练空闲再恢复;(2) 迁移到其他 GPU;(3) 如果推理支持增量 checkpoint,从断点继续。实测中推理暂停/恢复开销约 2-5 秒,对离线推理可接受。
三层透明注入:(1) 容器层:通过 admission webhook 自动注入 MPS 环境变量、VMM 配置和必要的 LD_PRELOAD 库;(2) 运行时层:Node Agent 通过 CUDA Driver API(cuMemCreate/cuMemMap/cuMemUnmap)管理显存,不需要训练/推理框架感知;(3) 调度层:Scheduler Plugin 在调度阶段就做好放置决策,用户只需要提交标准 Pod(带 elastico.sh/class: training 或 inference 标签)。
两个系统的基线利用率不同。ElastiCo 的场景是训推共存集群,训练任务本身有大量 IO/通信空窗,纯训练集群的平均利用率通常只有 20-30%;而 DeepShare 的场景是纯训练多租户集群,基线利用率约 40%。而且 ElastiCo 的 46% 是训推安全共置下的利用率,有 SLO 约束(不能让训练 slowdown 超过阈值),而 DeepShare 是训练间共享,干扰容忍度更高。两者不可直接比较数字。
MPS SM 比例调整通过设置 CUDA_MPS_ACTIVE_THREAD_PERCENTAGE 并重启 MPS control daemon 实现,切换延迟约 50-200ms。ElastiCo 不会在 prefill 阶段调整 SM 比例(那是推理的关键路径),而是在 decode 阶段或训练通信阶段做调整。对离线推理来说,200ms 级别的波动完全可接受。
问题背景
两个实际痛点:
- Profiling 成本高:深度学习模型上线前,往往需要在各种 GPU 型号、batch size、序列长度下反复试跑才能估计资源需求(需要多少显存、跑多快)。对于大模型,一次 profiling 可能需要多张 A100 跑几十分钟,成本高、周期长,拖慢上线节奏。
- Agentic 工作流冷启动慢:LLM Agent 系统中,不同工具调用会触发不同模型(搜索用小模型、代码生成用代码模型、总结用通用模型),模型频繁加载/卸载导致冷启动延迟(模型权重从 CPU 加载到 GPU 需要几秒到几十秒),同时固定显存预留要么 OOM 要么浪费。
核心洞察:模型的计算图(ONNX 格式)天然是一个图结构——节点是算子(matmul、conv、layer_norm 等),边是张量(带 shape、dtype 信息)。计算图的拓扑结构、算子类型和张量形状共同决定了模型的运行时性能。这和 GNN 的图结构建模能力天然匹配。
系统设计
图构建:将 PyTorch/TF 模型导出为 ONNX,然后将 ONNX 计算图转化为图样本:
- 节点特征:算子类型(embedding 为 one-hot + 可学习 embedding)、算子属性(kernel size、stride、groups 等卷积参数)、输入输出张量数量。
- 边特征:张量 shape(如 [B, 1024, 768] → 维度数值 + dtype + 总元素数)、tensor size(bytes)。
- 全局特征:batch size、序列长度、GPU 型号 embedding(不同 GPU 的 SM 数、显存带宽、算力作为 global feature)。
图预处理:ONNX 计算图可能有冗余节点(identity、constant),需要做常量折叠和节点融合预处理;过大的计算图做子图采样,控制图规模在可处理范围内。
为什么用 GNN:
- 计算图是天然的图结构,CNN/MLP 无法直接处理变长拓扑;
- GNN 的消息传递机制模拟了张量数据在算子间流动的过程——算子节点的特征聚合其输入张量的信息,类似实际执行时算子读入输入张量进行计算;
- 不同模型的计算图大小差异大(从几百到几万节点),GNN 可以处理变长图。
模型架构:
- GNN Backbone:使用 GIN(Graph Isomorphism Network)或 GAT(Graph Attention Network)做 4-6 层消息传递,因为算子间主要是 1-hop 依赖,但多层可以捕捉多跳数据流。
- Graph-level Readout:使用 global add/mean pooling 加上 attention pooling(重要算子如 matmul 赋更高权重),得到图级 embedding。
- 多任务输出头:共享 GNN backbone,接三个 MLP 输出头分别预测:(1) 运行时延(ms),(2) 显存峰值(GB),(3) GPU 利用率(%)。
训练策略:
- loss = w₁ · MSE(latency) + w₂ · MSE(memory) + w₃ · MSE(utilization),用 uncertainty weighting 自动平衡多任务 loss;
- 标签做 log 变换处理长尾(有些超大模型时延和显存是极端值);
- 显存预测偏向高估(安全裕度),OOM 的代价比浪费大。
通过运行时程序分析自动采集 (计算图, 性能指标) 对:
- 插桩 PyTorch/ONNX Runtime,运行模型时自动记录每个算子的输入 shape、执行时间、显存分配。
- 覆盖 CNN(ResNet、EfficientNet)、Transformer(BERT、GPT、LLaMA 系列)、推荐模型(DLRM、Wide&Deep)等多模型族。
- 跨多个 batch size、序列长度、GPU 型号采集。
- 数据集规模 10W+ 条(图样本 × 配置组合)。
将预测信号用于 LLM Agent 系统的模型调度:
- 冷启动预部署:根据 Agent 的当前对话上下文和下一步可能调用的工具,提前预测需要的模型,将其权重从 CPU/NVMe 预加载到 GPU,避免用户等待模型加载。
- OOM 风险感知选卡:预测模型峰值显存,如果当前 GPU 剩余显存不够(加上安全裕度),选择更大的 GPU 或驱逐低优先级模型,避免运行时 OOM。
- 显存复用与驱逐:根据预测的模型执行时长和显存需求,决定哪些模型可以常驻 GPU、哪些可以换出到 CPU,类似 Maestro 的分级缓存但用 GNN 预测替代启发式估计。
预期结果
(具体实验数据以论文最终版为准)
SagePilot 高频问答
参数量和 FLOPs 是粗粒度指标,无法捕捉关键的性能影响因素:(1) 算子类型差异——同样是 1GFLOP,matmul 是 compute-bound 且 GPU 利用率高,element-wise 是 memory-bound 且利用率低;(2) 内存访问模式——同样参数量的模型,访存密集型(如小算子多)和计算密集型(如大 matmul)性能差异巨大;(3) 模型结构影响——Attention 有不规则的 memory access pattern,和同等 FLOPs 的 conv 不可比。GNN 通过建模图结构和算子类型,能捕捉这些细粒度差异。
ONNX 静态图确实丢失了一些信息:(1) 算子融合:推理引擎(TensorRT/TVM)会做 kernel fusion,但 ONNX 里是分开的节点,导致预测的 kernel launch 数不准。补偿方式:加入 fusion pattern 匹配特征或用实际执行的 kernel trace 做训练标签。(2) 动态 shape:ONNX 的动态维度(如 batch size、seq_len)是符号化的,需要通过全局特征传入。(3) CUDA kernel 选择:cuBLAS/cutlass 会根据 shape 选择不同 kernel,同样的 matmul 在不同 shape 下效率差异大。补偿:把具体 shape 数值作为边特征,让模型学习 shape→kernel 性能的映射。
GPU 型号通过 global feature 传入(SM 数、显存带宽、FP16 算力、L2 cache 大小等)。GNN 的消息传递是GPU 无关的——它学习的是算子之间的数据流和算子类型的影响,而 GPU 特征只影响最终输出头的 scale。所以在 A100 上训练的模型,只需要更换 global feature 中的 GPU 参数,就可以 zero-shot 迁移到 H100 上预测。如果在 H100 上有少量 profiling 数据,可以 few-shot fine-tune 校准输出头。
使用 uncertainty weighting(Kendall 2018)自动学习每个任务的噪声参数 σ,动态调整 loss 权重。对于显存预测,使用非对称 loss(MSE + 不对称惩罚):低估的惩罚是高估的 3 倍——因为低估导致 OOM(请求失败),高估只是浪费显存(可接受)。时延预测用对称 MSE,GPU 利用率预测用 Huber loss(对异常值鲁棒)。
Maestro 的预测是请求级的——给定 agent 角色和 prompt 上下文,预测单次 LLM 推理的输出 token 数和 KV 显存需求,用的是 LightGBM(表格数据、结构化+语义特征)。SagePilot 的预测是模型级的——给定 ONNX 计算图和部署配置,预测模型本身的运行时延和显存峰值,用的是 GNN(图结构数据)。两者粒度不同:Maestro 管的是"这次请求需要多少 KV",SagePilot 管的是"这个模型跑起来需要多少资源"。SagePilot 的模型级预测可以为 Maestro 提供模型权重显存的基础估计,两者互补。
几个区别:(1) Paleo用解析模型(FLOPs/带宽)估算,需要手动建模每个算子,泛化差;(2) Habitat基于协同过滤,用同 GPU 上已有模型的性能做迁移,但冷启动需要至少一个 profiling;(3) Daydream用白盒模拟器,需要获取完整的 kernel 执行 profile,部署复杂。SagePilot 的优势:(a) 只需要 ONNX 计算图(导出即可,不需要实际执行);(b) GNN 自动学习算子→性能的映射,不需要手动写算子模型;(c) 一次推理同时输出多个指标(时延/显存/利用率);(d) 跨 GPU 泛化。
自动化采集 pipeline:(1) 从 HuggingFace 和 ONNX Model Zoo 拉取开源模型(约 500 个不同架构);(2) 在多个 GPU(V100/A100/H100)上用 ONNX Runtime 插桩运行,记录每个配置(batch size、seq_len、precision)的真实性能;(3) 每个模型跑多个配置组合,生成约 10W+ 条 (graph, config) → (latency, memory, util) 样本。覆盖 CNN(ResNet/EfficientNet/MobileNet)、Transformer(BERT/GPT-2/BART/LLaMA)、推荐(DLRM/Wide&Deep)、RNN(LSTM/GRU)等主流模型族。
面试叙事
互补关系
Maestro 解决推理侧的多 agent 调度,DeepShare 解决训练侧的多租户管理。一个完整的 GPU 集群需要同时支持训练和推理。
共通设计理念
| 理念 | Maestro | DeepShare |
|---|---|---|
| 预测驱动调度 | 预测输出长度 → 内存管理 + 排队 | 预测运行时间 → 排序 + 抢占 |
| 代价感知抢占 | 量化降级代价 C_deg 选最小影响路径 | 量化抢占效率 E_j 考虑进度损失 |
| 弹性资源管理 | CUDA VMM 3× 超配 | DRA 弹性配额借用 |
| 分层架构 | 全局调度器 + 节点运行时 | 全局调度器 + 节点 DaemonSet |
自我介绍中的论文定位
我的研究聚焦于 GPU 集群的资源调度与性能预测,在训练和推理两个互补场景下展开:
DeepShare(IEEE Cluster 2026)解决多租户 GPU 集群中训练作业的调度。核心创新是配额保障度 QAD,统一驱动弹性配额管理、预测性调度和干扰感知合用,在 219 GPU 的 K8s 集群上实现 70.58% GPU 利用率和 93% QoS 合规率。
Maestro(ICDCS 2026)面向 LLM 多智能体系统的推理调度。核心挑战是输出长度不确定性和多模型内存压力。设计了两阶段预测器加 CUDA VMM 超配加 SRTF 调度,在 64 块 A100 上将 SLO 达成率提升 23.6 个百分点。
贯穿核心能力:用轻量预测模型为调度器提供前瞻性信号,再设计弹性资源管理和抢占策略来利用这些信号。
与工业界系统的区别
| 对比对象 | 区别 |
|---|---|
| vLLM / SGLang | 它们是单节点推理引擎,Maestro 在其之上做多模型管理和跨节点调度 |
| Volcano | 面向 Gang scheduling,DeepShare 在配额弹性、干扰感知、运行时间预测方面做了增强 |
| Orca / FastServe | 它们关注单模型的迭代级调度,Maestro 关注多模型多 agent 的工作流级调度 |
简历论文提问的一般规律
面试官看简历上的论文/项目描述时,通常按以下路径追问:
- "这个东西解决什么问题?"——先确认你理解问题本身,不是只记了术语。
- "为什么现有方法不行?"——考察你是否理解 gap 和 motivation。
- "你的核心想法是什么?"——明确说清楚 insight。
- "具体怎么实现的?"——深入技术细节,考察你是否真做了。
- "XX 技术为什么选这个不选那个?"——设计决策题,考察 trade-off 思维。
- "效果怎么样?怎么评估的?"——数字背后的实验设计和结论可信度。
- "有什么局限性?如果重做会怎么改进?"——考察反思能力。
Maestro(ICDCS 2026)简历追问
简历原文:"面向 LLM 多智能体系统的工作负载感知调度系统 Maestro。针对 LLM 多智能体(LLM-MAS)工作流中解码成本不确定、长尾多模型显存竞争与过度预留等系统挑战,设计在严格 GPU 预算下的工作负载感知调度系统。预测层:利用 Agent 角色与工具调用语义构建两阶段输出长度与显存预测器;调度层:工作流感知优先级排序与阶段边界抢占,SLO 达成率较 EDF 提升 23.6pp;节点层:分级权重缓存与弹性显存供给,KV 预留显存降低 67.2%。"
比如一个旅行助手 Agent:用户说"帮我规划去东京的行程",系统会依次调用:需求分析 Agent(解析意图)→ 机票搜索 Agent(调工具查航班)→ 酒店推荐 Agent(查酒店)→ 行程整合 Agent(汇总输出)。每个 Agent 背后是一个 LLM 推理调用(称为 stage),一个用户请求可能触发十几次甚至几十次 LLM 调用。这些 Agent 之间有 DAG 依赖关系,不同 Agent 可能用不同模型。
LLM 推理的输出长度变化极大:工具调用输出几十 token(JSON 格式),用户交互输出几百上千 token。输出长度直接决定 KV Cache 大小和 decode 时长。固定按最大长度预留会导致严重的显存浪费(利用率低),按平均长度预留则会 OOM。关键挑战是在请求开始前就要预测输出长度来分配资源,但这个预测不准就会出问题。
第一阶段是工具调用分类器(LightGBM),判断当前 stage 是否会触发工具调用(AUC 0.96)。第二阶段是输出长度回归器,在分类结果的基础上预测具体 token 数(MAE 165 tokens,R² 0.78)。分两阶段是因为输出长度呈双峰分布——工具调用短(几十 token),用户交互长(几百上千 token),单一回归器在双峰上表现差。分类器先识别模式,回归器在各自模式下预测更精准。消融实验去掉分类器后 MAE 从 134 升到 142。
多 Agent 场景下一块 GPU 需要同时驻留多个模型权重。设计了五层状态:Running(GPU 上可立即执行)→ Sleeping(权重在 CPU,但 GPU 保留 CUDA Graph/JIT 缓存约 0.5GB,恢复省 5-8 秒)→ CPU-resident → Disk-resident → Remote。Sleeping 状态是关键创新——保留 GPU 侧的 kernel 缓存避免重建开销。层级化 LRU 逐级淘汰,最热模型留 GPU,最冷退到远端。
用 CUDA Virtual Memory Management 实现地址和物理页分离。在 40GB A100 上分配 122GB 虚拟地址池(3 倍超配),物理页按需映射。三层防护防 OOM:(1) 虚拟地址不等于物理内存,多 Agent 的 KV 使用不会同时达峰(统计复用);(2) 每个 stage 进入前做准入控制,检查剩余物理页是否满足预测需求;(3) cuMemMap 失败时拒绝该 stage 而非崩溃。偏向高估(安全裕度 ρ),低估导致 OOM 的代价远大于高估浪费。
Stage 边界抢占是指只在两个 LLM 推理调用之间切换(一个 stage 完成后、下一个 stage 开始前),不打断正在 decode 的请求。Token 级抢占需要和推理引擎深度集成、做 KV Cache 迁移,工程复杂度极高。Stage 边界抢占只需更新元数据,实测效果已足够——交互排队延迟从 11 秒降到 2 毫秒。
Baseline 是 EDF(Earliest Deadline First),实时系统经典调度策略。SLO 定义为"交互式 stage 的 TTFT(首 token 时间)< 阈值"。在高负载下 EDF 因为没有预测信息,无法区分长短 stage,导致长 stage 阻塞短交互 stage(队头阻塞)。Maestro 用预测的剩余时间做 SRTF,加上工作流感知的优先级(交互式 > 批处理),SLO 达成率从约 60% 提升到 83.6%。
Trace 来自内部部署的多 Agent 应用平台,记录了每个 agent stage 的输入/输出 token 数、模型类型、时间戳。实验分为两部分:16 台 V100 做原型实测(端到端延迟、SLO 达成率),46,769 条 trace 做大规模仿真(64 卡级别)验证调度策略的扩展性。仿真器基于真实 trace 回放,关键参数(KV 内存增长、推理延迟)从原型实测校准。
DeepShare(IEEE Cluster 2026)简历追问
简历原文:"以连续的「配额保障度(QAD)」为统一运行时控制信号、协调弹性配额借用、预测调度和干扰感知共置四类决策的 Kubernetes 原生调度框架。QAD = 分配量/min(配额, 保障需求),经 EMA 平滑。空闲配额以 best-effort 借出(DRA),按 QAD+运行时预测做字典序排序,代价感知抢占。干扰感知共置用 RF 预测吞吐损失,MPS 共置无需改代码。23,859 条 Venus trace 仿真 GPU 利用率 70.6%(vs Lucid +29.5%),排队延迟降 46%;16 节点 64 卡 K8S 实测 JCT 降 34%,QoS 达成 93%。"
QAD = 已分配的 Guaranteed GPU / min(配额, 当前 Guaranteed 需求)。分母用 min(quota, demand) 很关键:如果租户 quota 32 但只需要 8 张,保障 8 张就是满足(QAD=1),不需要给满 32 张;如果租户提交 100 张需求但 quota 只有 32,保障 32 张就够(QAD=1),不会因为超额提交就认为系统欠它的。而"使用率"(usage/quota)不区分 Guaranteed 和 Best-effort,也无法区分"需求少"和"被欠服务"。EMA 平滑(λ=0.3)避免瞬时波动频繁触发抢占。
四类决策:(1) 弹性配额借用/回收(DRA)——QAD < 1 时回收 Best-effort 资源恢复保障;(2) 调度排序——Guaranteed 优先,QAD 低的租户优先,QAD 接近时短作业优先;(3) 抢占 victim 选择——抢占效率 Ej = (释放资源 × 剩余时间) / (1 + α × 抢占代价),选代价最小的 Best-effort 作业;(4) GPU 共置准入——QAD 高时允许更激进的 colocation(利用率优先),QAD 低时收紧(保障优先)。QAD 作为统一信号,让四个模块的决策方向一致——保障不足时偏向 QoS,保障充分时偏向利用率。
K8s 的 nvidia.com/gpu 是 Extended Resource,分配后不可修改。GPU 共享通过节点侧 MPS DaemonSet实现——每块 GPU 运行 MPS control daemon,允多个 CUDA context 共享 GPU,通过 per-client SM 限制(CUDA_MPS_ACTIVE_THREAD_PERCENTAGE)做算力隔离。Scheduler Plugin 在 Filter 阶段检查节点是否有足够空闲 SM 和显存来接纳新 Pod(基于干扰预测),允许后 Pod 调度到该节点,Node Agent 配置 MPS 限制。不需要扩展 K8s 资源模型,也不需要改用户代码。
特征来自 DCGM 硬件计数器:SM activity、memory bandwidth utilization、L2 cache hit rate、PCIe throughput 等——这些是框架无关的,不管你跑 PyTorch 还是 TensorFlow 都能采集。选 RF 三个原因:(1) 推理延迟 < 1ms,满足实时调度(DL 模型要 50-200ms);(2) R² = 0.902,精度足够;(3) 硬件计数器特征跨模型泛化,不需要每种架构重训。运行时持续监控实际 slowdown,超过动态阈值时驱逐低优任务。
Venus 是公司内部集群的作业 trace,包含 23,859 个深度学习作业的提交时间、GPU 需求、运行时长等信息。Trace-driven simulation 可以在可控环境下对比多种策略(对比 Lucid、Gandiva 等 baseline),控制变量。同时我们在 16 节点 64 卡的 K8s 原型上做了实测验证,证明仿真结论在真实环境中成立。大规模集群实测成本高且影响生产,仿真是学术研究的标准做法。
JCT = 排队时间 + 执行时间。调度优化主要影响排队时间,执行时间由计算量决定。当集群负载高时排队时间占比大,JCT 改善明显;负载低时改善小。34% 是平均 JCT 降低,排队延迟降了 46%,执行时间基本不变。GPU 利用率从 39.64% 提升到 70.6%(+29.5% vs Lucid),说明资源确实被更充分利用了——主要来自 DRA 借用空闲配额和干扰感知共置两块收益。
ElastiCo(Performance Evaluation 2026)简历追问
简历原文:"训推弹性混部(ElastiCo):面向训练与离线 LLM 推理在同一 GPU 上的安全共置,提出资源形态变换、弹性影子定价与干扰感知共置三项机制,以原生 Kubernetes 中间件形式实现、无需改动用户代码。64 卡实测与最高 512 卡仿真下,平均完成时间最高降低 2.94×、集群吞吐提升 2.02×、GPU 利用率由约 25% 提升至 46%。"
训练集群平均 GPU 利用率只有 25% 左右——训练任务在数据加载、梯度同步通信、checkpoint 保存时 GPU 是空闲的,这些空窗期加起来占了大部分时间。同时离线推理(如批量 embedding、离线评估)有明确 SLO 但不需要独占 GPU。把它们共置可以填补这些空窗,把利用率从 25% 提到 46%。为什么不分开跑?分开跑需要额外 GPU,而 GPU 是最贵的资源——共置用同样的硬件跑更多任务,直接降成本。
"形态"指 SM 算力和显存的分配比例随负载动态变化。互补性体现在:(1) 训练在 forward/backward 阶段 SM 利用率高(80-90%),在 dataloader/communication 阶段 SM 空闲;(2) 推理在 prefill 阶段突发 SM 需求,decode 阶段 SM 利用率低但占显存(KV Cache)。通过 MPS 动态调整 SM 比例+ VMM 弹性显存,可以在训练空闲时把 SM 让给推理 prefill,训练繁忙时收回 SM。这和 MIG 静态切分(固定 50/50)的区别是:MIG 切完就不变,ElastiCo 毫秒级动态调整。
给 GPU 上的 SM 和显存定一个动态价格,反映当前稀缺程度。价格由训练任务的实时 GPU 利用率和显存占用决定——训练越忙价格越高,训练空闲价格越低。推理任务有一个"价值"(SLO 优先级 × 剩余工作量),价值大于当前价格才允许共置。本质上是一个基于市场机制的准入控制:价格自动调节供需,比固定阈值灵活——高优推理在资源紧张时仍可进入(付高价),低优推理只在空闲时进入(付低价)。
DeepShare 解决的是多租户之间的配额管理(A 团队和 B 团队之间怎么借 GPU),合用对象是训练+训练;ElastiCo 解决的是同一 GPU 上训推的共置问题,两者在不同层级。而且训推共置有特殊挑战:训练是长作业、不能被杀(重启代价大),离线推理是短作业、可以被暂停/驱逐——这种主客不对称性是 DeepShare 没有的。两者可以组合:DeepShare 做集群级租户治理,ElastiCo 做节点级训推填充。
三层透明注入:(1) Admission Webhook 自动给 Pod 注入 MPS 环境变量和 VMM 配置;(2) Node Agent(DaemonSet)通过 CUDA Driver API 动态管理显存映射和 SM 限制,不经过用户代码;(3) Scheduler Plugin 在调度时做放置决策,用户只需给 Pod 打上 elastico.sh/class: training 或 inference 标签。底层用 LD_PRELOAD hook 部分 CUDA 内存分配 API 实现显存记账,对训练/推理框架完全透明。
25% → 46% 已经是将近翻倍的提升。为什么不是 70%+?(1) 我们有严格的 SLO 约束——训练 slowdown 不能超过阈值(约 10%),推理 SLO 必须达标;(2) 训练的空窗期不是完全可预测的,有时推理刚加载进来训练就开始计算了,需要保护训练;(3) 显存容量是硬约束——训练占了大部分显存(权重+梯度+优化器状态),推理的 KV Cache 和权重可用空间有限;(4) 46% 是安全共置下的利用率,牺牲部分利用率换 SLO 保证是合理的 trade-off。
SagePilot(撰写中)简历追问
简历原文:"结构感知的深度学习负载资源预测与 Agentic 工作流编排(SagePilot)。计算图表征:ONNX 计算图→图样本,融合算子类型、张量形状与拓扑结构。GNN 多目标预测:一次前向预测时延、显存峰值、GPU 利用率,免反复试跑。Benchmark:运行时程序分析自动采集,10W+ 条,覆盖 CNN/Transformer/推荐。工作流编排:冷启动预部署、OOM 风险选卡、显存复用与驱逐。"
Profiling 成本非常高:一个 7B 模型在 A100 上跑一次推理 profiling 需要几分钟到十几分钟,如果要测多个 batch size、序列长度、GPU 型号组合,可能需要几小时、占用多张 GPU。对于大模型(70B),profiling 本身就需要多卡,成本更高。而且在 Agentic 场景下,模型组合是动态的(用户请求决定用哪个模型),无法提前 profile 所有组合。SagePilot 通过 ONNX 图 + GNN 一次前向推理(毫秒级)就能给出多指标预测,零试跑成本。
ONNX 计算图天然就是 DAG——节点是算子(matmul、conv、layernorm),边是张量(带 shape 和 dtype)。GNN 的消息传递机制恰好模拟了张量在算子间的流动:每个算子节点聚合其输入张量的信息,类似实际执行时算子读入输入计算输出的过程。MLP/CNN 无法处理变长拓扑(不同模型节点数从几百到几万不等),GNN 天然支持。
共享 GIN backbone,三个独立 MLP 输出头分别预测时延、显存、利用率。训练时用 uncertainty weighting 自动平衡三个 loss。显存预测使用非对称 loss——低估的惩罚是高估的 3 倍,因为低估导致 OOM(请求直接失败),高估只是浪费显存(可接受)。预测结果加安全裕度 ρ ∈ [0.1, 0.3]。
这是个好问题。ONNX 静态图确实看不到推理引擎的 kernel fusion 策略,但我们做了补偿:(1) 训练标签来自真实执行的 profiling 数据,fusion 带来的加速已经隐含在标签里,GNN 会学习到哪些算子模式容易被融合;(2) 加入常见 fusion pattern 的特征(如 matmul+bias+gelu 的组合模式);(3) 对于特定引擎(TensorRT)可以加一个校准步骤,用少量 profiling 数据 fine-tune。当前 R² 在 0.8 左右,对资源调度场景足够。
跨论文追问(面试官可能串联提问)
贯穿几篇工作的核心理念是用轻量预测为调度器提供前瞻性信号,再设计弹性资源管理和代价感知抢占来利用这些信号。DeepShare 预测作业运行时间来做排序和抢占,Maestro 预测输出长度来做显存分配和 SRTF 调度,ElastiCo 用影子定价(本质也是基于利用率的预测)做共置准入,SagePilot 直接预测模型资源画像。共同模式是:(1) 识别可预测的信号;(2) 选择轻量、低延迟、可泛化的预测模型(LightGBM/RF/GNN,不用大模型);(3) 设计弹性机制利用预测信号获益,同时有安全兜底应对预测错误。
Kubernetes 已经是 GPU 集群管理的事实标准,生态成熟(device plugin、CSI、CNI、Prometheus 监控)。基于 K8s Scheduler Framework 做插件可以复用大部分基础设施(节点管理、Pod 生命周期、资源账本),只需要扩展调度逻辑,用户迁移成本低。DeepShare 和 ElastiCo 都是 Scheduler Plugin + Controller + DaemonSet 的架构,不侵入 kube-scheduler 核心代码,升级 K8s 版本时维护成本低。Crater 开源平台也是基于 K8s + Volcano,验证了这个路线的可行性。
四篇一作论文中我都是第一作者,负责问题定义、系统设计、核心算法实现、实验验证和论文写作。具体来说:DeepShare 中我设计了 QAD 指标和三个子系统的协同机制,实现了 K8s Scheduler Plugin 和 Controller 的核心代码,跑了 64 卡实测和 trace 仿真;Maestro 中我设计了两阶段预测器和 CUDA VMM 弹性显存管理,实现了节点级运行时和全局调度器;ElastiCo 中我提出了资源形态变换和影子定价机制,实现了训推共置的 K8s 中间件;SagePilot 中我设计了计算图表征方案和 GNN 多任务架构,搭建了自动化数据采集 pipeline。导师给方向指导,合作者协助部分实验对比。
几个明确的局限:(1) 预测模型都需要训练数据,新场景/新硬件冷启动需要少量 profiling 数据做校准,未来方向是用 transfer learning 减少冷启动成本;(2) ElastiCo 目前只支持离线推理和训练共置,在线推理有严格 TTFT 要求,共置风险更大;(3) DeepShare 的 colocation 用 MPS 做 SM 隔离,但 MPS 不支持显存硬隔离(只是建议值),极端情况下一个任务可能撑爆显存影响另一个;(4) SagePilot 的 GNN 在超大规模计算图(>10万节点)上推理延迟可能成为瓶颈,需要子图采样或层次化预测。
核心思想一脉相承:都是在固定配额基础上做弹性资源借用和抢占回收。实习项目解决的是工业界真实问题——GPU 按团队固定分配导致 400 张卡闲置但其他团队排队,我设计的跨团队 Spot 资源动态分配和多维约束抢占回收算法,本质上和 DeepShare 的 DRA + 代价感知抢占是同一类问题。区别是工业界有更复杂的业务约束(ABC 多级优先级、MySQL + Redis 存储、Thrift RPC 对接 Merlin),而论文可以更干净地做形式化和算法设计。实习反过来也验证了论文中的弹性配额和抢占思路在生产环境是有实际需求的。
面试官"挑刺"与陷阱题
面试官可能用挑战性问题试探你对自己工作的理解深度——不是真的否定你,而是看你是否思考过弱点。这些问题如果没准备过很容易卡壳。
这个问题很尖锐。需要分清两个层面:(1) 预留(reservation)≠ 实际使用。传统方案为每个请求预分配最大 KV 空间(物理显存),即使实际输出很短也占着不放——这是真正的浪费。CUDA VMM 让虚拟地址远大于物理显存,但物理页按需映射,真正减少的是物理显存占用。(2) 67.2% 降低的是预留的 HBM 物理显存,不是虚拟地址。我们通过输出长度预测来决定实际映射多少物理页,短请求只映射少量物理页,其余虚拟地址不占物理内存。统计复用的前提是多 Agent 的 KV 峰值不重叠。如果所有请求同时输出长文本还是会 OOM,但实际 trace 中这种概率极低,且有准入控制兜底。
这是所有预测驱动系统都要面对的问题。我们做了三层防护:(1) 偏向高估——训练 loss 对低估加惩罚(类似 SagePilot 的非对称 loss),预测值偏高而不是偏低,宁可浪费不能 OOM;(2) 动态扩容——KV 内存在 decode 过程中按页增长(paged attention 类似 vLLM 的思路),不是一次分配完,如果实际输出超过预测,运行时可以追加映射物理页;(3) 优雅降级——如果物理内存真的耗尽,选择抢占/暂停优先级最低的 stage 释放空间,而不是让整个服务崩溃。预测准确率 R²=0.78 看起来不高,但配合安全裕度和动态扩容,实际 OOM 率 < 0.1%。
R²=0.902 是在离线测试集上的指标,真正运行时我们不依赖单点预测做决策,而是:(1) 保守准入——预测 slowdown < 5% 才允许共置,留出足够安全边界;(2) 运行时闭环——共置后持续监控实际 slowdown(通过 DCGM 实时采集 SM 利用率),一旦实测 slowdown 超过阈值(如 10%)立即驱逐 Best-effort 任务,反应时间在秒级;(3) 只对 Best-effort 任务冒险——Guaranteed 任务的资源绝不用于共置,只有空闲配额借出的 Best-effort 任务才参与共置,预测错误最坏情况是杀掉 Best-effort 任务,不影响 Guaranteed QoS。
这是学术研究的通用方法论局限。我们做了几件事增强可信度:(1) Trace 来自真实生产集群(Venus 23,859 条作业、Maestro 46,769 条 stage),不是合成数据;(2) 仿真器参数从 16 节点原型实测校准,保证仿真结果和真实环境趋势一致;(3) 64 卡 K8s 实测验证了关键结论(端到端 JCT、SLO 达成率),仿真主要用于验证大规模扩展性;(4) ElastiCo 做了 512 卡仿真看 scaling 趋势;(5) 字节实习中验证了核心算法思想在生产环境的可行性——弹性配额借用和代价感知抢占在工业界确实能落地。当然,真正部署到几千卡集群还需要更多工程鲁棒性工作,这也是未来方向。
这是不同层面的优化:vLLM/TGI 优化的是单节点内推理引擎的 batching 和 KV 管理(PagedAttention 解决内部碎片、continuous batching 提高 GPU 利用率),Maestro 解决的是多节点、多模型、多 Agent 工作流的调度问题——一个用户请求涉及十几个 Agent stage、用多个不同模型、分布在多块 GPU 上。Maestro 可以和 vLLM 配合使用:节点内用 vLLM 做推理引擎优化,节点间用 Maestro 做工作流感知调度和显存管理。事实上我们的原型就是基于 vLLM 做的,分级权重缓存和 CUDA VMM 超配是在 vLLM 之上的额外优化。
EDF 是实时调度的经典 baseline,但我们的对比不只是 EDF。Maestro 对比了 EDF、SRTF(无预测)、FCFS、Karma(LLM 服务最近的调度工作);DeepShare 对比了 Lucid(GPU 共享最强无侵入基线)、Gandiva(协同调度)、Tiresias(GPU 调度经典工作)、K8s 默认调度器。关键是 Maestro 的核心贡献不是调度算法本身(SRTF 是经典算法),而是把预测信号引入 LLM-MAS 场景并设计弹性显存机制来利用这些预测。和纯算法 baseline 比是为了证明预测信号的价值,而不是发明新的排序算法。
确实,MPS 的一个已知风险是故障隔离差。我们的应对:(1) 只在受控环境下使用 MPS 共置——Best-effort 任务和 Guaranteed 任务共置时,Best-effort 任务是经过准入检查的(短作业、已知模型类型),减少未知风险;(2) 每个 GPU 节点上跑 MPS health monitor,检测到 MPS server 异常立即重启并隔离该节点上的新任务调度;(3) ElastiCo 场景下训练任务直接跑在 GPU 上(不经 MPS),推理任务通过 MPS 共享 SM,训练故障不依赖 MPS;(4) 对于生产环境,长期方案是用 MIG 或时间片(MPS 属于进程级共享,MIG 是硬件级隔离),但 MIG 不支持动态 SM 划分,ElastiCo 的动态资源形态变换目前只能通过 MPS 实现。
Crater 开源平台追问
简历原文:"主导基于 Kubernetes 的 GPU 集群管理平台 Crater...已在实验室稳定运行 1.5 年,纳管 250+ 张 GPU、日均调度 200+ 任务,Apache-2.0 开源。"这是工程能力的重要证明。
Volcano 提供了队列、优先级、gang scheduling 等基础能力,但它是通用的批调度器,缺少科研场景需要的功能:(1) 配额管理是硬划分,没有 DeepShare/ElastiCo 那种弹性借用;(2) 没有用户管理、审批流程、账户计费——科研集群需要导师审批学生的 GPU 使用;(3) 没有一键 LLM 训练/推理的作业模板,用户要写完整 YAML;(4) 没有集成 Jupyter/WebIDE/终端开发环境,科研用户需要交互式开发。Kubeflow 更偏 ML pipeline,不是集群管理平台。Crater 在 Volcano 基础上做了面向科研场景的封装和增强,整合了 DeepShare 和 ElastiCo 的调度能力,提供 Web 控制台降低使用门槛。
最头疼的是多用户场景下的 GPU 资源争用和占卡不释放问题。实验室场景下学生经常启动 Jupyter 后忘记关,GPU 被占着但利用率为 0。我们做了:(1) 占卡检测——Agent 监控 GPU 利用率,连续 N 分钟低于阈值就通知用户,超时自动回收;(2) 交互式任务有最长运行时间限制(默认 12 小时,可以续期);(3) 训练任务必须在容器内跑,容器退出自动释放资源;(4) 空闲 GPU 标记和自动推荐。另外一个挑战是多型号 GPU(A100/A800/3090/4090/V100 混合),不同作业对 GPU 型号有不同要求,调度器需要感知拓扑和型号约束。
我是项目负责人,核心后端(Go)大约 70% 是我写的,包括自定义 Controller、Scheduler Plugin、API Server、配额管理逻辑;前端(React/TypeScript)主要是两个师弟做的,我做了架构设计和 Code Review;Helm Chart 和部署脚本是我写的。最复杂的部分是调度器和 K8s controller 的设计——队列状态机、配额超分/回收逻辑、和 Volcano 的协同、多维度抢占顺序的正确性保证。调试调度器问题非常痛苦,因为状态分布在 etcd、scheduler cache、node agent 多处,需要全链路 tracing。
论文间深层关系与体系化思考
面试官喜欢问"你的几篇论文之间是什么关系"——这考察你是否有体系化的研究视角,而不是零散地做了几个项目。
是从实践中逐步演进出来的,不是一开始就规划好的。最早做 Crater 平台(2023)时发现真实 GPU 集群利用率只有 25-40%,于是做了 DeepShare 解决多租户配额借用问题(集群级);在 DeepShare 实测中发现训推混部是更大的利用率提升空间,而且有独特的主客不对称挑战,于是做了 ElastiCo(节点级训推);同时在 LLM Agent 场景下发现输出长度不确定是全新的调度挑战,做了 Maestro(请求级 LLM 推理);在所有这些工作中反复遇到一个痛点——资源画像预测不准,需要 profiling,于是做 SagePilot(预测底座)。回头看形成了从集群→节点→请求→预测的逐层深入,但当时是跟着实际问题走的。
这是个好问题。分层架构:(1) 预测层(SagePilot)——所有上层决策的基础,提供作业/模型/请求级别的资源画像预测,不需要运行就能给出时延、显存、利用率估计;(2) 集群调度层(DeepShare)——基于 QAD 做多租户配额管理、弹性借用、全局排序和抢占决策,决定作业放到哪个节点;(3) 节点运行时层(ElastiCo + Maestro)——在节点内做精细资源管理:训推共置用 ElastiCo 的资源形态变换和影子定价,LLM 推理用 Maestro 的分级权重缓存和 CUDA VMM 弹性显存,stage 边界抢占。Crater 是产品形态,把这些能力封装成用户友好的平台。共同的设计原则:预测驱动、弹性资源、代价感知、安全兜底。
几个原因:(1) 工业界优先稳定性——预测驱动调度如果预测出错会产生线上事故,工业界倾向用简单确定性策略(优先级队列+固定配额),学术界更愿意用预测换效率;(2) 工作负载差异——我们的场景是科研集群+LLM Agent,负载波动大、任务类型多样,弹性收益明显;而大厂在线服务集群负载规律,弹性空间小;(3) 工程复杂度——MPS 共置、CUDA VMM 超配、干扰预测都需要精细的工程实现和监控,大厂有更成熟的隔离方案(如 MIG、物理分区);(4) 但趋势是工业界也在往这个方向走——字节内部的跨团队 Spot 调度、云厂商的 GPU 共享(如阿里云 cGPU、腾讯 qGPU)本质上都是弹性配额和精细隔离。我们的工作提供了算法和机制上的验证。
ESCAPE 是我硕士阶段做的微服务资源估算工作,用 GNN + Profiling Engine 预测微服务的资源需求。这是我第一次接触"用 ML 做资源预测"这个方向,GNN 的使用经验直接启发了 SagePilot 的计算图表征思路——微服务调用图和 DNN 计算图在结构上都是 DAG,都可以用 GNN 建模;Profile Engine 的经验让我意识到 profiling 成本问题,才有了 SagePilot "零试跑预测"的动机。可以说 ESCAPE 是 research line 的起点,后面的 DeepShare/Maestro/ElastiCo 都需要预测信号,SagePilot 是回到预测这个基础问题上做深度工作。
压力面与行为题(结合论文经历)
面试官可能在技术讨论中穿插行为面试问题,用你的论文经历来考察软素质。这些问题需要用 STAR 法则回答。
(STAR 示例)S: DeepShare 做 64 卡实测时,干扰预测模型在实验环境精度很高(R²=0.9),但部署到真实集群后预测完全不准,共置任务频繁 slowdown 超阈值。T: 需要在不重写系统的前提下找出原因并修复。A: 我花了两周时间排查:(1) 先加详细日志记录每次共置的特征和实际 slowdown;(2) 发现实验环境用的是同一类型 GPU(A100),但真实集群有多种型号 GPU 混用,DCGM 指标在不同型号上的分布差异很大;(3) 训练数据只覆盖了 A100,没有做跨 GPU 泛化。解决方案是为每个 GPU 型号训练独立的 RF 模型,并加入 GPU 型号作为特征,同时引入 online fine-tuning——新的共置数据持续更新模型。R: 修复后跨型号预测 R² 恢复到 0.85 以上,共置 QoS 达标率从 60% 回升到 93%。这个教训让我在后续 ElastiCo 和 SagePilot 中都提前考虑了跨硬件泛化问题。
我会先做小实验验证而不是直接反驳。例如最初导师建议在 DeepShare 中用强化学习做调度决策,我做了 literature review 后发现 RL 在调度场景的 sample efficiency 很低,真实集群无法承受在线探索的代价。但我没有直接否定,而是用一周时间做了个小 prototype:用 DQN 在仿真环境训练,对比 RF + 启发式规则的方案,结果 RL 收敛慢、调参困难、泛化差。带着数据和导师讨论,最终改用 RF 干扰预测 + 启发式排序的方案。我觉得导师给方向是大方向指引,具体技术选型需要自己用实验验证,用数据说话比争论更有效。
这确实是博士期间的挑战。我的方法:(1) 串行深入、并行维持——一个时间段主攻一个项目(做核心实验和写作),其他项目只做基础推进(每周开一次会、review 合作者进度);(2) 复用基础设施——四个项目共享 Crater 平台、trace 采集 pipeline、K8s 部署脚本,避免重复造轮子;(3) 借助合作者——ElastiCo 有师弟帮忙做部分实验对比,SagePilot 的 ONNX 解析和图特征工程有一个本科生协助,我专注核心算法设计和论文写作;(4) 按截止日期排列优先级——会议截稿日期前 2 个月集中全部精力在那篇论文上。关键是识别项目之间的依赖关系(比如 SagePilot 的预测能力反过来可以增强 Maestro),让它们互相促进而不是互相竞争。
最满意 DeepShare。原因:(1) 从问题到落地完整闭环——它是从 Crater 平台真实问题出发,经过 QAD 指标设计、系统实现、64 卡实测、开源验证完整走通的,不只是算法创新,而是真正在 250 卡集群上跑了一年多的系统;(2) 工程和研究的平衡最好——QAD 指标虽然简单,但统一协调四个子系统的设计很优雅,工程实现也足够扎实(Scheduler Plugin + Controller + DaemonSet 架构);(3) 反馈最好——在实验室落地后确实解决了 GPU 争抢问题,同学们的作业等待时间明显缩短,这种"真的有人在用"的感觉比论文中稿更有成就感。Maestro 的 LLM 场景更新颖,但 DeepShare 是我从系统思维到工程能力成长最多的一篇。
帮助很大,让我从底层理解了 AI 芯片的执行模型:(1) 做算子适配时需要理解 chip 的内存层次(SRAM/DRAM/片上缓存)、并行方式(多核/向量/张量核)、算子切分和 fusion 策略,这让我后来在做 GPU 调度时能从硬件特性出发思考问题——比如为什么 SM 和显存是两种不同资源、为什么 kernel fusion 会影响 SM 利用率、为什么 MPS 的 SM 比例调整不能太频繁;(2) C++ 底层调试经验让我在做 CUDA VMM、MPS 配置、LD_PRELOAD hook 时不怕碰底层;(3) 国产芯片的适配经历让我对硬件异构性有直观感受,后来 SagePilot 做跨 GPU 泛化时我就知道不同硬件的 performance counter 含义和分布差异很大。
场景题:如果面试官问"你来我们团队会怎么做"
几个直接相关点:(1) GPU 利用率优化——我在 DeepShare/ElastiCo 中做的弹性配额、干扰感知共置、训推混部可以直接应用于提高集群利用率,字节实习中已经验证了类似思路在生产环境可行(400 张空闲卡问题);(2) LLM 推理系统——Maestro 的输出长度预测、分级权重缓存、CUDA VMM 弹性显存思路可以优化 LLM 推理服务的显存利用率和 TTFT;(3) K8s 调度器开发经验——我有从零写 Scheduler Plugin、Controller、DaemonSet 的实战经验,不需要 Ramp-up 就能上手 K8s 相关开发;(4) 性能预测能力——SagePilot 的 GNN 预测思路可以用于作业调度前的资源预估、容量规划、自动扩缩容决策;(5) 工程能力——Crater 250 卡开源平台的经验证明我能把研究原型推进到生产级可用系统。