GPU 统一调度
HeteroFlow 是本站的异构算力与大模型调度产品。GPU 统一调度。GPU 统一调度 GPU 统一调度是 HeteroFlow 的核心组件:一台控制面把十种 GPU 架构(NVIDIA、昇腾、摩尔线程、海光 DCU、沐曦、燧原、天数智芯、壁仞、寒武纪、昆仑芯)的异构节点池当成一份统一资源,用类 Kubernetes Scheduler 的多阶段流…
GPU 统一调度
GPU 统一调度是 HeteroFlow 的核心组件:一台控制面把十种 GPU 架构(NVIDIA、昇腾、摩尔线程、海光 DCU、沐曦、燧原、天数智芯、壁仞、寒武纪、昆仑芯)的异构节点池当成一份统一资源,用类 Kubernetes Scheduler 的多阶段流水线为每个任务做放置决策。调度器每 5 秒一轮,任务先过内置过滤链(可用性 → 租户 → 资源 → 亲和),再走 PreScore → Filter → Score → PostScore → Bind 五阶段插件流水线;绑定链路内建 CAS 认领防双绑、GPU 防超卖双路记账与跨租户共卡边界等强约束。策略全部插件化:装箱与分散两种布局策略互斥可切,NVLink / RDMA / 机架拓扑三类感知打分按需参与,高优先级任务可在资源不足时抢占显式声明可让位的任务。
功能总览
| 能力 | 一句话说明 | 状态 |
|---|---|---|
| 五阶段流水线 | PreScore → Filter → Score → PostScore → Bind,每 5 秒一轮 | 已实现 |
| 8 个内置调度插件 | 布局 / 拓扑 / 网络 / 类型 / 资源五类决策插件,开关与权重可调 | 已实现 |
| GPU 类型匹配 | gpu_type 声明即强制过滤到对应架构节点,大小写不敏感 | 已实现 |
| 整卡与分片双语义 | 整卡任务按"显存利用率 <95% 的卡数"计容量,分片任务查单卡剩余显存 | 已实现 |
| GPU 防超卖记账 | 调度器实时账 + 心跳重算账双路一致,按 SUM(gpu_required) 核算 | 已实现 |
| 跨租户共卡边界 | 同时共卡必须同租户或同共享租户组,判定失败一律拒绝 | 已实现 |
| 拓扑感知调度 | Region / Zone / Rack 三层叠加打分,偏好软加分 + 硬约束过滤 | 已实现 |
| NVLink 机内拓扑 | agent 采集机内拓扑,多卡任务优先落同一 NVLink 域并选卡组 | 适配(代码与上报链路就绪,待 NVLink 硬件联调) |
| RDMA 网络感知 | 声明 RDMA 的节点加分,任务可硬性要求 RDMA | 已实现 |
| 任务抢占 | 高优先级任务抢占声明 preemptible 的低优先级任务,看门狗兜底 | 真机验证 |
| 并发与优先级调度 | 每轮有界批处理 + 评分并行打分 + CAS 认领,priority 0-100 降序 | 已实现 |
| 调度窗口 | 推理服务按时间窗口自动暂停 / 缩放 / 停止,窗口恢复自动回副本 | 已实现 |
| 组调度类型约束 | 训练 / 推理组一致声明 gpu_type 时五条路径一律严格过滤不回落 | 已实现 |
五阶段流水线
调度器的主循环是一个事件循环:5 秒主调度 ticker、积压恢复(60s)、推理重建(10s)、抢占看门狗(30s)、训练借卡唤醒巡检(15s)各自独立节拍,另有任务创建即触发的即时队列通道。每个待调度任务在流水线之前,先经过内置过滤链——可用性(节点须 online/busy 且可执行)→ 租户(专属节点只对归属租户可见)→ 资源预过滤(显存粗筛、推理容器上限、模型分布)→ 亲和与跨租户约束。然后进入插件流水线:
| 阶段 | 职责 | 内置插件挂载点 |
|---|---|---|
| PreScore | 评分前预处理钩子(如抢占需求识别) | preempt(挂载于此阶段名下,实为配置载体,见插件矩阵注) |
| Filter | 排除不满足硬条件的节点,插件报错即排除该节点(fail-closed) | resource-filter、gpu-filter(常开)+ rdma / topology / nvlink(按配置) |
| Score | 对通过过滤的节点并行打分,每插件 × 每节点一个 goroutine,加权求和 | spread 或 binpack(互斥)+ nvlink、topology、rdma |
| PostScore | 分数归一化与最终调整 | 当前无内置插件,预留扩展点 |
| Bind | 取最高分节点,完成资源绑定 | 由调度器 BindTask 实现(非插件化) |
Bind 阶段做四件事:以 UPDATE ... WHERE status='pending' 的 CAS 原子认领任务(多实例并发绑定同一任务时只有一方成功);按实时数据复查负载阈值 / 显存 / 端口;按任务形态做节点内选卡或分片分配;落库并更新 GPU 记账。任何一步失败都回滚认领,任务回到 pending 等下一轮,不会留下半绑定状态。
任务生命周期
| 状态 | 含义 |
|---|---|
| Pending | 已创建,等待调度 |
| Scheduled | 已分配节点,等待执行 |
| Starting | 已绑定节点,容器启动中(推理服务预热阶段) |
| Running | 正在执行 |
| Completed / Failed / Cancelled | 终态;Failed 按错误类型决定是否重试 |
| Paused | 推理服务因调度窗口暂停,窗口恢复后自动重启 |
| Draining | 滚动更新中的旧副本,不再接新请求,存量请求处理完退出 |
全部关键状态迁移(含 preempting、stopping 等过渡态)由状态机统一约束:非法迁移直接拒绝,过渡期间资源仍计占用,正在被抢占的任务不允许被标记为成功完成。
内置调度插件矩阵
实际注册的 8 个调度插件如下(注册入口 RegisterP0Plugins):
| 插件 | 阶段 | 功能 | 默认状态 | 口径 |
|---|---|---|---|---|
| spread | Score | 分散调度均衡分布(利用率低者优先) | 启用(weight 1) | 已实现 |
| binpack | Score | 紧凑装箱(利用率高者优先,减少碎片) | 注册但配置禁用(weight 0) | 已实现 |
| nvlink | Filter+Score | 机内 GPU NVLink 拓扑感知(消费 heteroflow.io/gpu-topology 标签;SelectGPUs 节点内选卡组) | 启用 | 适配(代码与上报链路就绪;现有测试节点为 PCIe 版无 NVLink,机内拓扑联调未做) |
| topology | Filter+Score | 拓扑感知(Region/Zone/Rack 层级打分过滤) | 启用 | 已实现 |
| rdma | Filter+Score | RDMA 网络感知(rdma: required 过滤 + 能力标签打分;数据缺失时降级语义明确) | 启用 | 已实现 |
| gpu-filter | Filter | 按 task.gpu_type 匹配节点 GPU 类型 | 强制启用常开 | 已实现 |
| resource-filter | Filter | GPU 资源检查(整卡按显存利用率 <95% 计卡;分片查单卡剩余显存) | 强制启用常开 | 已实现 |
| preempt | 配置载体 | 承载 preempt_stage 抢占策略配置(抢占执行逻辑在调度器内,插件不参与节点评分与过滤) | 启用 | 真机验证 |
三个纪律性设计贯穿全矩阵:
- 正确性基础插件不可关:resource-filter 与 gpu-filter 被硬编码强制启用,不受配置文件与 API 开关影响,防止误操作把资源不足或类型不匹配的节点放进调度结果。
- 数据缺失干净降级:nvlink / topology / rdma 对没有相应标签数据的节点一律中性计分(不打扰排序)、过滤放行(不清空集群),标签显式存在时加分 / 惩罚 / 硬过滤才生效。
- 配置真实传导:插件开关与权重经 API 修改后即时重建调度器生效插件集合并持久化,
GET /api/v1/scheduler/plugins返回的就是调度器实际读到的集合,不存在"页面显示已生效、调度器仍用旧集合"的假开关。
调度策略:Binpack 与 Spread
两种布局策略互斥,同一时刻只生效一个;默认 spread 启用、binpack 禁用。两者共用同一份节点使用率计算:CPU 取心跳上报的使用率百分比(与核数无关),内存按已用 MB / 总 GB 换算,GPU 取已占卡数 / 总卡数。
| 维度 | Binpack(紧凑装箱) | Spread(分散调度) |
|---|---|---|
| 目标 | 任务集中到少数节点,提高密度、减少碎片 | 任务分散到更多节点,故障隔离、负载均衡 |
| 打分函数 | 得分 = 综合使用率 × 100,越满的节点分越高 | 得分 = (1 − 综合使用率) × 100,越空的节点分越高 |
| 综合使用率 | CPU×0.4 + 内存×0.3 + GPU×0.3 | CPU×0.3 + 内存×0.2 + GPU×0.2 + 任务负载×0.3(每个活跃任务折算 5%,上限 100%) |
| 适用场景 | 高密度计算、给多卡任务留整机、减少跨节点开销 | 高可用、故障影响面小、负载均衡 |
| 跨节点通信 | 少 | 多 |
切换方式:在插件管理页或经 POST /api/v1/plugins/{name}?action=enable|disable 启停,启用 binpack 会自动禁用 spread(binpack 优先),反之亦然;权重经 PUT /api/v1/plugins/{name} 调整。切换后以 GET /api/v1/scheduler/plugins 验证实际生效列表。
GPU 感知与资源过滤
类型匹配(gpu-filter)
任务声明 gpu_type(如 nvidia、ascend、musa)即触发强制类型过滤:节点 GPU 类型标签或卡列表与之大小写不敏感相等才通过;任务不声明则放行所有节点;节点尚未上报 GPU 信息时保守放行,由绑定期实时复查兜底。类型标识符与 agent 检测模块的十种架构一一对应。
容量检查(resource-filter)
整卡任务与分片任务走两套容量语义:
| 任务形态 | 判定条件 | 说明 |
|---|---|---|
整卡(gpu_required ≥ 1) | 节点上"显存使用率 <95%"的卡数 ≥ gpu_required | 高负载卡不再接新任务,留出余量 |
分片(gpu_memory_mb > 0 且 gpu_required ≤ 0) | 存在任一卡"总显存 − 已用显存 ≥ gpu_memory_mb" | 按单卡剩余显容纳片,不占整卡 |
两条路径的判定以字段组合为准:只声明 gpu_memory_mb(不传 gpu_required 或传 0)才走分片路径;两者都传按整卡任务处理,gpu_memory_mb 只作为显存准入条件、不创建分片。分片任务在绑定阶段经分片管理器创建分片:QoS 等级按落点节点硬件能力自动推导(不由用户指定),显存 / 算力限额随环境变量注入容器(NVIDIA 卡含 MPS per-client 限额),分配失败则整单绑定失败留在 pending——申请了显存边界的任务绝不被放出裸跑;任务结束后分片自动释放、资源归还。
插件只检查 GPU 维度(本系统是 GPU 调度系统);CPU / 内存的准入由绑定期按实时负载阈值(默认 CPU 90%、内存 90%、GPU 显存 95%、GPU 利用率 95%、GPU 温度 79°C)复查兜底。
防超卖双路记账
节点已占卡数(gpu_used)由两路账本互相校验:调度器实时账在 bind 成功时原子自增 gpu_required、任务终态时扣减;心跳重算账按节点活跃任务 SUM(gpu_required) 周期重算,防止按任务条数低估占用。两路账本与租户配额共用同一权威活跃状态集合,杜绝"调度记账算占用、配额不算"的窗口错位。
跨租户共卡边界
产品红线,代码强制:同一份物理资源被多个任务同时占用(分片叠放、推理显存比例共卡、训练借卡)必须满足"同租户,或双方租户同属一个共享租户组";组外完全隔离,默认不配组即全部隔离。判定函数查询失败一律按不允许处理(fail-closed)。一张卡上已有占用时,新任务必须与卡上每一个占用租户都满足关系才可用,防传递性绕过。排队等空闲资源不看租户(先来后到不是共享);因该约束无卡可用时按 NoTenantEligibleGPU 明确报错,绝不静默塞进别家租户的卡。
拓扑感知调度
Region / Zone / Rack 层级(topology 插件)
节点三层位置字段(Region 地理区域 → Zone 可用区 → Rack 机架)参与打分与过滤:基础分 50,任务偏好与节点同 Region +5、同 Zone +15、同 Rack +10,三层命中独立叠加(最高 80);节点字段为空时放行且计中性分,不因数据缺失清空候选。
| 任务侧表达 | 语义 |
|---|---|
preferred-region / preferred-zone / preferred-rack 标签(或任务 region 字段) | 软偏好:命中加分,不满足也能调度 |
required-region / required-zone / required-rack 标签 | 硬约束:节点字段非空且不匹配即过滤 |
节点位置字段可由管理员经专用接口与节点详情页手动填写;不填则插件恒中性、对调度结果无影响——是否维护这批数据取决于集群是否真实存在跨机房分布。
NVLink 机内拓扑(nvlink 插件,适配)
拓扑数据由节点侧 agent 执行 nvidia-smi topo -m 采集,编码为节点标签 heteroflow.io/gpu-topology(含 NVLink 连接对与 NUMA 归属)随心跳上报;插件解析标签用并查集识别 NVLink 域。控制面绝不在本机探测远端节点拓扑。
评分对象是该节点对任务最优的卡组:卡组整体落在同一 NVLink 域 +50,该域恰好被任务用满再 +30,域内卡全部可用再 +40;卡组被迫跨域 −20;同 NUMA +15 / 跨 NUMA −10。绑定阶段插件做节点内选卡组:在容得下任务的域中取最小够用域(少切碎大域),域内优先凑同 NUMA。任务声明 nvlink: required 标签时,无足够大 NVLink 域的节点被过滤(注意纯 PCIe 节点每张孤立卡也是单卡域,不是"有域就行")。
无 NVLink 硬件或无拓扑数据的节点全程中性降级(打分 50、过滤放行、选卡走"每卡活跃任务数最少"的负载均衡退路),行为正确不受影响。当前状态如实说明:插件与 agent 采集上报链路均已生产启用,但现有测试节点为 PCIe 版无 NVLink,机内拓扑端到端联调待有 NVLink 的多卡机后补做。
RDMA 网络感知(rdma 插件)
节点能力靠标签声明(rdma: true,可选 rdma-speed: <Gbps>),由运维在确认硬件后打标。打分:无标签中性 50 零影响;rdma=true 加 20,另有速度标签再按 speed/10 加分(上限 +30);显式声明不支持则 40(轻度惩罚)。过滤:任务标签 rdma: required 时,无标签节点放行(数据未知不做硬约束)、显式不支持的节点被过滤。适合分布式训练、分布式存储等网络密集型负载。
任务抢占
抢占是调度失败后的兜底路径,不是每轮常规阶段。任务优先级 priority 为 0-100 整数(默认 50,越高越优先),每轮调度 pending 任务按优先级降序排队(同优先级按创建时间 FIFO)——这层排序独立于抢占始终生效。
触发:普通调度或绑定失败(NoSchedulableNodes / InsufficientResources)后进入抢占规划。
谁能抢谁:victim 必须同时满足四个条件——不是 training / inference 类型任务、显式声明 preemptible=true、优先级严格低于发起方、当前状态匹配 preempt_stage 配置的起点。训练任务双向不参与抢占(不发起、不被抢,排队 + 优先级 FIFO 是训练唯一的竞争方式,详见《训练服务》篇),由三道独立防线保证:发起方拦截、victim 类型豁免(无论 preemptible 字段何值)、创建入口直接 400 拒收 training + preemptible=true 组合。推理任务可作为发起方但不做 victim——训练被 SIGKILL 丢 checkpoint、推理被杀是线上中断,这两类豁免是刻意的。
最小 victim 集合规划:候选按"优先级升序(最不重要先抢)→ 同优先级创建时间降序(晚创建的先抢,已产出成果最少)→ 任务 ID 兜底"排序,按节点分组累加各 victim 能归还的 GPU 卡数 / 显存 / CPU / 内存,一旦够用立刻停手,只抢"刚好够用"的最小前缀;多节点可行时按 victim 数最少 → 优先级之和更小 → 节点 ID 择优;抢光也不够则一个都不抢。
执行与结算:对计划内 victim 只做 CAS running → preempting(不释放资源);agent 轮询到 preempting 后执行与用户主动停止完全相同的优雅停流程(docker stop -t 10,兜底强杀),确认后 CAS 上报回 pending;服务端在确认之后才结算副作用(释放分片、归还节点计数、清 NodeID、preempt_count++,且置 Preemptible=false 防反复抢占)。preempting 过渡期间资源仍算占用,物理显存未释放前新任务不会被放进同一张卡。抢占看门狗每 30 秒扫描,preempting 超过 60 秒未确认即走同一 CAS 弧强制推进——agent 迟到的确认会 CAS 失败,天然互斥不重复结算。发起方本轮返回 PreemptionPending 收手,下一轮基于真实账本重新绑定。
配置:唯一开关 preempt_stage(disabled / scheduled / running,默认 running——只抢运行中任务),经 PUT /api/v1/plugins/preempt 修改,GET /api/v1/scheduler/plugins 验收。被抢占的任务不会被丢弃:优雅停后回到 pending 由调度器重新安排。
并发调度与状态机
- 有界批处理:每轮调度周期最多处理 200 个 pending 任务,配合扫描游标在后续轮次接力,不饿死队尾;修复前单轮无上限,2000 pending × 300 节点实测单轮约 30 秒,钉死 CPU 且拖累 API 延迟。
- 并行打分:Score 阶段每插件 × 每节点一个 goroutine 并行计算,加权求和取最高分。
- CAS 状态机:任务认领与全部关键状态迁移走
UPDATE ... WHERE status=期望值的原子 CAS——绑定认领防多实例双绑(输方静默让路)、抢占迁移防并发误伤、agent 状态上报防重复结算。 - 执行侧并行:节点 agent 以并行 Worker Pool 执行任务,并发度按 CPU 核数动态推导(核数/2,下限 2 上限 32),每个任务经 CAS 认领
scheduled → running后才启动容器,多任务互不阻塞。 - 失败必回滚:选卡失败、分片分配失败、落库失败都回滚认领回 pending,不留半绑定状态。
调度窗口
推理服务(TaskGroup)可配置时间窗口策略,由独立的 leader-only 周期任务每 60 秒检查:当前时间在窗口外时执行动作(pause / scale / stop),窗口恢复时 pause 与 scale 自动恢复到窗口前的副本数(stop 单向不恢复)。窗口外期间副本数由窗口任务接管,与自动伸缩互斥(AutoScaler 跳过该组评估);会增加副本数的窗口动作对处于非活跃状态的租户跳过,缩容与暂停不受影响。
组调度与网络域感知
多节点训练 / 推理组(TaskGroup,world_size 超过单节点卡数)走拓扑感知批量调度:先筛选满足 GPU 数量与类型的节点,按拓扑评分排序(同 Rack 3 分 > 同 Zone 2 分 > 其余 0 分,把同一训练组的各 rank 凑到同机架 / 同可用区以降低跨机网络延迟——软偏好,凑不到不拒绝调度),贪心选择最优节点组合,再为每个 Worker 分配 rank 与 Master 地址。整组全有或全无绑定:凑不齐就不动,不会出现半个组悬空运行。
跨机通信能否走内网由网络域判定决定,且不从 IP 前缀猜:优先认节点显式声明的 heteroflow.network_zone / heteroflow.vpc_id 标签,其次按节点上报的真实内网 IP 计算同子网归属;同一分组内出现重复内网地址会被判定为跨 VPC 自动拆开——这是真机上真实撞到过内网 IP 跨 VPC 撞地址导致分布式通信永久挂起的事故后加固的机制。判定同域才注入内网地址 + NCCL 后端,跨 VPC 一律公网地址 + gloo 后端。纯数据并行路径直接用这套真实网络判定,不依赖人工维护的位置标签——"能不能用同一套内网"由真实 IP 说了算,位置标签只是存在时的粗粒度优先级提示。
GPU 类型优先级链
agent 检测器按固定优先级链注册,决定混装节点上各厂商 GPU 的检测顺序:
musa(摩尔线程)→ hygon(海光 DCU)→ cambricon(寒武纪)→ biren(壁仞)→ ascend(昇腾)→ kunlun(昆仑芯)→ iluvatar(天数智芯)→ nvidia → metax(沐曦)→ enflame(燧原)
调度侧与之配套的是 gpu_type 强制匹配(gpu-filter)与组调度的类型约束:训练 / 推理组内全部任务一致声明 gpu_type 时,张量并行、数据并行、按卡数贪心、协同调度、流水线并行五条路径一律按该类型严格过滤、不回落到别家卡;租户范围内没有该类型节点或该类型节点当前不可用均明确报错并记入诊断账本,组退回 pending 等待。
典型调度场景
| 场景 | 任务声明 | 调度行为 |
|---|---|---|
| 单卡任务 | gpu_required: 1 | 节点内选当前活跃任务数最少的一张卡,分散落卡 |
| 多卡任务 | gpu_required: 4 | 绑定卡组:优先 NVLink 拓扑选卡(最小够用域内凑同 NUMA),无拓扑数据退路取每卡负载最少的 N 张;卡组随任务下发,agent 注入容器可见设备 |
| 显存分片任务 | gpu_memory_mb: 2048(不传 gpu_required) | 过滤查单卡剩余显存,绑定阶段创建分片并注入显存 / 算力限额;分配失败整单留在 pending,绝不裸跑 |
| 需要 NVLink | labels: {nvlink: "required"} | 只有存在容得下任务全部 GPU 的 NVLink 域的节点入选,其余过滤 |
| 需要 RDMA | labels: {rdma: "required"} | 显式不支持 RDMA 的节点被过滤,声明 RDMA 的节点打分优先 |
| 拓扑偏好 / 硬约束 | preferred-zone: zone-a / required-rack: rack-1 | 偏好命中加分可让步;硬约束不满足直接过滤 |
| 可让位的低优先级任务 | preemptible: true + 低 priority | 资源紧张时被高优先级任务抢占:优雅停容器 → 回 pending 重新排队,资源确认释放后结算 |
| 分布式训练组 | 训练配置(n_nodes × per_node_gpu) | 拓扑感知批量调度:候选节点按同 Rack / 同 Zone 排序凑近,跨 VPC 走公网 + gloo、同网络域走内网 + NCCL;整组全有或全无绑定 |
| 指定 GPU 架构 | gpu_type: ascend | 强制过滤到昇腾节点;组调度一致声明时五条路径同样严格过滤 |
一次端到端走查(多卡任务 gpu_required=4、gpu_type=nvidia):任务出队进入内置过滤链,离线节点、其他租户专属节点、显存不足节点被剔除;gpu-filter 只留 NVIDIA 节点,resource-filter 只留"显存利用率 <95% 的卡 ≥ 4 张"的节点;score 阶段各评分插件并行对候选打分加权求和(布局策略 + 拓扑 / 网络信号),取最高分节点;BindTask 以 CAS 认领任务,按实时数据复查负载与显存;节点内选卡——有拓扑标签时在最小够用 NVLink 域内凑同 NUMA 四张卡,无拓扑数据时取每卡活跃任务最少的四张;卡组写入任务随下发落库,gpu_used += 4,任务转 scheduled 等待 agent 拉取执行。
任务侧声明清单
任务对调度器的全部表达入口集中在请求体顶层资源字段与 labels 标签,两类各有纪律:
| 声明 | 载体 | 语义 |
|---|---|---|
gpu_type / gpu_required / gpu_memory_mb / cpu_required / memory_mb / priority / preemptible | 顶层字段 | 资源需求与优先级、可抢占声明;preemptible=true 与 task_type=training 组合被 400 拒收 |
nvlink: required / same-numa: required | labels | NVLink 域 / 同 NUMA 硬要求 |
rdma: required | labels | RDMA 节点要求(无标签节点放行,显式不支持节点过滤) |
preferred-region / preferred-zone / preferred-rack | labels(region 亦可作顶层字段) | 拓扑软偏好,命中加分 |
required-region / required-zone / required-rack | labels | 拓扑硬约束,不满足过滤 |
控制面对请求体做严格解码:不认识的顶层字段直接 400 并点名该字段(require_nvlink、topology_constraints 之类不存在的字段不会再被静默忽略);策略类开关(如 require_nvlink)是插件配置而非任务字段,应经插件 API 修改。
调度失败错误码
| 错误码 | 含义 | 后续行为 |
|---|---|---|
NoSchedulableNodes | 无节点通过过滤 / 打分 | 触发抢占规划;pending 超时后判失败 |
InsufficientResources | 绑定期实时复查不通过 | 触发抢占规划或下一轮重试 |
InsufficientGPUMemory | 全部候选节点可用显存不足 | 与 NoNodesAvailable 同规则:pending 超时才判失败,错误信息带需求数值与可用数值 |
NoTenantEligibleGPU | 分片任务因跨租户共卡约束无卡可用 | 明确判失败并标注租户与被排除卡数,绝不静默降级成跨租户放置 |
PreemptionPending | 抢占已发起、资源尚未到账 | 发起方本轮收手留在 pending,下一轮基于真实账本重绑,不计超时失败 |
TaskClaimConflict | CAS 认领未命中(任务已被并发流程认领) | 非故障,静默让路,不告警不触发抢占 |
配置参考
scheduler:
default_task_timeout: 7200 # 任务默认超时(秒)
gpu_reserve_fixed_mb: 500 # 每节点保留显存(固定值)
gpu_reserve_percent: 10 # 每节点保留显存(百分比)
port_range_start: 8000 # 推理服务宿主机端口池
port_range_end: 8999
load_thresholds: # 绑定期实时负载准入阈值
gpu_memory_percent: 95
gpu_utilization_percent: 95
cpu_percent: 90
memory_percent: 90
gpu_temperature_threshold: 79
plugins: # 评分插件开关与权重
spread: { enabled: true, weight: 1 }
binpack: { enabled: false, weight: 0 } # 与 spread 互斥,启用时 binpack 优先
nvlink: { enabled: true, weight: 1 }
topology: { enabled: true, weight: 1 }
rdma: { enabled: true, weight: 1 }
preempt: { enabled: true, weight: 0, extra: { preempt_stage: running } }调度周期(5 秒)与任务队列容量(1000)为代码常量;resource-filter / gpu-filter 无需配置且不受开关影响。主要管理接口:
| 端点 | 方法 | 用途 |
|---|---|---|
/api/v1/plugins | GET | 插件列表(含开关与权重) |
/api/v1/plugins/{name} | GET / PUT | 查看或更新单个插件配置(含 extra 打分参数) |
/api/v1/plugins/{name}?action=enable\|disable | POST | 启停插件(自动处理 spread/binpack 互斥) |
/api/v1/scheduler/plugins | GET | 调度器实际生效的 Filter / Score 插件与 preempt_stage(验收口径) |
/api/v1/scheduler/status / /api/v1/scheduler/queue | GET | 调度器状态 / 调度队列 |
与插件系统的关系
本篇讲的是调度器内置的 8 个调度插件及其调度语义。调度插件体系本身(Plugin / FilterPlugin / ScorePlugin / PreScore / PostScore 扩展点接口、插件生命周期、配置规范、自定义插件开发)是平台通用插件架构的一部分,与通知插件等非调度插件共用同一套插件管理器与管理页面——详见《插件系统》篇。
<!-- 状态标注说明:本文各能力的状态口径如下——"真机验证"指在真实 GPU 节点上端到端运行并确认结果(任务抢占真机验证并修复 3 个实战问题;NVLink 联调因现有测试节点为 PCIe 版无 NVLink 未做,标"适配");"已实现"指代码合入并有单元测试 / 集成测试覆盖,未在真实 GPU 集群端到端验证。国产卡(摩尔线程/海光/沐曦/燧原/天数智芯/壁仞/昇腾)检测逻辑已适配,端到端训练 / 推理验证以 NVIDIA 节点为准。 -->