Linux NUMA
NUMA(Non-Uniform Memory Access)
NUMA = 每个 CPU 有“自己更近的内存”,访问别的 CPU 内存会更慢
和它对立的是 UMA(Uniform Memory Access)。
CPU0 ─┐
CPU1 ─┼── Memory
CPU2 ─┤
CPU3 ─┘
- 所有 CPU 共享同一内存控制器
- CPU 越多 -> 内存争用越严重
- 总线成为瓶颈
NUMA Node 0 NUMA Node 1
+-----------+ +-----------+
| CPU0 CPU1 | | CPU2 CPU3 |
| Memory 0 | <──QPI──> | Memory 1 |
+-----------+ +-----------+
- 内存控制器集成到 CPU
- 每个 CPU(Socket)直接连一部分内存
- CPU 访问:
- 本地内存 -> 快
- 远程内存 -> 慢
大致数量级(因硬件不同而异):
| 访问类型 | 延迟 |
|---|---|
| 本地内存 | ~70 ns |
| 远程内存 | ~120–150 ns |
| L3 Cache | ~10–15 ns |
| 内存 miss + 跨 NUMA | 性能断崖式下降 |
👉 数据库、缓存、中断密集型应用非常敏感
- 一个 NUMA Node = 一组 CPU + 本地内存
- 通常:
- 1 个 CPU Socket = 1 个 NUMA Node
- 有些服务器:1 Socket = 2 NUMA Node(子 NUMA)
| 类型 | 含义 |
|---|---|
| Local | CPU 访问自己 Node 的内存 |
| Remote | CPU 访问其它 Node 的内存 |
numactl --hardware
示例:
node distances:
node 0 1
0 10 20
1 20 10
- 数值越小 -> 越快
- 本地通常是 10
lscpu
NUMA node(s): 2
NUMA node0 CPU(s): 0-15
NUMA node1 CPU(s): 16-31
numactl --hardware
node 0 size: 128 GB
node 1 size: 128 GB
numastat -p <pid>
原因:
- 进程启动在 CPU0
- 内存由其它 CPU 触发分配(first-touch 原则)
结果:
CPU 跨 NUMA 访问内存 -> 延迟翻倍
常见于:
- 网卡
- NVMe
- 高速存储
导致:
- 一个 CPU/socket 被打爆
- 另一个很闲
- KVM / Docker 默认不绑 NUMA
- 大内存 VM 性能极不稳定
内存分配在哪个 NUMA Node,取决于“第一次写它的 CPU”
malloc()
memset() ← 决定内存属于哪个 NUMA Node
cat /proc/sys/kernel/numa_balancing
- 1:开启(默认)
- 0:关闭
作用:
- 尝试把内存迁移到更靠近 CPU 的 Node
⚠️ 数据库场景有时反而更慢
# 绑定 CPU 和内存
numactl --cpunodebind=0 --membind=0 myapp
taskset -c 0-15 myapp
⚠️ 不推荐单独使用
CPUAffinity=0-15
NUMAPolicy=local
- 大内存实例 必须 NUMA 感知
- 常见策略:
- 单 NUMA Node 运行
- 或 NUMA interleave
numactl --interleave=all mysqld
-XX:+UseNUMA
- 正确方式:vCPU ↔ NUMA Node 对齐
- 内存 pre-allocate
- 默认:不感知 NUMA
- 高性能场景:
- CPU Manager static
- HugePages + 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 绑定
- 内存分配策略
一起考虑
Linux 系统
- 使用终端命令 lscpu, 查看 Socket(s) 一项,数值为 2 则表示双路CPU。
- 或者运行
cat /proc/cpuinfo | grep "physical id" | sort -u | wc -l来计算物理CPU个数。
硬件查看
- 直接打开服务器机箱,观察主板上是否有两个并排的CPU风扇/散热片。
注意:不要将 “双路CPU(2个物理芯片)” 与 “双核CPU(1个芯片内有两个核心)” 混淆。双路系统多用于服务器或工作站。