1.1 NUMA 架构基础:定义、与 UMA 的区别、节点与内存域

NUMA(Non-Uniform Memory Access,非统一内存访问)是现代多路服务器与云原生基础设施的核心内存架构。理解 NUMA 是分析容器运行时内存带宽竞争、设计 NUMA 感知调度与容量调优的前提。本节从定义出发,对比 UMA 架构,并拆解 NUMA 节点与内存域的核心概念。

1.1.1 什么是 NUMA?

NUMA 是一种为多处理器系统设计的内存架构。在 NUMA 系统中,每个处理器(或处理器组)被分配一个本地内存域,处理器访问本地内存的速度远快于访问其他处理器所关联的远程内存。这种“非统一”的访问延迟与带宽差异,是 NUMA 架构的本质特征。

核心要点: NUMA 通过将内存物理地分布到每个处理器附近,解决了传统 SMP/UMA 架构中内存总线带宽瓶颈,但引入了跨节点访问的代价(Remote Access Penalty)。

1.1.2 NUMA 与 UMA 的对比

UMA(Uniform Memory Access,统一内存访问)是 NUMA 之前的经典架构。下表从关键维度对比两者差异:

对比维度 UMA(对称多处理 SMP) NUMA(非统一内存访问)
内存访问方式 所有处理器通过共享总线访问同一块物理内存 每个处理器(或一组处理器)拥有本地内存,可访问远程内存
访问延迟 所有内存访问延迟一致(统一) 本地访问快,远程访问慢(非统一)
内存带宽 受限于共享总线带宽,扩展性差 总带宽随节点数增加而线性增长,扩展性好
可扩展性 通常支持 2~8 个 CPU,超过后总线成为瓶颈 支持数十甚至上百个 CPU 核心,适合大规模服务器
编程模型 对操作系统和应用程序透明,无需感知拓扑 需要操作系统和应用程序感知 NUMA 拓扑,进行亲和性优化
典型应用 早期 PC、小型服务器、嵌入式系统 现代数据中心服务器、云基础设施、高性能计算
工程启示: 在容器编排场景中,UMA 架构下无需关心内存位置;但在 NUMA 架构下,容器 vCPU 与内存的分配位置直接决定了内存带宽竞争程度和应用性能。NUMA 感知是容器性能调优的必修课。

1.1.3 NUMA 节点与内存域

NUMA 架构由两个核心抽象构成:NUMA 节点和内存域。它们是操作系统内核(尤其是 Linux)管理物理资源的基本单元。

  • NUMA 节点(NUMA Node): 物理上由一个或多个 CPU 核心、本地内存控制器(IMC)以及本地内存条(DIMM)组成的集合。每个节点在 Linux 内核中被分配一个唯一的节点 ID(从 0 开始)。节点内的 CPU 访问本地内存延迟最低。
  • 内存域(Memory Zone / ZONE): Linux 内核将每个 NUMA 节点的物理内存进一步划分为多个内存域,用于管理不同用途的内存分配。常见的内存域包括:
    • ZONE_DMA / ZONE_DMA32: 用于需要直接内存访问(DMA)的设备,地址空间受限。
    • ZONE_NORMAL: 常规内存映射区域,大多数应用程序内存分配发生在此域。
    • ZONE_HIGHMEM: 仅存在于 32 位系统,用于访问超过 4GB 的物理内存(现代 64 位系统已不再使用)。
    • ZONE_MOVABLE: 用于可迁移页面,支持内存热插拔和碎片整理。

下图展示了双路 NUMA 服务器的典型拓扑结构,包含两个 NUMA 节点及其内部的内存域划分:

双路 NUMA 服务器拓扑与内存域结构 双路 NUMA 服务器拓扑与内存域结构 NUMA Node 0 CPU 核心组 Core 0 - Core N L1/L2/L3 Cache 本地内存控制器 IMC DDR4/DDR5 通道 本地物理内存 (DIMM) 容量: 64GB / 128GB / 256GB 内存域 (ZONE) 划分 ZONE_DMA32 | ZONE_NORMAL | ZONE_MOVABLE 内核管理不同用途的内存分配 NUMA Node 1 CPU 核心组 Core 0 - Core N L1/L2/L3 Cache 本地内存控制器 IMC DDR4/DDR5 通道 本地物理内存 (DIMM) 容量: 64GB / 128GB / 256GB 内存域 (ZONE) 划分 ZONE_DMA32 | ZONE_NORMAL | ZONE_MOVABLE 内核管理不同用途的内存分配 互联 远程访问路径 延迟更高,带宽更低

1.1.4 Linux 内核中的 NUMA 拓扑表示

Linux 内核通过 struct pglist_data(每个 NUMA 节点一个)和 struct zone(每个内存域一个)来管理 NUMA 拓扑。系统管理员和开发者可以通过以下方式查看 NUMA 拓扑:

# 查看 NUMA 节点数量与 CPU/内存分布
numactl --hardware

# 查看每个 NUMA 节点的内存域信息
cat /proc/zoneinfo

# 查看进程的 NUMA 内存分配策略
cat /proc/<PID>/numa_maps
常见误区: 许多开发者误以为 numactl --hardware 输出的“node distances”只是参考值。实际上,这些距离值直接影响了内核的 slab 分配器、页面回收策略以及容器 cpuset 的默认行为。忽略距离值会导致跨节点内存分配失控。

1.1.5 内存域与容器内存分配的关系

在容器运行时(如 containerd + runc),每个容器进程的内存分配最终由内核的内存域(ZONE)管理。当容器被绑定到特定 NUMA 节点(通过 cpuset cgroup)时,内核优先从该节点的 ZONE_NORMAL 分配内存。如果该节点内存不足,内核会跨节点分配(Remote Allocation),从而引入带宽竞争和延迟抖动。

下表总结了不同内存域在容器场景下的典型用途:

内存域 典型用途 容器场景影响
ZONE_DMA32 设备驱动、DMA 缓冲区 容器通常不直接使用,但宿主机网络/存储驱动会占用
ZONE_NORMAL 应用程序堆、栈、匿名页、文件页缓存 容器进程的主要内存来源,NUMA 本地分配优先
ZONE_MOVABLE 可迁移页面(透明大页、虚拟化内存) 容器内存热迁移、碎片整理的关键域