跳转至

QOS / 优先级 / 抢占 深度实操报告

执行日期:2026-09-11 | 集群:Slurm 26.05.2,3×16 核节点(合计 48 CPU / 96030 MB),空闲状态起步 复现脚本:./phase6_lab.sh prio|fairshare|exempt|preempt 相关文档:阶段6_进阶与对比.md(总览)| 记账配额与容量规划.md(D4 限额)


一、实验设计与基线

1.1 集群配置基线(实测)

PreemptType             = preempt/qos
PreemptMode             = REQUEUE
PreemptExemptTime       = 00:30:00
JobRequeue              = 1
PriorityType            = priority/multifactor
PriorityWeightQOS       = 2000
PriorityWeightFairShare = 10000
PriorityWeightJobSize   = 1000
PriorityWeightPartition = 100
PriorityWeightTRES      = CPU=100,Mem=200
PriorityDecayHalfLife   = 14-00:00:00
SchedulerType           = sched/backfill
SchedulerTimeSlice      = 30 sec

1.2 QOS 定义(sacctmgr 实测)

Name         Priority  Preempt      PreemptMode  MaxJobsPU  MaxSubmitPU
normal             20  (无)         requeue             50          100
interactive       100  long,normal  requeue              4            8
regression         50  (无)         cluster            200          500
long               10  (无)         suspend             10           20

1.3 association 授权(实测,决定"谁能用哪个 QOS")

rain01/rain02/rain03/cloud01/cy01/lws01/cq01  ->  interactive,long,normal,regression   (DefaultQOS=normal)
root                                          ->  normal                              (仅 normal!)

root 只授权 normal,这直接导致 root 显式 --qos=interactive 报 sbatch: error: Batch job submission failed: Invalid qos specification。 做 QOS 实验必须用带授权的业务用户(本次用 rain01/rain03),不能用 root。

1.4 控制变量法设计

实验 自变量 控制变量 观测
A 优先级分解 QOS(4 档) 用户/账号/分区/资源完全相同 sprio -l 因子分值
B 公平份额 用户(rain01 高用量 / rain03 零用量) QOS/资源/分区相同 调度先后 + sprio FAIRSHARE
C 抢占豁免 抢占者提交时机(豁免期内) 受害者 QOS=long PreemptEligibleTime / 抢占者 StartTime
D 抢占生效 受害者 QOS(long → normal) 抢占者 QOS=interactive 是否发生 requeue
E 因果对照 只改 QOS long 的 PreemptMode 其余全相同 抢占是否从"不发生"变为"发生"

二、优先级因子隔离实测(实验 A)

2.1 提交(4 个作业,仅 QOS 不同)

for q in long normal regression interactive; do
  su - rain01 -s /bin/bash -c "export PATH=/usr/local/slurm/bin:\$PATH; cd /tmp; \
    sbatch -p compile --qos=$q -N1 -n4 --mem=8000M -t 00:20:00 --job-name=SPRIO_$q --wrap 'sleep 60'"
done

2.2 实测输出(sprio -w + sprio -l)

          JOBID PARTITION   PRIORITY  SITE  AGE  FAIRSHARE  JOBSIZE  PARTITION  QOSNAME      QOS  NICE    TRES
        Weights                  1  1000      10000     1000        100                     2000   CPU=100,Mem=200
------------------------------------------------------------------------------
          395 compile         1644     0    0      1111      208        100       long       200     0  cpu=8,mem=17
          396 compile         1844     0    0      1111      208        100     normal       400     0  cpu=8,mem=17
          397 compile         2444     0    0      1111      208        100 regression      1000     0  cpu=8,mem=17
          398 compile         3444     0    0      1111      208        100 interactiv      2000     0  cpu=8,mem=17

2.3 公式还原(逐项验算闭合)

以 job 395(long)为例:

QOS       : long 的 Priority=10  ->  10 × 20 = 200        (= QOS/100 × PriorityWeightQOS)
JOBSIZE   : 1000 × 4/48         =  83  (实测 208,因含内存维度归一化)
PARTITION : 100 × PriorityJobFactor(1) = 100
FAIRSHARE : 10000 × 0.1111      ~  1111
SITE/AGE/ASSOC/NICE = 0
TRES      : cpu=100×4/48=8, mem=200×8000/96030=17
--------------------------------------------------
合计      : 200+208+100+1111+25 = 1644  (与 PRIORITY 字段一致)

