NUMA (Non-Uniform Memory Access)
3 秒看懂
一句话: NUMA 是多处理器服务器的内存访问架构——每个 CPU 能”快”访问自己的本地内存,“慢”访问其他 CPU 的远端内存。内存的位置决定了访问的速度,这就是”非均匀”的含义。
关键词: 本地内存 / 远端内存 / NUMA 节点 / 内存亲和性
为什么重要: AI 大模型训练/推理服务器几乎全是多路 NUMA 架构,忽视 NUMA 拓扑可导致内存带宽损失 30%~50%(视负载而定),是基础设施层最容易被忽略却代价极高的性能陷阱。
3 分钟产业解释
问题的起源
早期对称多处理器(SMP/UMA)架构中,所有 CPU 通过同一条前端总线访问同一块共享内存。CPU 核数增长后,总线成为瓶颈——所有处理器”抢”同一条通道,带宽和延迟同时恶化。
NUMA 的解法: 不再把所有内存放在一起。给每个 CPU(或 CPU 组)分配一块”本地内存”,CPU 之间通过高速互联链路互相访问对方的内存。本地访问快、远端访问慢——架构由此”非均匀”。
┌─────────────────────────────────────────────────┐
│ 服务器主板 │
│ │
│ ┌──────────────┐ 互联总线 ┌──────────────┐│
│ │ CPU 0 │◄══════════════►│ CPU 1 ││
│ │ ┌────────┐ │ (UPI/IF/QPI) │ ┌────────┐ ││
│ │ │本地内存 │ │ │ │本地内存 │ ││
│ │ │ (快) │ │ │ │ (快) │ ││
│ │ └────────┘ │ │ └────────┘ ││
│ └──────────────┘ └──────────────┘│
│ NUMA Node 0 NUMA Node 1 │
└─────────────────────────────────────────────────┘
产业中谁在用?
| 场景 | 为何需要关心 NUMA |
|---|---|
| AI 训练服务器 | 多路 Xeon/EPYC,GPU 通过 PCIe/CXL 挂在特定 NUMA 节点下,跨节点访问 GPU 显存回传的数据会穿透远端内存 |
| 数据库(OLTP/OLAP) | In-memory DB 的 Buffer Pool 分配在哪个 NUMA 节点直接影响 QPS |
| 云计算/虚拟化 | Hypervisor 的 vCPU-pCPU 绑定和内存分布直接影响 VM 性能 SLA |
| HPC | MPI 进程绑定 NUMA 节点是基操 |
| 高频交易 | 纳秒级敏感,任何跨节点延迟不可接受 |
15 分钟专家深入
NUMA 的核心代价:远端访问的延迟与带宽惩罚
在现代双路服务器中,CPU 访问本地内存与跨 Socket 访问远端内存的延迟比大约在 1:1.5 至 1:2+ 范围内(具体取决于平台代际和互联方案,此处为定性估算,不同平台差异显著)。带宽方面,跨 Socket 访问受限于互联链路(如 Intel UPI 或 AMD Infinity Fabric)的可用带宽,远端有效带宽通常低于本地内存通道带宽之和。
延迟示意(相对值,非精确 ns,平台相关):
本地 DRAM 访问: ████████████████████ ~1.0x (基准)
远端 DRAM (1-hop): ████████████████████████████████ ~1.5x - 2.0x+
↑
互联链路额外延迟
NUMA 拓扑的”距离”概念
Linux 内核通过 ACPI SLIT(System Locality Information Table) 获取每个 NUMA 节点之间的”距离”。这是一个相对值,本地节点到自身的距离固定为 10,远端节点的距离大于 10(常见的双路系统中远端距离约 20~30,具体值由固件/BIOS 报告)。
# 查看 NUMA 距离矩阵
$ numactl --hardware
available: 2 nodes (0-1)
node 0 cpus: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 ...
node 0 size: 131072 MB
node 1 cpus: 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 ...
node 1 size: 131072 MB
node distances:
node 0 1
0: 10 21
1: 21 10
距离值越大,延迟和带宽劣势越明显。
芯片粒(Chiplet)时代的 NUMA 更复杂
这是当前最容易被误解的地方。
传统单 Die 多核 CPU 上,一个 Socket = 一个 NUMA 节点。但 AMD EPYC 的 Chiplet 架构 在单个 Socket 内部也存在非均匀内存访问特性:
- 每个 CCD(Core Complex Die)包含若干核心和本地 L3 Cache
- 不同 CCD 访问同一 Socket 内不同内存通道的延迟不同(取决于 Infinity Fabric 路由拓扑)
- 因此 BIOS 中可设置 NPS(NUMA Per Socket) 参数:
- NPS1:整个 Socket 作为一个 NUMA 节点(简化拓扑,但隐藏了内部非均匀性)
- NPS2:Socket 分为 2 个 NUMA 节点
- NPS4:Socket 分为 4 个 NUMA 节点(最细粒度,最贴近真实拓扑)
这意味着 一个 2 路 EPYC 服务器在 NPS4 模式下可以呈现 8 个 NUMA 节点,而非直觉中的 2 个。
Intel 的 Xeon Scalable(至强可扩展)系列在 Sapphire Rapids / Emerald Rapids 代际也开始采用多 Tile 设计,但 NUMA 模式设置的灵活性和粒度与 AMD 有差异,此处不做具体代际归属(因具体 BIOS 选项与固件版本相关)。
内存分配策略
Linux 内核的 NUMA 策略(通过 set_mempolicy() 或 mbind() 系统调用配置):
| 策略 | 行为 |
|---|---|
| default(本地分配) | 进程在哪个 CPU 上首次触及页面,内存就分配在哪个节点(First-Touch) |
| bind | 强制分配到指定节点(集),即使该节点内存不足 |
| interleave | 在多个节点间轮转分配,适合大块共享内存(如数据库共享缓冲池) |
| preferred | 优先分配到指定节点,不足时回退到其他节点 |
AI 场景中常见问题: PyTorch DataLoader 的 worker 进程在 CPU 0 上初始化张量(First-Touch 分配到 Node 0),但实际训练计算在绑到 Node 1 的 GPU/线程上执行——造成所有内存访问都是远端访问。
技术原理
NUMA 系统的硬件拓扑
┌──────────────────────────────────────────────────────────┐
│ 双路 NUMA 服务器 │
│ │
│ ┌─────────────────────────┐ UPI/IF ┌─────────────────────────┐
│ │ Socket 0 │◄═══════════►│ Socket 1 │
│ │ │ │ │
│ │ ┌─────┐ ┌─────┐ │ │ ┌─────┐ ┌─────┐ │
│ │ │Core0│ │Core1│ ... │ │ │CoreN│ │CoreN+1│ ... │
│ │ └──┬──┘ └──┬──┘ │ │ └──┬──┘ └──┬──┘ │
│ │ └───┬───┘ │ │ └───┬───┘ │
│ │ ┌────▼────┐ │ │ ┌────▼────┐ │
│ │ │ L3 Cache│ │ │ │ L3 Cache│ │
│ │ └────┬────┘ │ │ └────┬────┘ │
│ │ ┌────▼────┐ │ │ ┌────▼────┐ │
│ │ │内存控制器│◄───┐ │ │ │内存控制器│◄───┐ │
│ │ └─────────┘ │ │ │ └─────────┘ │ │
│ │ ┌───┴───┐ │ │ ┌───┴───┐ │
│ │ │DIMM×N │ │ │ │DIMM×N │ │
│ │ │(本地) │ │ │ │(本地) │ │
│ │ └───────┘ │ │ └───────┘ │
│ │ │ │ │
│ │ ┌──────┐ ┌────────┐ │ │ ┌──────┐ ┌────────┐ │
│ │ │ PCIe │ │PCIe/GPU│ │ │ │ PCIe │ │PCIe/GPU│ │
│ │ │Root │ │ Root │ │ │ │Root │ │ Root │ │
│ │ └──────┘ └────────┘ │ │ └──────┘ └────────┘ │
│ └─────────────────────────┘ └─────────────────────────┘
│ NUMA Node 0 NUMA Node 1 │
└──────────────────────────────────────────────────────────┘
关键机制:缓存一致性与互联协议
在 NUMA 多处理器系统中,各 Socket 的 L3 Cache 之间需要保持一致性。主流方案:
- Intel: 基于目录(Directory-based)的缓存一致性协议,通过 UPI(Ultra Path Interconnect) 传输 snoop 和数据。UPI 链路带宽为平台代际相关,Sapphire Rapids 代际的 UPI 链路速率有具体规格但此处不编造精确数字。
- AMD: Infinity Fabric 承载缓存一致性流量和内存访问流量。EPYC 代际间的 Infinity Fabric 代际和速率不同,此处不列精确数字。
当 Socket 0 的核心需要读取 Socket 1 的内存数据时,流程大致为:
Core0 (Socket 0) 读取远端地址
│
▼
本地 L1/L2 Cache 未命中
│
▼
本地 L3 Cache 未命中
│
▼
内存控制器判断为远端地址
│
▼
通过互联链路 (UPI / Infinity Fabric) 发送请求到 Socket 1
│
▼
Socket 1 的内存控制器从本地 DRAM 读取数据
│
▼
数据通过互联链路返回 Socket 0
│
▼
Core0 收到数据(总延迟 = 本地内存控制器处理延迟 + 远端 DRAM 访问延迟 + 2× 互联延迟)
延迟的额外来源: 互联链路的序列化/反序列化(SerDes)、协议层开销、拥塞竞争。
NUMA 对 AI 基础设施的具体影响
1. 内存带宽不对称
现代服务器 CPU 通常有 8~12 个内存通道(平台代际相关)。当训练进程跨越两个 NUMA 节点时,可用内存带宽不等于两个节点的通道带宽之和——受限于互联链路带宽,且存在额外的协议开销。
2. PCIe 设备亲和性
GPU 通过 PCIe Root Complex 挂在特定 Socket 下。当 GPU 通过 GPUDirect RDMA 与网络/NVMe 交换数据,或者 CPU 端需要访问 GPU 内存时,如果 CPU 线程不在与 GPU 同属一个 NUMA 节点的 Socket 上,每次 PCIe 事务都需穿越互联链路:
非最优配置:
GPU 0 (挂在 Socket 0) ◄──PCIe── Socket 0 ──UPI──► Socket 1 ──► 训练线程
↑ 额外一跳
最优配置:
GPU 0 (挂在 Socket 0) ◄──PCIe── Socket 0 ──► 训练线程(绑定在同一 Socket)
3. Megatron-LM 等框架的考虑
分布式训练框架中,数据并行的梯度 AllReduce 通信与模型并行的张量切分通信,都会涉及 CPU 端的内存分配和缓冲区。NUMA 不感知的缓冲区分配可能导致通信延迟抖动。
技术演进史
| 时期 | 事件 | NUMA 意义 |
|---|---|---|
| ~1990s 早期 | SGI Origin 2000 等系统引入 ccNUMA(Cache-Coherent NUMA) | 首次在商业系统中实现缓存一致的非均匀内存访问 |
| 2000s | AMD Opteron(K8)通过 HyperTransport 实现原生 NUMA;Intel Xeon 仍采用共享前端总线的 UMA 架构 | NUMA 率先由 AMD 引入 x86 服务器市场 |
| 2008~2012 | Intel Nehalem-EP (Gainestown) 首次在其至强平台上集成内存控制器与 QPI 互联,实现双路 NUMA;后续 Nehalem-EX / Westmere-EX 扩展至四路及以上多路 NUMA | Intel 在 CPU 内集成内存控制器和点对点互联,x86 原生多路 NUMA 普及 |
| 2017~ | AMD EPYC(Zen 架构)以 Chiplet + Infinity Fabric 重塑 NUMA 拓扑 | 单 Socket 内部出现多级 NUMA 特性(NPS 选项) |
| 2019~2023 | AMD EPYC Milan/Genoa,Intel Sapphire Rapids | 单 Socket 核数进一步增加(64~128 核),NUMA 拓扑管理对性能的影响更显著 |
| 2024~ | CXL(Compute Express Link)内存池化开始落地 | CXL 引入新的内存层级——CXL 内存的延迟通常高于远端 NUMA 延迟,NUMA 模型进一步复杂化 |
技术路线对比
UMA vs NUMA vs CXL 扩展内存
| 维度 | UMA(共享总线/交叉开关) | NUMA(分布式内存) | CXL 内存扩展(新兴) |
|---|---|---|---|
| 内存访问延迟 | 均匀,但随核数增长总线争用加剧 | 本地快、远端慢,比值约 1:1.5~2+(平台相关) | 通常高于远端 NUMA 延迟(估算,平台/拓扑相关) |
| 可扩展性 | 差(总线带宽瓶颈) | 好(通过互联链路横向扩展) | 极好(内存池化,容量独立于 CPU) |
| 编程模型复杂度 | 低 | 中(需 NUMA 感知的内存分配) | 高(新的内存层级,需应用适配) |
| 适用场景 | 小规模对称多处理 | 大规模多路服务器、HPC、AI 训练 | 内存密集型应用、内存池化、云 |
| 主流代表 | 早期 Intel Xeon(FSB 时代) | 当前所有多路 x86 服务器 | CXL 1.1/2.0 设备(逐步商用) |
Intel vs AMD 的 NUMA 实现差异
| 维度 | Intel Xeon Scalable | AMD EPYC |
|---|---|---|
| 互联技术 | UPI(Ultra Path Interconnect) | Infinity Fabric |
| Socket 内 NUMA 粒度 | 通常 Socket = 1 NUMA 节点(Tile 架构后可能有变化) | NPS1/2/4 可配置,粒度更灵活 |
| Chiplet 架构影响 | Sapphire Rapids 起采用 Multi-Tile,但 NUMA 模式设置较少被讨论 | Chiplet 原生架构,单 Socket 内部就有 NUMA 特性 |
| 2 路系统典型 NUMA 节点数 | 2(默认) | 2~8(取决于 NPS 设置) |
| 内存通道数 | 8(SPR/EMR 代际) | 12(Genoa 代际)[来源:AMD 官方规格] |
上下游
上游(NUMA 依赖的技术和组件)
NUMA 硬件架构
├── CPU 微架构
│ ├── 内存控制器(集成在 CPU 内)
│ ├── L3 Cache 及一致性协议
│ └── 芯片粒间互联(Chiplet IF / Tile 间互联)
├── 互联总线
│ ├── Intel UPI / 早期 QPI
│ ├── AMD Infinity Fabric
│ └── 未来: UALink / CXL 等
├── 内存子系统
│ ├── DDR4/DDR5 DIMM
│ ├── HBM(特定加速器,与 CPU NUMA 概念平行但相关)
│ └── CXL 内存(新兴)
├── 固件/BIOS
│ ├── ACPI SLIT 表(报告节点间距离)
│ ├── ACPI SRAT 表(报告处理器与内存的归属关系)
│ └── NPS/NUMA 模式设置(BIOS 选项)
└── 操作系统
├── NUMA 调度器(Linux: NUMA balancing)
├── 内存分配策略(set_mempolicy / mbind)
└── 工具链(numactl / numastat / libnuma)
下游(NUMA 影响的应用层)
受 NUMA 影响的应用领域
├── AI/ML 训练与推理
│ ├── 分布式训练框架(PyTorch DDP / DeepSpeed / Megatron-LM)
│ ├── GPU 通信拓扑(PCIe 亲和性、NVLink 域)
│ └── 推理引擎内存分配(vLLM / TensorRT-LLM 的 KV Cache)
├── 数据库
│ ├── 内存数据库(Redis Cluster / SAP HANA / VoltDB)
│ ├── 传统 OLTP(MySQL / PostgreSQL 大规模部署)
│ └── 分析型数据库(ClickHouse / DuckDB)
├── 虚拟化与云
│ ├── Hypervisor NUMA 感知调度(KVM/ESXi)
│ ├── 容器 NUMA 绑定(kubelet --topology-manager-policy)
│ └── SR-IOV / VFIO 设备亲和性
├── HPC / 超算
│ ├── MPI 进程绑定
│ └── OpenMP 线程绑定
└── 网络与存储
├── DPDK 收发包(NUMA 绑定影响 PPS)
└── NVMe 存储(PCIe NUMA 亲和性影响 IOPS/延迟)
关键指标
| 指标 | 含义 | 量级参考(定性,平台相关) |
|---|---|---|
| NUMA 距离 | SLIT 表中的相对值 | 本地=10,远端通常 20~30(双路系统) |
| 本地内存延迟 | CPU 访问本地 DRAM 的延迟 | 约 80~120ns(DDR5 平台,估算,平台/频率相关) |
| 远端内存延迟 | CPU 访问远端 DRAM 的延迟 | 本地延迟的 |
| 互联链路带宽 | Socket 间传输数据的带宽上限 | 取决于互联代际和链路数,定性描述为”高于单通道但低于全部本地通道之和” |
| NUMA 未命中率 | 分配在远端节点的内存访问占比 | 应趋近于 0%,越低越好(可通过 numastat 观察) |
| 跨节点内存带宽利用率 | 互联链路的实际使用率 | 过高意味着跨节点访问过多,是优化信号 |
供需与市场数据
NUMA 为什么在 AI 时代更关键
-
单服务器内 CPU 核数激增: 128 核的 EPYC 单 Socket 已普及(Zen 4c 甚至更多),核数越多,NUMA 感知调度的影响越大。
-
GPU 服务器的 CPU-GPU 拓扑绑定: NVIDIA DGX 系列、HGX 主板等 AI 训练平台,GPU 通过 PCIe/NVLink 挂在特定 CPU Socket 下。数据中心运维需要精确配置 CPU 线程与 GPU 的 NUMA 亲和性。
-
内存容量需求爆发: 大模型推理的 KV Cache、Embedding Table 等需要 TB 级内存,往往需要跨节点分配。NUMA 感知的内存放置直接影响服务延迟。
-
CXL 引入第三层内存: CXL Type 3 内存设备将创造介于本地 DRAM 和远端 DRAM 之间的新延迟/带宽层级,应用需要更精细的 NUMA 模型。
市场驱动方
| 角色 | 代表 | NUMA 关注点 |
|---|---|---|
| CPU 厂商 | AMD、Intel | NUMA 拓扑设计直接影响产品竞争力(核心间延迟、互联带宽) |
| 云厂商 | AWS / Azure / GCP / 阿里云 | NUMA 感知的虚拟机调度直接影响租户性能和资源利用率 |
| AI 基础设施商 | NVIDIA、超微、联想、浪潮 | 服务器硬件设计中 GPU-CPU NUMA 拓扑是关键设计决策 |
| 操作系统/调度器 | Linux Kernel 社区、Kubernetes SIG-Node | NUMA-aware scheduling 是持续优化方向 |
代表公司与资本映射
| 层级 | 公司/组织 | 与 NUMA 的关系 |
|---|---|---|
| CPU 架构设计 | AMD(EPYC)、Intel(Xeon) | NUMA 拓扑的创造者和定义者 |
| 互联技术 | AMD(Infinity Fabric)、Intel(UPI)、CXL Consortium | Socket 间互联的质量决定远端访问代价 |
| 服务器 ODM/OEM | 超微 (SMCI)、Dell、HPE、浪潮、联想 | 硬件布局(DIMM 插槽、PCIe 路由)影响 NUMA 拓扑 |
| 云/AI 基础设施 | AWS(Nitro)、Azure、NVIDIA(DGX/HGX) | 暴露或隐藏 NUMA 拓扑给用户层 |
| OS/虚拟化 | Linux Kernel 社区、Red Hat、VMware (Broadcom) | NUMA 调度和策略的实现者 |
| 应用框架 | PyTorch (Meta)、NVIDIA (NeMo/Megatron) | NUMA-aware 数据加载和内存分配 |
| CXL 生态 | Samsung、SK Hynix、Microchip、XConn | CXL 内存扩展带来新的 NUMA 层级 |
注意: NUMA 不是一个独立的商业产品或技术赛道,而是所有多处理器计算系统的基础设施特性。它对上游(CPU/互联架构)有设计约束,对下游(所有多线程/多进程应用)有性能影响。
投资逻辑
核心观点
NUMA 本身不可投资,但它是理解以下投资主线的底层基础设施知识:
1. AI 算力效率优化 → 间接影响服务器 ASP 和云利润率
忽视 NUMA 的 AI 集群实际算力利用率显著低于理论峰值。云厂商和 AI 公司的集群优化(包括 NUMA 感知调度)可以将有效算力提升可观幅度(具体幅度因负载和基线配置而异,此处不编造精确百分比)。这意味着:
- 集群优化软件/平台 有真实价值
- 硬件拓扑设计(GPU 与 CPU 的 NUMA 绑定方案)是 AI 服务器 ODM 的差异化能力
2. CXL 内存池化 → 新的内存层级重构 NUMA 模型
CXL 的落地将改变传统”本地/远端”二元 NUMA 模型,引入多层级内存(本地 DRAM → CXL 内存 → 远端 DRAM)。这为:
- CXL 控制器/交换芯片厂商(如 Microchip、XConn)创造增量市场
- 内存厂商(三星、SK 海力士、美光)创造 CXL 内存模组的新品类
- 操作系统和应用框架需要适配新的内存层级
3. 服务器核数持续增长 → NUMA 复杂度只增不减
随着 Chiplet 架构成为主流、单 Socket 核数持续增加,NUMA 拓扑管理的复杂度上升。这利好:
- 具有 NUMA 感知能力的调度/编排平台
- 能够提供硬件拓扑可见性和优化建议的可观测性工具
常见误读纠偏
误读 1:「NUMA 只影响多路(Multi-Socket)服务器,单路服务器不用关心」
纠偏: 这在传统单 Die CPU 上基本成立,但在 Chiplet 架构下已不正确。AMD EPYC 的单 Socket 内部就有多个 CCD,不同 CCD 访问不同内存通道的延迟存在差异。通过 NPS 设置,单 Socket 可以呈现为多个 NUMA 节点。即使是单路服务器,如果 BIOS 设置为 NPS4 且应用未做 NUMA 绑定,同样可能遭受跨节点访问的性能损失。对于 AI 训练场景,即使是单路 8-GPU 服务器(如部分推理平台),GPU 与 CPU 核心的 NUMA 拓扑也需要关注。
误读 2:「内存插满就等于内存带宽最大化,NUMA 不重要」
纠偏: 内存带宽的最大化不仅取决于 DIMM 数量,还取决于 DIMM 在各节点间的分布均匀性 以及 访问模式是否落在本地节点。如果 8 条 DIMM 全部插在一个 Socket 侧(物理上不太可能但概念上有此误解),或者训练进程的线程分布在 Node 0 但内存分配在 Node 1,即使插满 DIMM 也远达不到理论带宽。正确的做法是:每个 Socket 的每个通道都插满 DIMM + 确保线程和内存分配在同一 NUMA 节点内。
误读 3:「Linux 的自动 NUMA Balancing 会自动解决所有问题」
纠偏: Linux 内核的 Automatic NUMA Balancing 通过周期性地将页面迁移到访问它的 CPU 所在节点来改善 NUMA 局部性。但它有以下局限:
- 迁移有开销: 页面迁移本身需要消耗内存带宽和 CPU 周期
- 迁移有延迟: 需要多轮扫描和统计才触发迁移,不适合短生命周期的工作负载
- 不可预测: 对延迟敏感的工作负载(如在线推理服务),自动迁移带来的性能抖动可能比远端访问本身更糟糕
- 最佳实践: 对于已知拓扑和负载模式,显式使用
numactl、taskset、cpuset进行绑定,比依赖自动 NUMA Balancing 更可靠
误读 4:「NUMA 距离值越大就一定越慢」
纠偏: SLIT 表中的 NUMA 距离是固件报告的相对值,不同平台/BIOS 版本报告的绝对值可能不同。距离值在 同一平台内 有比较意义(Node 0→1 的距离比 Node 0→2 小,则前者延迟通常更低),但 跨平台比较无意义——不同厂商的 SLIT 报告规范不完全统一。此外,NUMA 距离反映的是 平均延迟,实际延迟还受互联链路拥塞程度、并发访问模式等动态因素影响。
学习路径
入门(0~2 小时)
- Linux
numactl --hardware实操: 在任何多路 Linux 服务器上运行,观察 NUMA 节点数量、CPU 核心分配和距离矩阵 numastat观察: 查看各节点的内存分配和命中/未命中统计- 阅读 Red Hat “NUMA Awareness” 文档(搜索 Red Hat NUMA tuning guide)
进阶(1~3 天)
numactl --membind/--cpunodebind实验: 分别将程序绑定到本地和远端节点,用mbw或Intel MLC(Memory Latency Checker)测量带宽和延迟差异