想象一家大型综合医院:手术室是全院最宝贵的资源,每一间都排满了择期手术——关节置换、胆囊切除、白内障……突然,120 救护车拉来一位急性心肌梗死病人,心电监护仪在尖叫。主刀医生必须做出选择:暂停一台正在进行的常规手术,把手术室让给抢救。但被暂停的手术台上还开着腹腔,绝不能丢下不管——麻醉师记录当前用药剂量,主刀护士清点器械数量,巡回护士在病历上写下“切至第 3 层组织、止血完善”。等抢救结束,医生回到这台手术,照着记录无缝续做。 GPU 集群的抢占式调度,演的就是这出医院大戏。GPU 是手术室,训练任务是排队等手术的病人;有紧急微调、事故驱动的模型回滚(急诊),也有日常实验、数据批处理(择期)。调度器要回答五道题:什么时候该抢?抢谁最划算?被抢任务怎么记住进度?普通任务会不会永远轮不上?以及——在 Slurm 和 K8s 集群里到底怎么配?这篇文章用贯穿始终的“医院急诊”比喻,把这五道题逐个讲透。
抢占式调度是共享 GPU 集群公认的“硬骨头”。掌握触发条件、检查点、SLA 保护与两大集群的配置实践,你就能在千卡集群里既保住紧急任务的时效,又不让常规任务饿死——这是 AI 平台工程师升职加薪的必修课。
可视化演示
交互展示抢占触发条件、三种抢占策略对比和检查点恢复机制,理解多租户环境下的资源调度与SLA保障
本节配有交互动效(进入视口后自动加载,约 3KB)。
抢占触发 高优先级任务提交 调度器检测资源不足 低优先级任务被抢占释放资源
抢占触发条件
急诊分诊台上,护士手握电话:120 报告三分钟后送来一位心梗病人。分诊护士要回答一个关键问题——现在就要清空手术室,还是先等等?答案取决于两条硬指标:新病人是否比正在手术的病人危急得多?手术室门口的常规病人是否已经等了太久、再拖要出医疗事故?
GPU 集群的调度器也在做同样的分诊。它以事件驱动的方式监听任务状态变化,抢占触发条件归结为三类:高优任务插队、排队超时提升和人工优先级调整。高优任务插队是最常见的触发点——当一个新的高优任务提交,且当前所有 GPU 都被占用时,调度器会比较新任务与运行中任务的优先级。注意,不是“新任务优先级更高就抢”,而是必须高出一个阈值 Δ。这个阈值是防抖设计:集群里任务进进出出,优先级波动是常态,设太小会导致调度器频繁打断任务,检查点开销甚至超过抢占收益。
排队超时提升是防止任务“饿死”的第二道保险。一个低优任务如果在队列里等待超过 SLA 承诺的上限(比如 2 小时),系统会动态上调它的优先级,直到它能抢占一个 GPU。这相当于分诊台承诺:“普通病人等待不超过 4 小时,超时自动升级为加急。”人工调整则是管理员用命令把某个任务标记为紧急,对应救护车直接打电话指定手术室。
分诊台最后给出结论:抢不抢,不是看心情,而是看两条量化指标的“或”运算。急诊通道的大门,始终由规则把关,而不是调度员拍脑袋——这正是抢占式调度在工业集群里能被信任的前提。
- 新任务优先级$\text{prio}_{\text{new}}$ 表示新提交任务的基础优先级,数值越大越紧急,由用户提交时指定。
- 运行中任务优先级与阈值$\text{prio}_{\text{running}}$ 是当前占用 GPU 的任务优先级,$\Delta$ 是防抖阈值,避免轻微优先级差异就触发抢占。
- 逻辑或门$\lor$ 符号表示“两者任一成立即可”,任何一边满足,抢占触发条件就为真。
- 排队超时判定$T_{\text{wait}} > T_{\text{SLA}}$ 比较任务实际排队时间与 SLA 承诺上限,超时则触发“排队升级”机制。
抢占策略设计
急诊科主任面临一个更棘手的抉择:手术台上有两台常规手术,一台刚开腹 10 分钟,另一台已经缝合到最后一层。现在必须腾出一间手术室抢救心梗病人——停哪台?答案显而易见:停缝合到一半的那台太可惜,不如停刚开腹的。
这就是抢占策略设计的核心:决定“抢谁”以及“怎么抢”。业界有两大模式:全抢占(Preemption)和半抢占(Graceful Preemption)。全抢占简单粗暴——调度器立刻杀掉或挂起低优任务,把资源让给高优任务,适合任务有完善检查点、抢占成本低的场景。半抢占则像医生缝合完最后一针再下台——给被抢占任务一个宽限期(Grace Period),允许它把当前迭代跑完、保存检查点后主动退出,适合无法强制中断的场景。Slurm 里的 CANCEL/REQUEUE 对应全抢占,CHECKPOINT 模式则更接近半抢占。
选定模式后,还要选受害者。调度器不会随机挑一个任务下手,而是计算每个候选任务的抢占代价:运行进度越多,被夺走时浪费的计算量越大;优先级越高,动它引发的“民愤”越大。所以最优受害者往往是“进度少、优先级低”的任务——就像急诊医生选择开腹不久的病人,而不是缝合到一半的病人。
急诊科的智慧在于:抢救不是把手术室掀个底朝天,而是精确选择代价最小的停台方案。集群管理员配置抢占策略时,本质上就是在给调度器写一本“停台手册”——明确哪些台子可以停、停之前给多少时间穿针引线。
- 运行进度占比$\text{progress}(v)$ 是候选任务 v 已完成的工作量(如已训练步数),进度越高,剥夺它浪费的计算越多。
- 检查点保存开销$\text{ckpt\_cost}(v)$ 是把任务 v 当前状态固化到磁盘所需的时间与存储成本,是抢占时必须额外支付的“账单”。
- 优先级权重$\text{prio}(v)$ 放在分母上,说明任务的优先级越高,清算代价时折扣越大——高优任务几乎不会被当作受害者。
- 分子系数 α$\alpha$ 是进度敏感系数,用于调节“已做工作”与“检查点成本”之间的权重比例。
检查点机制
被暂停的手术为什么能无缝续接?因为主刀医生留下了详细的手术记录:切到第几层、出血量多少、缝了几针、用了哪种麻醉。没有这份记录,重新打开腹腔等于从零开始,病人白挨一刀。
GPU 任务的“手术记录”就是检查点(Checkpoint)。它是一份完整的训练状态快照,通常包含四类内容:模型权重、优化器状态(如 Adam 的一阶二阶动量)、当前 epoch 和步数、随机数生成器种子及学习率调度器状态。缺了任何一项,恢复后的训练就“失忆”——要么精度异常,要么数据顺序错乱。这就是为什么框架广泛采用 torch.save 与 torch.load 配合 model.state_dict() 与 optimizer.state_dict() 落盘的原因。
检查点的保存频率是个权衡艺术。存太频繁,IO 开销拖慢训练——假设每 10 分钟存一次、每次花 30 秒,训练有效时间就少了 5%;存太稀疏,一旦被抢占,丢失的进度太多。工业界常用的做法是周期快照 + 异步落盘:每 N 个 step 触发一次内存快照,再用后台线程写入分布式文件系统。恢复流程则像一个标准抢救预案:加载权重 → 装载优化器状态 → 恢复随机种子 → 续跑。断点续跑的恢复时间完全取决于检查点加载的 IO 速度。
手术记录越详细,抢救后恢复越快;但记录本身也占用医生时间。GPU 集群的检查点设计就是在这对矛盾中找平衡——让“病历”足够细,又不至于让医生光顾着写病历忘了做手术。
- 加载时间$T_{\text{load}}$ 是从共享存储读回检查点文件的时间,取决于文件大小与存储带宽。
- 恢复时间$T_{\text{resume}}$ 是重建优化器状态、重置随机种子到正确步数的时间,通常远小于加载时间。
- 单次保存时长$T_{\text{ckpt}}$ 是生成一次快照并落盘所花的时间,是检查点的“单次成本”。
- 保存间隔$T_{\text{interval}}$ 是两次检查点之间的训练时长,间隔越短,潜在进度损失越小但开销越高。
保护与SLA
急诊室的秩序不能失控:如果救护车一辆接一辆地送来病人,普通门诊的病人是不是永远排不上手术?医院对此有明文规定——择期手术病人等待超过一定时限,必须安排手术,哪怕要临时加台。这条规定,就是医院的"SLA"。
GPU 集群里,SLA 保护是抢占式调度的刹车片。没有它,低优先级任务可能被反复抢占,“饿死”在队列里——永远无法完成,GPU 浪费在反复保存与恢复检查点上。三种常见保护机制构成了护栏:最小运行时间保障,任务一旦开始运行,在至少 X 分钟内禁止被抢占,相当于手术后病人入住恢复室,不会被立刻赶走;排队超时升级,低优任务排队超过 SLA 上限后自动提权,保证它能抢到资源;抢占次数上限,单个任务在一天内最多被抢占 K 次,超过后调度器拒绝再抢它——相当于合情合理的“免死金牌”。
此外还有配额与权限控制:不是任何用户都能提交高优任务。集群通过优先级配额(如 Slurm QOS 的 GrpTRES、K8s 的 ResourceQuota)限制高优任务的总量,防止有人滥用急诊通道。SLA 的量化指标通常是任务排队时间 P95 分位数:系统承诺 95% 的任务等待时间不超过规定值,剩余的 5% 允许超限。
急诊室不会让普通病人等到天荒地老。SLA 保护的实质,是把“不饿死任何人”从道德口号变成可量化的数学约束——这是共享 GPU 集群在多团队协作中维持信任的基石。
- 等待时间随机变量$T_{\text{wait}}$ 是一个任务从提交到真正运行的总等待时长,受队列长度、抢占频率影响。
- 概率符号$P( \cdot )$ 表示括号内事件发生的概率,对抗的是“任务排队过长”这一随机事件。
- 超限概率上限$\leq 0.05$ 是硬性指标,意思是 95% 的任务等待时间必须小于 $T_{\text{SLA}}$。
Slurm配置实践
医院的信息系统里,每个科室都有应急响应等级:急诊科最高,门诊部最低。Slurm 就像这套信息系统——管理员在配置文件中定义谁有资格抢占、怎么抢。
Slurm 抢占调度的第一站是 slurm.conf 的全局配置。PreemptType 指定抢占插件,常用 preempt/qos(按 QoS 优先级抢占);PreemptMode 决定抢占动作:OFF 完全关闭,CANCEL 直接取消低优任务,REQUEUE 取消后让任务重新排队(无检查点则从头跑),CHECKPOINT 先保存检查点再抢占——生产环境推荐 REQUEUE 或 CHECKPOINT。
第二站是 QOS 关联:每个任务队列(Partition)绑定指定的 QoS,QOS 里配置 Priority 数值或 GrpTRES 资源上限。高优 QOS 的任务可以抢占低优 QOS 的任务,优先级数值差满足 PreemptExemptTime 的豁免规则——任务运行超过豁免时间后不再接受抢占。最后,禁止抢占的配置用 PreemptExemptTime 或单独设置任务的 --no-requeue 标志实现,相当于给重要任务贴“免打扰”标签。
管理员在 Slurm 里的工作,就像给医院各科室设定响应等级:急诊科随时可以叫停门诊,但门诊病人等久了也会自动升级。配置的关键是先想清楚业务优先级分层,再落成 QOS 数字——而不是等出了事故才手忙脚乱。
- QOS 基础分$\text{QOS}_{\text{prio}}(j)$ 是任务所属 QoS 层级的初始分数,数值越高,在抢占博弈中越占优。
- 排队老化加分$w_a \cdot \text{Age}(j)$ 是队列等待时间带来的加分,等待越久分数越高,防止长期饥饿。
- 资源大小加分$w_s \cdot \text{Size}(j)$ 是任务申请资源规模带来的加分,大任务对集群调度影响更大,因此也更容易被提前调度。
K8s配置实践
如果说 Slurm 是老牌三甲医院的信息系统,K8s 就是互联网医院的新架构——一切都是声明式配置,调度器像 AI 分诊机器人一样自动化运作。
K8s 的抢占机制核心是 PriorityClass 资源对象。管理员先定义一个调度优先级类(如 high-priority 值 1000),Pod 通过 priorityClassName 引用它。调度器为每个待调度 Pod 计算优先级数值;当高优 Pod 无法找到满足资源需求的节点时,就会进入抢占流程:找出所有可能腾出资源的低优 Pod,驱逐它们,让高优 Pod 落座。preemptionPolicy 参数可以设置 Never,表示该 PriorityClass 的 Pod 永不抢占别人,只做排队等待。
K8s 的驱逐比 Slurm 更温和——遵循 PDB(PodDisruptionBudget) 保护,确保每次驱逐不会让某个服务的副本数低于红线;真正的驱逐动作是向 kubelet 发送优雅终止信号,给 Pod 留出退出时间,运行中的进程收到 SIGTERM 后可以尝试保存状态。这就是 K8s 的“半抢占”底色。
K8s 的抢占哲学和急诊室一样:不动最危重的病人,专挑已完成治疗、即将出院的床位周转。POD 被驱逐不是灾难——弹性本来就是云原生的底色,而抢占只是让资源流动得更聪明。
- 受害者集合$\text{victims}$ 是候选节点上可以被驱逐的 Pod 集合,排除受 PDB 保护的 Pod。
- 优先级倒数$\frac{1}{\text{prio}(v)}$ 让低优 Pod 贡献更高的分数,驱逐它们对集群的“冲击”最小。
- 求和累加$\sum$ 把所有受害者的得分加总,总分数越高的节点越优先被抢占腾退。
平衡与调优
医院院长站在月中复盘会上:急诊抢救成功率是高了,可普通门诊的手术量下滑了 20%,医生们抱怨手术台被反复打断。这就是抢占式调度的永恒课题——平衡。
调优的量化目标是一个多目标优化问题:最大化 GPU 利用率(U),最小化任务平均等待时间(T_wait),同时控制抢占频率(f_preempt)。三者互相牵制:抢占太激进,高优任务爽了,但检查点开销吃掉利用率;抢占太保守,低优任务不饿死了,但紧急任务被堵在队列里。工程实践通常用加权评分法,给三个目标配权重系数 α、β、γ,再滚动观察指标曲线。
具体调优手段包括:调整抢占触发阈值 Δ(防抖),修改检查点间隔(IO 开销与进度损失的折中),设置宽限期长短(半抢占的耐心程度),以及微调 SLA 上限。推荐做法是在测试集群上回放历史任务日志,比较不同参数组合下的目标函数值——就像医院用过去一年的急诊数据做仿真,而不是直接拿病人做实验。
没有放之四海皆准的参数,只有持续观测、小心调优的耐心。医院院长最终发现:把急诊通道拓宽一点,同时给门诊安排“最长等待不超过 3 小时”的承诺,整体满意度反而最高——抢占式调度的艺术,正是在冲突的目标之间找到那道最优的窄门。
- 利用率$U$ 是所有 GPU 实际计算时间占比,越高代表硬件越不闲着,是集群收益的基础。
- 平均等待时间$\bar{T}_{\text{wait}}$ 是任务从提交到运行的平均排队时长,越低用户体验越好。
- 抢占频率$f_{\text{preempt}}$ 是单位时间内发生过抢占的次数,过高说明配置太激进。
- 权重系数$\alpha, \beta, \gamma$ 是管理员对三个维度的偏好权重,优先保交付就调大 $\beta$。
AI 应用场景
场景一:共享 GPU 集群的高优任务保障
阶段:模型训练与资源调度
解决的问题:在多人共享的 GPU 集群中,算法团队日常跑实验占满了所有卡;突然出现线上事故,需要紧急重新训练一个模型做模型回滚,传统方式只能干等排队,错过黄金修复时间。抢占式调度让紧急训练任务直接插队,几分钟内开始计算。
具体案例:某大厂推荐系统广告模型出现线上效果回退,算法负责人提交一个优先级为 100 的紧急微调任务(训练时长 20 分钟),调度器立刻抢占 8 张正在跑离线数据清洗的低优 GPU,保存检查点后让出资源。紧急任务 18 分钟跑完,模型快速上线止血,低优任务随后无缝恢复。
场景二:大模型紧急微调的“插队抢救”
阶段:大模型微调与部署
解决的问题:大模型微调动辄上百 GPU·小时,如果被低优任务占着卡,紧急的合规修改或安全对齐任务无法及时执行。抢占式调度配合检查点,能在大规模任务之间实现“安全换挡”。
具体案例:某机构正在用 64 张 A100 跑一周的 Llama 3 继续预训练,突然监管要求模型输出内容在 24 小时内完成安全对齐。管理员提交高优微调任务,Slurm 触发 CHECKPOINT 抢占,继续预训练任务保存检查点后让出 32 张卡;微调完成后继续预训练从断点恢复,全程人工干预不超过 10 分钟。
场景三:跨团队共享集群的 SLA 管理
阶段:资源治理与成本核算
解决的问题:公司内部多个业务线共享 GPU 集群,业务线之间优先级不清晰,经常发生“高优任务堵死低优任务”的口水战。用优先级分层配合 SLA 超时升级,让每个团队都有明确的交付预期。
具体案例:某公司把集群分为 P0/P1/P2 三级,P0 是线上紧急任务,P1 是日常训练,P2 是离线评测。P2 任务排队超过 4 小时自动升为 P1 进入抢占队列;每个团队每月提交 P0 任务的配额为 200 卡·小时。三个月运行后,P2 任务的平均等待时间从 9 小时降到 3.5 小时,高优任务的资源保证率提升到 99%。
Python 演示
import heapq class Job: """模拟一个 GPU 训练任务""" def __init__(self, name, priority, submit_time, duration): self.name = name self.priority = priority # 数值越大越紧急 self.submit_time = submit_time self.duration = duration self.progress = 0.0 # 已完成 GPU 时长 self.checkpointed = 0.0 # 已保存的检查点进度 def remaining(self): return self.duration - self.progress def __repr__(self): return (f"{self.name}(prio={self.priority}, " f"progress={self.progress:.1f}/{self.duration})") def preemptive_schedule(jobs, gpu_count=1, dt=0.5): """逐帧推进抢占式调度, 返回事件时间线""" queue = [] # 元组(-priority, submit_time, job) gpus = [None] * gpu_count timeline = [] time = 0.0 idx = 0 jobs = sorted(jobs, key=lambda j: j.submit_time) while idx < len(jobs) or queue or any(gpus): # 提交到点的新任务 while idx < len(jobs) and jobs[idx].submit_time <= time: job = jobs[idx] heapq.heappush(queue, (-job.priority, job.submit_time, job)) idx += 1 # 抢占判定: 队头任务比运行中任务更紧急则抢占 if queue: top_prio = -queue[0][0] for gi in range(gpu_count): g = gpus[gi] if g is not None and top_prio > g.priority: g.checkpointed = g.progress gpus[gi] = None heapq.heappush(queue, (-g.priority, g.submit_time, g)) _, _, attacker = heapq.heappop(queue) gpus[gi] = attacker timeline.append( (time, f"抢占: {attacker.name}拦截了{g.name}")) break # 运行与恢复: 空槽位弹队列, 正在运行则推进 for gi in range(gpu_count): if gpus[gi] is None: if queue: _, _, nxt = heapq.heappop(queue) nxt.progress = nxt.checkpointed gpus[gi] = nxt timeline.append((time, f"启动: {nxt.name}")) else: g = gpus[gi] g.progress += dt if g.progress >= g.duration: timeline.append((time, f"完成: {g.name}")) gpus[gi] = None time += dt return timeline if __name__ == "__main__": sample_jobs = [ Job("常规训练A", priority=5, submit_time=0.0, duration=10), Job("紧急微调B", priority=80, submit_time=1.0, duration=4), Job("数据分析C", priority=20, submit_time=2.5, duration=6), ] for t, event in preemptive_schedule(sample_jobs): print(f"t={t:5.1f} | {event}")
heapq.heappush(queue, (-job.priority, job.submit_time, job))用负优先级技巧把最小堆变成“最高优先级先出队”,是抢占模拟的发动机。if g is not None and top_prio > g.priority:抢占判定的核心行:只有新任务优先级严格高于运行中任务才触发,对应正文中的 Δ 阈值思想。g.checkpointed = g.progress保存检查点:记录当前已完成进度,后续恢复时从这里续跑,而不是从零开始。nxt.progress = nxt.checkpointed从检查点恢复:任务再次启动时,把进度设置成上次保存的值,模拟“断点续跑”。timeline.append((time, f"抢占: {attacker.name}拦截了{g.name}"))把抢占事件写入时间线,便于分析调度器的行为是否符合预期。
常见误区
误区我理解的抢占式调度就是高优任务一来,系统就把低优任务 kill 掉,代码想删就删,简单粗暴。
正解直接 kill 是 Slurm CANCEL 模式的下下策——被 kill 的任务训练进度全部丢失,下次从头再来,浪费的算力由集群买单。真正可靠的抢占式调度一定配合检查点机制:先保存断点,再让出资源,等资源空闲了从断点恢复。就像急诊抢救不会把普通手术台掀翻,而是把开腹的病人妥善缝合好再腾地方。
为何常见:很多入门者看到“抢占”这个词望文生义,以为抢占=终止,忽略了“保存现场”这个关键步骤。实际上,保存检查点才是抢占能落地的前提。
误区反正高优任务能抢占,那我把自己所有任务都标成最高优先级,不就能最快跑完吗?
正解这相当于医院里所有人都挂急诊号——结果就是没有急诊,全部变成排队。集群的优先级需要通过 QoS 配额和权限控制来约束:高优任务数量有限,且抢占会带来检查点开销。人人都高优,等于没有高优;而且调度器会限制单个用户的高优配额,滥用者会被风控。
为何常见:初学者只看到抢占的“好处”,没有意识到抢占是零和博弈——你抢来的资源,正是别人被迫让出的,频繁抢占反而降低集群整体吞吐。
误区为了不让进度丢失,我应该每训练一步就保存一次检查点,这样任何时刻被抢都不心疼。
正解检查点保存本身有巨额 IO 成本。假设一次保存花 60 秒,如果每 5 分钟存一次,训练效率直接下降 20%。更合理的做法是周期快照(如每 30 分钟)配合异步落盘,把开销控制在 2% 以内。过度频繁的快照,等于主刀医生每缝一针就叫护士拍一张照片——手术没做完,时间全耗在拍照上了。
为何常见:人们天然对“丢失”感到恐惧,却忽略了“保存”本身也要付出代价。在分布式训练中,全量检查点动辄几十 GB,IO 瓶颈往往比算力瓶颈更先到来。
误区SLA 就是保证高优任务尽快运行,低优任务无所谓,等多久都行。
正解恰恰相反,SLA 保护的重点恰恰是低优任务——防止它们被无限期饿死。通过排队超时升级、最小运行时间保障、抢占次数上限,系统承诺每个任务等待时间有上限。订阅了一个“最迟 4 小时接诊”的承诺,急诊病人再多,门诊病人在第 4 小时也会被自动排上台。
为何常见:SLA 在商业语境里常被理解为“优先客户的权益”,但在调度系统里,它更多是“最差情况下的公平底线”。忽略了这一点,集群就会出现“饿死”任务,长期占用队列却不产出结果。
面试题
Q1. 抢占式调度中,检查点(Checkpoint)的核心作用是什么?
- A.定期保存任务进度以便恢复← 正确答案
- B.提高 GPU 的计算运行频率
- C.压缩模型文件的存储体积
- D.自动修复训练代码中的 Bug
答案:A。检查点的作用是把训练状态(权重、优化器、步数)持久化,让任务被抢占后能从断点继续。它不提升频率、不压缩体积,更不能修 Bug——就像手术记录的价值是让手术能续接,而不是加快心跳。
Q2. 下列哪种情况最应该触发抢占式调度?
- A.新任务优先级显著高于运行任务← 正确答案
- B.集群网络发生了短暂抖动故障
- C.GPU 散热风扇转速明显降低
- D.管理员想测试一下抢占功能
答案:A。抢占的核心触发条件是“优先级差值超过阈值”。网络故障、风扇问题属于硬件运维事件,管理员测试也需要有真实的高优任务配合。急诊通道只为病情危急的病人开放,不能因为好奇就拉响警报。
Q3. 下列哪项策略能有效防止低优任务被“饿死”?
- A.排队超时后自动提升优先级← 正确答案
- B.将所有任务优先级设为相同
- C.禁止任何形式的任务抢占
- D.提高所有任务的检查点频率
答案:A。排队超时升级是标准的反饿死机制——低优任务等太久就自动提权。全部同优先级等于没有优先级,完全禁止抢占会让紧急任务无法插队,单纯提高检查点频率与饿死无关。
Q4. 在 Slurm 中,要关闭抢占功能应如何设置 PreemptMode?
- A.设置为 OFF 直接关闭抢占← 正确答案
- B.设置为 CANCEL 排队等待
- C.设置为 SUSPEND 提升频率
- D.设置为 GANG 人工审批
答案:A。Slurm 中 PreemptMode=OFF 表示彻底关闭抢占。CANCEL 是抢占后直接取消低优任务,SUSPEND 是挂起,GANG 是轮转调度,三者都不是关闭抢占。就像医院关停急诊通道的开关只有 OFF 一个档位。
Q5. K8s 中定义 Pod 调度优先级的机制是哪个对象?
- A.PriorityClass 资源对象← 正确答案
- B.NodeSelector 节点配置
- C.ServiceAccount 服务账户
- D.ConfigMap 配置字典
答案:A。K8s 通过 PriorityClass 定义优先级数值,Pod 用 priorityClassName 引用。NodeSelector 管节点选择,ServiceAccount 管权限,ConfigMap 管配置,它们都和抢占调度无关。
Q6. 检查点保存频率过高会带来什么直接后果?
- A.存储 IO 开销急剧增加← 正确答案
- B.模型训练精度明显下降
- C.GPU 算力成倍地提升
- D.任务优先级被自动重置
答案:A。检查点本质是写磁盘,频率越高,IO 占用的时间越多,有效训练时间减少。它不影响模型精度,不会提升算力,更不会影响优先级——就像拍照太频繁会耽误手术时间,但照片本身不会改变病人的病情。
Q7. 抢占式调度的触发条件可能包括以下哪些?
- A.高优任务提交且无空闲 GPU← 正确答案
- B.低优任务排队时间超过 SLA← 正确答案
- C.管理员手动调高任务优先级← 正确答案
- D.GPU 硬件发生掉卡等故障
答案:ABC。三类典型触发:高优任务插队、排队超时升级、人工干预调优先级。GPU 硬件故障触发的是故障转移机制,不是抢占——硬件坏了没有“暂停保存”的余地,相当于手术室着火了只能转移病人,不是让台。
Q8. SLA 对低优任务最重要的保护意义是什么?
- A.保证等待时间有明确上限← 正确答案
- B.保证永远不被高优任务抢占
- C.保证获得最高优先级配额
- D.保证检查点文件永不丢失
答案:A。SLA 的核心是给低优任务一个“最多等多久”的承诺,超时自动提权。它不能保证永不被抢,也绝不意味着最高优先级,检查点文件属于存储可靠性问题,与 SLA 无直接关系——等太久会升级加急,但急诊来了该让还是让。
Q9. 抢占式调度带来的开销包括哪些方面?
- A.检查点保存的存储和时间成本← 正确答案
- B.恢复时加载检查点的 IO 耗时← 正确答案
- C.被抢占任务回退进度的损失← 正确答案
- D.任务源代码的编写和维护成本
答案:ABC。抢占开销集中在三处:保存检查点花的时间与存储、恢复时加载检查点的时间、两次检查点之间的进度丢失。源代码编写成本是研发开销,不是调度开销——就像急诊让台的成本是手术中断的损失,而不是医生学手术的学费。
Q10. 某任务被抢占后恢复,但其训练进度回退了一小段,可能的原因有哪些?
- A.检查点只按周期保存而非实时← 正确答案
- B.最后几秒的训练进度未写入检查点← 正确答案
- C.检查点文件从存储中被意外删除← 正确答案
- D.GPU 时钟频率在运行中发生了波动
答案:ABC。回退的根源是“检查点不是实时镜像”:周期保存使得最后一段进度丢失,这与选项 A、B 一致;文件被删除则导致恢复到更早的备份、进退更多。GPU 频率波动只影响训练速度,不影响进度存档的完整性——病历上没记录的内容,做了手术也算没做。