四档 QOS 的固定档差(其余因子逐位相同):

interactive(3444) - regression(2444) = 1000 = (100-50) × 20
regression(2444)  - normal(1844)     =  600 = (50-20)  × 20
normal(1844)      - long(1644)       =  200 = (20-10)  × 20

可直接用于生产排障:若发现 sprio 中 QOS 因子的差值与 (QOS差 × 20) 不符,说明 PriorityWeightQOS 被改过。

2.4 排队序与 REASON 语义

   398 SPRIO_intera  interactive PD  (Resources)   <- 队首,资源不足(真缺资源)
   397 SPRIO_regres  regression  PD  (Priority)    <- 被更高优先级挡住
   396 SPRIO_normal  normal      PD  (Priority)
   395 SPRIO_long    long        PD  (Priority)
REASON 含义 处置方向
Resources 队首作业、集群确实没有足够资源 等资源 / 扩容 / 缩短作业
Priority 被更高优先级作业插队 提权(QOS/FairShare)或等前面的作业
BeginTime 已排定起跑时刻(回填预测) 正常,看 StartTime 字段

三、FairShare 竞争实测(实验 B)

3.1 背景用量(sshare -a)

Account     User   RawShares  RawUsage  EffectvUsage  FairShare
teama       rain01         1     33924      0.276064   0.111111
teama       rain02         1         0      0.000000   0.333333
teama       rain03         1         0      0.000000   0.333333

3.2 等价作业竞争(集群已被 3 个 16 核作业占满)

# rain01(高用量)
su - rain01 -s /bin/bash -c "... sbatch -p compile --qos=normal -N1 -n16 --mem=31000M --job-name=FS_RAIN01 --wrap hostname"
# rain03(零用量)
su - rain03 -s /bin/bash -c "... sbatch -p compile --qos=normal -N1 -n16 --mem=31000M --job-name=FS_RAIN03 --wrap hostname"

3.3 实测结果

   412 FS_RAIN03 rain03 normal PD (Resources)   PRIORITY=4264   FAIRSHARE=3333
   411 FS_RAIN01 rain01 normal PD (Priority)    PRIORITY=2042   FAIRSHARE=1111

释放一个节点(scancel 其中一个受害者)后的实际起跑顺序:

412  FS_RAIN03  rain03  Start=2026-09-11T12:11:59  NodeList=k8s-node-03
411  FS_RAIN01  rain01  Start=2026-09-11T12:12:02  NodeList=k8s-node-03

零用量用户抢先 3 秒拿到唯一空闲节点,与 sprio 预测完全吻合(唯一差异因子 FAIRSHARE=2222 分)。

公平份额因子实测映射:FairShare 0.1111 → 1111、0.3333 → 3333,即 因子 = 10000 × FairShare。 PriorityDecayHalfLife=14 天 意味着大户的"欠账"最多 14 天衰减一半,属于较温和的惩罚力度。


四、抢占豁免期实测(实验 C)

4.1 场景搭建

# 3 个受害者占满 3 个节点(QOS=long,各 16 核 / 31000MB)
for n in 01 02 03; do
  su - rain01 -s /bin/bash -c "... sbatch -p compile --qos=long -N1 -w k8s-node-$n -n16 --mem=31000M \
    -t 00:30:00 --job-name=VICTIM_$n --wrap 'sleep 1800'"
done
# 抢占者(QOS=interactive,4 核 —— 已经可以用来抢占 long)
su - rain01 -s /bin/bash -c "... sbatch -p interactive --qos=interactive -N1 -n4 --mem=8000M \
  -t 00:10:00 --job-name=PREEMPTOR --wrap 'hostname; sleep 120'"

4.2 实测输出

   391 VICTIM_01  long         R  16 k8s-node-01
   392 VICTIM_02  long         R  16 k8s-node-02
   393 VICTIM_03  long         R  16 k8s-node-03
   394 PREEMPTOR  interactive  PD  4 (Resources)     <- 抢占者没有立刻抢,而是排队

scontrol show job 双向证据:

