NUMA-Aware Scheduling

https://zhuanlan.zhihu.com/p/713060080

一、 什么是 NUMA?

NUMA (Non-Uniform Memory Access,非统一内存访问) 是现代多处理器服务器(尤其是AI服务器)的标准架构。

  • 核心思想:将CPU和内存划分为多个“节点”(Node)。每个节点内的CPU访问本节点的内存速度极快(本地内存访问),而访问其他节点的内存则速度较慢(远程内存访问),存在显著的延迟和带宽差异。
  • 类比:想象一个办公室有多个小组,每个小组有自己的文件柜(本地内存)。找自己组的文件柜拿资料很快,但去别的组借资料就要走过去,花时间。

在一台配备8块GPU和2个CPU插槽的AI服务器上,通常会形成2个或4个NUMA节点。GPU通常通过PCIe总线直连到某个特定的CPU(NUMA节点)上。


二、 为什么需要 NUMA-Aware Scheduling?

在传统的、非NUMA感知的调度下,操作系统或调度器(如K8s原生调度器)可能会做出灾难性的决策:

  • 场景:一个需要大量内存的大模型推理Pod被调度到NUMA Node 0上的CPU核心,但它的内存却被分配到了NUMA Node 1上。
  • 后果:该Pod的进程需要频繁地通过“慢速通道”去访问远程内存,导致内存带宽成为瓶颈,CPU和GPU大量时间在等待数据,整体性能可能下降30%甚至更多。这与你追求的“提升集群利用率”和“GPU复用”目标背道而驰。

NUMA-Aware Scheduling 的核心目标就是:让进程(Pod)的计算资源(CPU)和它所需的内存资源,尽可能位于同一个NUMA节点上,从而最大化内存访问速度,消除性能瓶颈。


三、 NUMA-Aware Scheduling 如何工作?

它不是一个单一的功能,而是一套协同工作的策略:

  1. 拓扑感知:调度器(如 Volcano)必须能够感知到集群中每个节点的NUMA拓扑结构,知道哪些CPU核心、哪些内存块、哪些GPU设备属于哪个NUMA节点。
  2. 亲和性绑定
    • CPU亲和性:将Pod的进程绑定到特定NUMA节点的CPU核心上。
    • 内存分配策略:使用 numactl 或内核的 mbind() 系统调用,强制进程的内存从本地NUMA节点分配。
    • 设备亲和性:对于GPU任务,不仅要考虑CPU和内存,还要确保Pod被调度到其GPU所在的NUMA节点上。因为GPU与CPU之间的数据传输(如模型参数加载)也受NUMA影响。
  3. 调度决策:调度器在为Pod选择节点时,不仅要考虑节点的总资源(CPU、内存、GPU),还要考虑该节点内部的NUMA资源分布。它会优先选择能将Pod的所有资源(CPU、内存、GPU)都“塞进”同一个NUMA节点的方案。

四、 Volcano 与 NUMA-Aware Scheduling

Volcano 作为面向高性能计算的调度器,对 NUMA 有原生的支持。

  • 通过插件实现:Volcano 有一个 nodeorder 插件,它可以根据节点的拓扑信息(包括NUMA)对节点进行打分排序。在 allocate Action 的优选阶段,它会选择NUMA局部性最好的节点。
  • 与你的代码阅读关联:你在阅读 Volcano 源码时看到的 nodeOrderFnsBatchNodeOrderFn,正是实现这种“优选”逻辑的钩子。NUMA感知是这些打分函数中一个非常重要的考量维度。

五、 总结

NUMA-Aware Scheduling 不是锦上添花,而是AI时代高性能计算的刚需。 它是在硬件层面为你的“GPU超卖”、“带宽限制”等上层优化保驾护航的基石。