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 系统架构,包含处理器核心、本地内存、缓存层次以及节点间的互联链路:
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 内核调度器带来了三个核心挑战:
- CPU 亲和性(CPU Affinity):调度器需要优先将进程调度到与已分配内存所在节点相同的 CPU 上,避免跨节点访问。
- 内存分配策略(Memory Allocation Policy):缺页异常处理时,内存分配器(如 Buddy Allocator)需要感知 NUMA 节点,优先从本地节点分配物理页面。
- 负载均衡(Load Balancing):当某个 NUMA 节点的 CPU 负载过高而其他节点空闲时,调度器需要迁移进程,但迁移时必须考虑内存访问代价。