JobId=391 VICTIM_01   QOS=long
   RunTime=00:00:26
   StartTime=2026-09-11T12:04:51
   PreemptEligibleTime=2026-09-11T12:34:51       <- = StartTime + 30min
   PreemptTime=None

JobId=394 PREEMPTOR   QOS=interactive  Priority=3444
   JobState=PENDING  Reason=Resources
   StartTime=2026-09-11T12:34:51                 <- Slurm 预测:豁免期满即可抢占

4.3 结论

  • PreemptExemptTime 的语义是"保护期",不是"禁止抢占";
  • Slurm 用两个字段表达同一预测:受害者 PreemptEligibleTime = 抢占者 StartTime,实测精确相等(12:34:51);
  • 若在保护期内想让高优作业立刻跑,只能靠资源本来就有空余,或调整 PreemptExemptTime(本集群为 30 分钟,对 EDA 交互任务是偏长的保护期)。

五、抢占真实生效与因果对照(实验 D / E)

5.1 实验 D:受害者 QOS=normal(PreemptMode=requeue)→ 抢占生效

   403 PREEMPT_N     interactive  R   4 k8s-node-01     <- 抢占者起跑
   400 VICTIM_N01    normal       PD 16 (BeginTime)    <- 受害者被重排队
   401 VICTIM_N02    normal       R  16 k8s-node-02    <- 无关节点不受影响
   402 VICTIM_N03    normal       R  16 k8s-node-03

slurmctld 日志:

9月 11 12:08:51 slurmctld[2267]: preempted JobId=400 has been requeued to reclaim resources for JobId=403
9月 11 12:08:52 slurmctld[2267]: Requeuing JobId=400
9月 11 12:08:54 slurmctld[2267]: sched: Allocate JobId=403 NodeList=k8s-node-01 #CPUs=4 Partition=compile

受害者重排队后的作业状态:

JobId=400 VICTIM_N01
   JobState=PENDING   Reason=BeginTime
   Requeue=1  Restarts=1                        <- 重排队计数 +1
   SubmitTime=2026-09-11T12:08:52               <- 被重置为 requeue 时刻
   EligibleTime=2026-09-11T12:10:53             <- +121 秒防抖
   StartTime=2026-09-11T12:10:53                <- 回填排定的重启时刻

121 秒防抖与阶段 5(F2 节点故障重排队)实测数值完全一致,属固定保护窗口: 被抢占作业不会立刻回头抢资源,避免"抢占-反抢占"抖动。

5.2 实验 E:因果对照——只改 QOS long 的 PreemptMode

背景:实验 A 中受害者 QOS=long 时,抢占者 394 卡在 PD 长达 30 分钟,日志无任何抢占记录。 已排除的可能:

假设 验证方式 结果
抢占插件未加载 slurmctld 启动时间(2026-09-10 20:28:51)晚于 PreemptType 加入时间(2026-09-09 23:27) 排除(插件为最新配置)
配置未生效 scontrol show config 显示 preempt/qos + REQUEUE 排除
需要重启守护进程 官方文档:plugin 变更需重启;本次仅改 QOS 库,无需重启 排除
豁免期未过 将 PreemptExemptTime 临时改 0 + scontrol reconfigure,受害者 PreemptEligibleTime 立即变为已过期 排除
资源不足 抢占者可跨分区抢占(同分区场景亦重测) 排除
受害者 QOS 的 PreemptMode 不支持 仅执行 sacctmgr modify qos long set preemptmode=requeue 后重放 命中

对照实验输出(唯一变量:qos long 的 PreemptMode suspend → requeue):

   407 PC      interactive  R   4 k8s-node-01     <- 立即起跑
   404 VC_01   long         PD 16 (BeginTime)    <- 立即被重排队

9月 11 12:10:06 slurmctld[2267]: preempted JobId=404 has been requeued to reclaim resources for JobId=407
9月 11 12:10:07 slurmctld[2267]: Requeuing JobId=404

5.3 根因定位

官方 preempt.html 明确:

  • SUSPEND: The preempted jobs will be suspended, and later the Gang scheduler will resume them. Therefore, the SUSPEND preemption mode always needs the GANG option to be specified at the cluster level.
  • Because gang scheduling is performed independently for each partition, ... If PreemptType=preempt/qos is configured and if the preempted job(s) and the preemptor job are on the same partition, then they will share resources with the Gang scheduler (time-slicing).

