NUMA 架构基础:什么是 NUMA,UMA 与 NUMA 的区别,NUMA 节点与内存访问延迟

1. 从 UMA 到 NUMA:对称多处理器的内存瓶颈

在对称多处理器(SMP)系统发展的早期,所有处理器核心通过一条共享的前端总线(FSB)或交叉开关连接到统一的内存控制器,所有内存访问具有相同的延迟和带宽。这种架构称为 UMA(Uniform Memory Access,统一内存访问)。

随着处理器核心数量的增长(从 4 核到 64 核甚至更多),UMA 架构面临严重的 总线争用 和 内存墙 问题:

  • 带宽瓶颈:所有核心共享同一条内存通道,核心越多,每个核心获得的平均内存带宽越低。
  • 延迟增加:内存控制器需要处理来自所有核心的请求,队列深度增加导致访问延迟显著上升。
  • 扩展性差:增加核心数量无法线性提升系统性能,甚至可能因为缓存一致性协议(如 MESI)的广播开销导致性能下降。
关键认知: UMA 架构在 8 核以下表现良好,但超过 16 核后,内存访问的竞争和延迟成为系统性能的主要瓶颈。NUMA 正是为了解决这一扩展性问题而设计的。

2. 什么是 NUMA:非统一内存访问架构

NUMA(Non-Uniform Memory Access,非统一内存访问) 是一种将处理器和内存划分为多个 节点(Node) 的计算机内存架构。每个 NUMA 节点包含一组物理 CPU 核心、本地内存控制器以及直接连接的内存条(DIMM)。

在 NUMA 系统中,内存访问延迟取决于请求发起方与目标内存所在的节点关系:

  • 本地访问(Local Access):CPU 访问本节点内的内存,延迟最低(通常 60-100 ns)。
  • 远程访问(Remote Access):CPU 访问其他 NUMA 节点的内存,需要通过节点间的互联链路(如 Intel UPI、AMD Infinity Fabric),延迟显著增加(通常 120-200 ns,甚至更高)。
实际案例: 在双路 Intel Xeon 服务器上,本地内存访问延迟约为 80 ns,而跨 NUMA 节点的远程访问延迟约为 140 ns,增加了 75%。在 AMD EPYC 多芯片模块(MCM)架构中,跨 CCD(Core Complex Die)的远程访问延迟差异可能达到 2-3 倍。

3. UMA 与 NUMA 的核心区别对比

对比维度 UMA(统一内存访问) NUMA(非统一内存访问)
内存控制器位置 集中式,位于北桥或芯片组 分布式,集成在每个 CPU 内部
内存访问延迟 所有核心访问延迟一致 本地访问快,远程访问慢
内存带宽 所有核心共享总带宽 每个节点拥有独立带宽
扩展性 较差,8-16 核后瓶颈明显 优秀,可扩展到数百核心
缓存一致性 通过总线监听实现 通过目录协议(Directory-based)实现
典型应用 嵌入式、低端桌面、旧式服务器 现代服务器、数据中心、HPC

4. NUMA 节点与内存访问延迟的量化分析

NUMA 节点之间的内存访问延迟差异可以用 距离(Distance) 或 跳数(Hop Count) 来描述。Linux 内核通过 SLIT(System Locality Information Table) 记录节点间的相对延迟比例。

以下是一个典型的 4 节点 NUMA 系统的访问延迟矩阵(以本地访问延迟为基准 1.0):

请求节点 目标 Node 0 目标 Node 1 目标 Node 2 目标 Node 3
Node 0 1.0(本地) 1.5 2.0 2.5
Node 1 1.5 1.0(本地) 2.5 2.0
Node 2 2.0 2.5 1.0(本地) 1.5
Node 3 2.5 2.0 1.5 1.0(本地)
性能陷阱: 如果调度器将进程分配到 Node 0,但进程使用的内存分配在 Node 3,则每次内存访问的延迟是本地访问的 2.5 倍。对于内存密集型应用(如数据库、大数据处理),这种跨节点访问可能导致性能下降 30%-50%。这正是调度域拓扑配置和 NUMA 感知调度需要解决的核心问题。

5. NUMA 架构拓扑结构图

下图展示了一个典型的 4 节点 NUMA 系统架构,包含处理器核心、本地内存、缓存层次以及节点间的互联链路:

4 节点 NUMA 系统架构拓扑 NUMA Node 0 CPU Core 0-3 L1/L2/L3 Cache 本地内存 DDR4 64GB 内存控制器 NUMA Node 1 CPU Core 4-7 L1/L2/L3 Cache 本地内存 DDR4 64GB 内存控制器 NUMA Node 2 CPU Core 8-11 L1/L2/L3 Cache 本地内存 DDR4 64GB 内存控制器 NUMA Node 3 CPU Core 12-15 L1/L2/L3 Cache 本地内存 DDR4 64GB 内存控制器 UPI UPI UPI 远程访问路径(Node 0 → Node 2) 延迟:本地 1.0x → 远程 2.0x NUMA 内存访问延迟差异 • 本地访问(Local):CPU 访问本节点内存,延迟 60-100 ns • 远程访问(Remote):CPU 访问其他节点内存,延迟 120-200+ ns • 跨节点跳数越多,延迟越高(每跳增加 30%-50%) • 调度域拓扑的目标:尽量让进程在本地节点完成内存访问

6. 查看 NUMA 拓扑的常用命令

在 Linux 系统中,可以通过以下命令查看当前系统的 NUMA 拓扑结构和节点信息:

# 查看 NUMA 节点数量和每个节点的 CPU 列表
numactl --hardware

# 查看每个 NUMA 节点的内存大小和状态
numastat -m

# 查看进程的内存分配和 NUMA 节点分布
numastat -p <PID>

# 查看系统 SLIT 表(节点间相对延迟)
cat /sys/devices/system/node/node*/distance
实践建议: 在开始调度域拓扑配置之前,务必先使用 numactl --hardware 了解系统的 NUMA 节点数量、每个节点的 CPU 核心范围以及内存大小。这是后续所有调优工作的基础数据。

7. NUMA 对 Linux 调度器的挑战

NUMA 架构给 Linux 内核调度器带来了三个核心挑战:

  1. CPU 亲和性(CPU Affinity):调度器需要优先将进程调度到与已分配内存所在节点相同的 CPU 上,避免跨节点访问。
  2. 内存分配策略(Memory Allocation Policy):缺页异常处理时,内存分配器(如 Buddy Allocator)需要感知 NUMA 节点,优先从本地节点分配物理页面。
  3. 负载均衡(Load Balancing):当某个 NUMA 节点的 CPU 负载过高而其他节点空闲时,调度器需要迁移进程,但迁移时必须考虑内存访问代价。