Skip to content

任务优先级与资源抢占(通用调度) ​

难度与前置

难度:架构
前置:读过 调度依赖、告警值班;经历过「大作业占满集群、出数全迟到」。
读完能做什么:设计优先级与队列隔离、定义可抢占边界与保护作业,并用演练指标验收(厂商无关)。

适用场景 ​

  • 共享集群上报出数、训练、回刷、即席分析争抢 CPU/内存/槽位
  • SLA 分层:P0 报表必须准点,P2 回刷可降级
  • 云上队列 / Yarn 队列 / K8s namespace 需要统一优先级语言

不适用:

  • 单租户独占集群且无争抢
  • 仅依赖 DAG 无资源层(仍建议预留队列,但本文重点在资源)
  • 具体某云产品点击路径(只讲通用原则)

真实场景(一条) ​

月末财务回刷与晨间 P0 报表同队列。回刷占满槽位,P0 迟到 90 分钟,值班救火。改造:队列拆 sla-p0 / batch-default / backfill;P0 保障容量;回刷最低优先且可抢占;大回刷限流并行度。次月同窗口 P0 准点,回刷拉长但可接受。

怎么做(步骤清单) ​

1. 先定优先级语义(全公司一本账) ​

级别含义示例
P0超时业务不可接受核心损益、履约大盘
P1当日必须普通经营报表
P2尽量完成实验、非核心
P3可推迟/可杀历史回刷、探索

优先级写在任务元数据,并与 依赖 READY 解耦:依赖满足 ≠ 有权抢资源。

2. 队列 / 池隔离 ​

text
建议最少三池:
- sla-guard:P0/P1,保障容量,禁止低优占满
- default:日常 P1/P2
- backfill:P3,可抢占、有并发上限
即席分析单独池,避免 ad-hoc 打死出数

3. 抢占规则(写清楚) ​

规则说明
谁可抢谁仅更高优先级可抢更低;同级 FIFO/公平
保护期任务启动后 T 分钟内免抢(防抖动)
检查点友好批作业尽量在 stage 边界停;流作业另策
禁止抢标 non_preemptible 的短 P0(慎用)
text
抢占不是「杀光重来」的借口:被抢方应可恢复或可续跑,并记入成本

4. 调度侧实现要点(通用) ​

  • 任务提交带 priority + queue
  • Worker 资源分配:保障额度 + 弹性借用
  • 借用必须可回收:低优借用高优保障池时,高优到来可回收
  • 回刷作业:最大并行、最大时长、错峰窗口

5. 与 DAG / SLA 联动 ​

text
P0 依赖链:上游也必须 P0 队列,否则优先级虚假
SLA 时钟:资源等待时间计入「调度延迟」,与执行时长分开监控
迟到预案:见告警值班;资源争抢根因桶单独统计

6. 回刷与补数 ​

  • 默认进 backfill,不可进 sla-guard
  • 大范围补数拆窗,避免单作业巨型化
  • 与 补数追数 流程绑定审批

7. 观测指标 ​

指标用途
队列待运行时长发现饿死
P0 准点率北极星
抢占次数 / 被抢任务数策略是否过激
保障池利用率是否浪费或不足

常见坑(至少牢记这些) ​

  1. 只标优先级、不拆队列
    调度器仍一把抢,标签成摆设。

  2. P0 过多
    全是 P0 = 没有 P0;保障池被「重要」淹没。

  3. 回刷进保障池
    一次历史重算打死当日出数。

  4. 无保护的频繁抢占
    任务反复被杀,集群有效吞吐下降。

  5. 上游低优、下游 P0
    优先级倒挂,P0 空等数据。

  6. 即席与生产共池
    分析师 SELECT * 拖垮出数。

如何验收(可量化) ​

  • [ ] 任务元数据含 priority + queue,P0 比例受控(如 < 10%)
  • [ ] 演练:backfill 打满时提交 P0,P0 在约定时间内获得资源
  • [ ] P0 准点率 ≥ 目标;资源等待 P99 有基线
  • [ ] 抢占事件可审计(谁抢谁、何时)
  • [ ] 回刷审批与队列强制校验(CI/提交钩子)
bash
# 示意:从调度 API/审计导出
echo "date,p0_ontime_rate,p0_wait_p99_sec,preempt_count,backfill_running" > sched_prio_kpi.csv
# 验收周:p0_ontime_rate>=0.99, preempt 可解释
sql
-- 若运行实例入仓
SELECT
  priority,
  AVG(unix_timestamp(start_ts)-unix_timestamp(ready_ts)) AS avg_wait_sec,
  percentile_approx(unix_timestamp(start_ts)-unix_timestamp(ready_ts), 0.99) AS wait_p99
FROM ops_task_instance_di
WHERE dt='${biz_date}'
GROUP BY priority
ORDER BY priority;
text
演练步骤:
1. 在 backfill 队列提交 N 个长任务占满可借资源
2. 提交 P0 短任务
3. 观察:等待时长 ≤ 目标(如 5min)或发生对低优抢占
4. P0 成功结束后低优可恢复/重跑

相关面试题 ​

占位:与题库小程序对齐后补链接(建议关联:调度优先级、资源隔离、抢占、SLA)。


改写说明:结构参考 Wood 原创调度实践,已改写成厂商无关可执行清单;未包含未公开队列名与配额原值。

附:优先级评审会最小议程 ​

  1. 本季度新增 P0 列表是否超配额
  2. 是否存在上游低优 → 下游 P0 倒挂
  3. 回刷窗口与保障池冲突日历
  4. 上月抢占 Top 原因与误杀复盘
text
出口标准:P0 清单冻结、倒挂清零、回刷不进 sla-guard、准点率达标

附:提交钩子伪代码 ​

text
on_submit(task):
  assert task.priority in {P0,P1,P2,P3}
  assert task.queue matches priority policy
  if task.tags contains "backfill":
    assert task.queue == "backfill"
    assert task.priority >= P2
  if task.priority == P0:
    assert task.owner_oncall is not empty