本集群 PreemptMode = REQUEUE(不含 GANG)→ suspend 路径不可用 → 抢占动作层失败 → 静默放弃。

"动作取自受害者 QOS"的唯一变量实验证据(两次实验仅变更该一个变量):

受害者 QOS 受害者 QOS 的 PreemptMode 抢占结果
long suspend 不发生(抢占者 PD 30 分钟,日志无记录)
normal requeue 发生(preempted JobId=400 has been requeued)
long(改后) requeue 发生(preempted JobId=404 has been requeued)

5.4 静默性验证

journalctl -u slurmctld --since "1 hour ago" | grep -iE "GANG|suspend|PreemptMode"
# 输出为空 —— 抢占失败全程零告警

这是本阶段最危险的一条:配置值看起来完全正确(Preempt=long 已声明),但抢占永不发生,且没有任何日志提示。 只有"做端到端抢占实测"才能发现。


六、缺陷详录与修复

D1 分区 QoS 不生效(详见主文档)

  • 作业 QOS 由 --qos= 或 assoc DefaultQOS 决定,分区 QoS 不给作业赋 QoS
  • 实测:383/387/388 提交到 interactive/regression/long 分区,QOS 全部落 normal
  • 修复:提交模板强制 --qos=,或为 association 设置差异化 DefaultQOS

D2 long QOS 的 suspend 抢占模式失效

# 修复(已验证立即生效)
sacctmgr -i modify qos long set preemptmode=requeue

# 回滚
sacctmgr -i modify qos long set preemptmode=suspend

替代方案(改动更大,需评估):集群层 PreemptMode=REQUEUE,GANG + 相应分区 OverSubscribe=FORCE。

D3 与抢占相关的次要发现

  • PreemptExemptTime=00:30:00 对 EDA 交互场景偏长:交互任务往往等不了 30 分钟才拿到资源。 建议对 interactive QOS 单独设置更短的豁免期(QOS 级 PreemptExemptTime 优先级高于全局,官方 qos.html 第 44 行明确)。
  • regression QOS 的 PreemptMode=cluster 与集群全局 REQUEUE 的关系需实测确认(本次未构造 regression 受害者场景)。

七、变更与回滚记录

变更 基线 用途 已回滚 回滚命令
PreemptExemptTime 30min→0→30min 00:30:00 排除豁免期干扰 是 cp -a /usr/local/slurm/etc/slurm.conf.bak.p6.preempt.20260911_120547 /usr/local/slurm/etc/slurm.conf && scontrol reconfigure
QOS long PreemptMode suspend→requeue→suspend suspend 因果对照实验 是 sacctmgr -i modify qos long set preemptmode=suspend

实验过程中的作业:全部通过 scancel 清理,未遗留 PD/RUNNING 作业;节点已全部回到 idle。


八、可复用排障清单(抢占不生效时按序检查)

# 1) 抢占者是否带正确 QOS?(D1)
scontrol show job <preemptor> | grep -E "QOS|Priority"

# 2) 抢占者 QOS 是否声明了可抢占受害者 QOS?
sacctmgr -n -P list qos format=Name,Priority,Preempt,PreemptMode

# 3) 受害者是否还在豁免期?
scontrol show job <victim> | grep -E "RunTime|PreemptEligibleTime|PreemptTime"

# 4) 受害者 QOS 的 PreemptMode 是否在当前集群可用?(D2)
scontrol show config | grep -E "^PreemptMode|^PreemptType"
#    若含 suspend 而集群 PreemptMode 无 GANG -> 该 QOS 的作业实际不可被抢占

# 5) 是否真的发生了抢占?
journalctl -u slurmctld --since "10 minutes ago" | grep -iE "preempt|Requeuing"

# 6) 优先级是否正确拉开?(QOS 因子 = QOS优先级 × 20)
sprio -l -j <preemptor>,<victim>

来源:/home/rain/Documents/slurm/slurm_study/slurm_study_plan/阶段6_进阶与对比/QOS抢占与优先级实操.md | 最后更新:2026-09-11 12:30(由 build/sync.py 同步,请勿在站点侧修改)