一句话定义:NUMA 亲和(NUMA Affinity)是把进程或线程固定在某个 NUMA 节点上运行,同时让它的内存在同一个节点里分配,避免跨插槽取数据。
背景:NUMA 是什么
多路服务器上插着两颗、四颗 CPU,每颗 CPU 自带内存控制器,直连一部分内存条。一台机器因此被切成几个 NUMA 节点(Non-Uniform Memory Access,非统一内存访问)。CPU 读自己直连的内存,走本地通道;读另一颗 CPU 名下的内存,必须先经过 CPU 之间的互连通道绕过去。
就像开放式办公室里几个小组,每组身后有自己的文件柜。拿自家柜子里的材料,伸手就到;材料在隔壁组柜子里,得穿过走廊,而走廊只有一条,所有人一起去挤就会堵。NUMA 节点就是「CPU + 它身后的柜子」,跨节点访问就是穿走廊。
为什么它卡住推理吞吐
大模型推理的解码阶段是典型的内存带宽敏感型负载:每生成一个 token,都要把权重和 KV 缓存至少读一遍。瓶颈往往不在算力,而在「把字节搬到计算单元」的速度。如果一部分数据躺在远端节点,它们就得挤那条共享互连,延迟更高、带宽更低,还和其他流量抢道——算力吃不饱,吞吐上不去,延迟抖动也更明显。
| 本地节点访问 | 跨节点访问 | |
|---|---|---|
| 路径 | CPU → 本地内存控制器 → 内存 | CPU → 互连 → 对方控制器 → 内存 |
| 延迟 | 低 | 明显更高 |
| 带宽 | 独享本地通道 | 争抢共享互连 |
| 影响 | 基本无所谓 | 带宽敏感负载最吃亏 |
延迟差多少、带宽差多少,取决于厂商和机型,别记固定数字。
和相邻概念的区别
CPU 亲和(CPU affinity)只管线程在哪跑,不管内存落在哪。常见翻车场景就是绑了核、内存却落在远端节点,白绑。NUMA 亲和是「线程位置 + 内存位置」一起管。
自动 NUMA 均衡(automatic NUMA balancing)是内核定期探测并搬页的兜底机制,它不替你规划拓扑,高频访问下搬迁本身也有成本,关键路径别指望它兜住。
还有个容易踩的坑叫首次触碰(first-touch):内存页物理上分配给第一个写它的线程所在的节点。若初始化时主线程一口气把大数组写完,所有页都落在它的节点,之后 worker 线程全在跨节点访问。批量加载权重、开大 buffer 时值得留意这个顺序。
对从业者的实际意义
- 单机多卡推理:先确认 GPU 挂在哪个插槽的 PCIe 下,让喂数据的进程和内存都待在该插槽的节点,主机到设备(host-to-device)的数据搬运才不会绕远路。
- CPU 推理框架通常暴露线程数和 NUMA 相关开关,多路机器上花时间调这一项,性价比往往高于改模型。
- 容器与编排平台默认常常看不到完整拓扑,需要显式的拓扑感知调度或资源策略,具体能力以官方文档为准。
- 挑云主机时,「几路」比「多少核」更能说明内存带宽上限——核数相同的两台机器,可能完全不是一个量级。
