Skip to main content
☘️ Septvean's Documents
Toggle Dark/Light/Auto mode Toggle Dark/Light/Auto mode Toggle Dark/Light/Auto mode Back to homepage

Linux NUMA

NUMA(Non-Uniform Memory Access)

一、NUMA 是什么(一句话先立住)

NUMA = 每个 CPU 有“自己更近的内存”,访问别的 CPU 内存会更慢

和它对立的是 UMA(Uniform Memory Access)

二、为什么会有 NUMA?

1️⃣ UMA 的问题(老架构)

CPU0 ─┐
CPU1 ─┼── Memory
CPU2 ─┤
CPU3 ─┘
  • 所有 CPU 共享同一内存控制器
  • CPU 越多 -> 内存争用越严重
  • 总线成为瓶颈

2️⃣ NUMA 的诞生(现代服务器)

NUMA Node 0              NUMA Node 1
+-----------+           +-----------+
| CPU0 CPU1 |           | CPU2 CPU3 |
| Memory 0  | <──QPI──> | Memory 1  |
+-----------+           +-----------+
  • 内存控制器集成到 CPU
  • 每个 CPU(Socket)直接连一部分内存
  • CPU 访问:
    • 本地内存 -> 快
    • 远程内存 -> 慢

三、NUMA 中“慢”到底慢多少?

大致数量级(因硬件不同而异):

访问类型 延迟
本地内存 ~70 ns
远程内存 ~120–150 ns
L3 Cache ~10–15 ns
内存 miss + 跨 NUMA 性能断崖式下降

👉 数据库、缓存、中断密集型应用非常敏感

四、NUMA 的核心概念

1️⃣ NUMA Node

  • 一个 NUMA Node = 一组 CPU + 本地内存
  • 通常:
    • 1 个 CPU Socket = 1 个 NUMA Node
    • 有些服务器:1 Socket = 2 NUMA Node(子 NUMA)

2️⃣ Local / Remote Memory

类型 含义
Local CPU 访问自己 Node 的内存
Remote CPU 访问其它 Node 的内存

3️⃣ NUMA Distance

numactl --hardware

示例:

node distances:
node   0   1
  0   10  20
  1   20  10
  • 数值越小 -> 越快
  • 本地通常是 10

五、Linux 如何“感知” NUMA?

查看 NUMA 拓扑

lscpu
NUMA node(s):        2
NUMA node0 CPU(s):   0-15
NUMA node1 CPU(s):   16-31

查看 NUMA 内存分布

numactl --hardware
node 0 size: 128 GB
node 1 size: 128 GB

进程的 NUMA 使用情况

numastat -p <pid>

六、NUMA 带来的“隐性性能坑”

1️⃣ CPU 在 Node0,内存分配在 Node1

原因:

  • 进程启动在 CPU0
  • 内存由其它 CPU 触发分配(first-touch 原则)

结果:

CPU 跨 NUMA 访问内存 -> 延迟翻倍

2️⃣ 中断只落在一个 NUMA 节点

常见于:

  • 网卡
  • NVMe
  • 高速存储

导致:

  • 一个 CPU/socket 被打爆
  • 另一个很闲

3️⃣ 虚拟化 / 容器默认“忽略 NUMA”

  • KVM / Docker 默认不绑 NUMA
  • 大内存 VM 性能极不稳定

七、Linux 中的 NUMA 核心机制

1️⃣ First-Touch Policy(非常关键)

内存分配在哪个 NUMA Node,取决于“第一次写它的 CPU”

malloc()
memset()   决定内存属于哪个 NUMA Node

2️⃣ NUMA 自动均衡(Automatic NUMA Balancing)

cat /proc/sys/kernel/numa_balancing
  • 1:开启(默认)
  • 0:关闭

作用:

  • 尝试把内存迁移到更靠近 CPU 的 Node

⚠️ 数据库场景有时反而更慢

八、NUMA 控制工具(必会)

numactl

# 绑定 CPU 和内存
numactl --cpunodebind=0 --membind=0 myapp

taskset(只绑 CPU,不绑内存)

taskset -c 0-15 myapp

⚠️ 不推荐单独使用

cgroups / systemd

CPUAffinity=0-15
NUMAPolicy=local

九、NUMA 与常见组件的关系

🔹 数据库(MySQL / PostgreSQL)

  • 大内存实例 必须 NUMA 感知
  • 常见策略:
    • 单 NUMA Node 运行
    • 或 NUMA interleave
numactl --interleave=all mysqld

🔹 JVM

-XX:+UseNUMA

🔹 KVM 虚拟机

  • 正确方式:vCPU ↔ NUMA Node 对齐
  • 内存 pre-allocate

🔹 Docker / Kubernetes

  • 默认:不感知 NUMA
  • 高性能场景:
    • CPU Manager static
    • HugePages + NUMA

十、什么时候“要关 NUMA”?

❌ 误区:一上来就关 NUMA

numactl --interleave=all
# 或 BIOS 里关 NUMA

合理的情况

场景 建议
小内存 / 单进程 interleave
NUMA 感知差的软件 interleave
性能调优完成 精细绑定

十一、运维实战检查清单

lscpu
numactl --hardware
numastat
numastat -p <pid>

重点看:

  • 是否跨 NUMA 分配
  • 是否某 Node 内存被打满

十二、总结

NUMA 是“CPU 和内存的距离问题”,忽视 NUMA = 白白浪费 30%~50% 性能。

十三、建议

前提:

  • 双路服务器
  • 中断亲和性
  • 数据库 / 容器 / 高并发

👉 NUMA 一定要和:

  • IRQ 亲和性
  • CPU 绑定
  • 内存分配策略

一起考虑

查看是否为双路CPU(物理双CPU)

Linux 系统

  • 使用终端命令 lscpu, 查看 Socket(s) 一项,数值为 2 则表示双路CPU。
  • 或者运行 cat /proc/cpuinfo | grep "physical id" | sort -u | wc -l 来计算物理CPU个数。

硬件查看

  • 直接打开服务器机箱,观察主板上是否有两个并排的CPU风扇/散热片。

注意:不要将 “双路CPU(2个物理芯片)” 与 “双核CPU(1个芯片内有两个核心)” 混淆。双路系统多用于服务器或工作站。