异构算力调度:资源池幻觉与可验证的折中
九月的南京,一场产学研闭门会上,有人抛出一张监控图:集群平均空闲率18%,队列却排到第二天。会议室安静了几秒。问题不在“没卡”,而在调度器看见的卡和任务需要的卡不是同一种东西。
异构算力调度常被描述成把GPU、NPU、CPU塞进一个池子。这个说法省事,也危险。池子里每个设备的能力边界并不一样:显存、互联、算子、驱动、故障域,任何一项错配都能让“空闲”变成“不可用”。
空闲率会骗人:资源画像的粒度
调度器的输入决定它的上限。只记录卡数和显存,等于把异构设备压成同质标量。训练任务要的是显存、SM占用、NVLink域、PCIe带宽、NCCL版本;推理任务还要看算子支持、批处理窗口、尾延迟预算。NPU与GPU的指令集差异更直接:同一个模型,算子图在一边能跑,另一边要回退。
所以资源画像应该是带时间窗和置信度的多维向量,而不是瞬时快照。采样太粗,调度做出错误放置;采样太细,代理开销和标签维护又压垮节点。折中办法是分层:节点级粗画像做初筛,设备级细画像在候选节点上二次校验。拓扑标签要显式建模,比如同一NVLink域、同一NUMA节点、跨叶交换机。别小看这些标签,它们是碎片化的来源,也是减少跨域流量的抓手。
异构算力调度集群GPU与NPU资源画像监控界面
反例也常见:画像更新滞后于任务到达,调度器把任务放到刚被占用的设备上,引发抢占和重排。抖动一多,队列看起来更忙,吞吐反而下降。资源画像的时效性比维度数量更值得先解决。没有时效,维度只是装饰。
多目标没有单一解:吞吐、尾延迟与成本的拉扯
把调度目标写成一个数,工程上很诱人。集群吞吐高就行?在线推理的尾延迟会抗议。成本低就行?批训练可能被反复抢占,checkpoint开销吃掉收益。公平性、隔离、能耗、许可证约束也在场。多目标之间不是加法,更多时候是交换。
可行的路径是分层:全局层做放置和配额,本地层做重排和回填。全局层用约束规划处理硬约束——设备类型、显存下限、拓扑亲和、租户配额;本地层用队列策略处理软目标——短任务插空、长任务保序、gang scheduling保证多卡任务同时起步。拓扑感知要参与打分,但打分函数不宜过重,否则每次调度都变成一次小规模求解。
数据中心异构算力调度任务拓扑与网络带宽监控图
抢占是另一个容易踩坑的地方。条件很清楚:只有当checkpoint成本低于等待收益时,抢占才成立。否则调度器只是在制造上下文切换。一个反例是显存碎片整理:为了合并空闲块,强行迁移运行中的任务,跨NUMA访问增加,带宽争用把尾延迟推高。碎片少了,SLA坏了。这笔账要算在调度策略里,不能只看利用率。
可验证性:调度决策的审计与回放
智能调度听起来好,落地时先问一句:出了问题,能不能回放?资源快照、约束集合、打分结果、随机种子、抢占记录,这些不留下,事后只能猜。黑盒策略在负载漂移时失效,团队无法归因,最后又退回手工规则。不是算法不行,是决策链不可审计。
可验证的做法不复杂:策略沙箱、影子调度、历史回放。新策略先在影子模式跑,和在线决策对比资源占用与SLA违约,再小流量切换。仿真环境要保留拓扑和故障注入,否则回放只是 happy path。跨域调度还要加一条:网络成本与数据合规必须进入约束,不能把“算力可达”当成“任务可迁”。
边界也要说清。小集群、任务类型单一时,手工规则加简单队列足够,过度画像和全局求解是负担。多租户、多设备类型、SLA分层的场景,才需要更细的画像和审计。调度器不必假装全知。承认不确定性,把置信度、回退路径和人工干预入口暴露出来,往往比追求一个漂亮的目标函数更可靠。