numactl —— 查看 NUMA 拓扑 & 把进程/内存绑到指定节点
这个工具是做什么的
numactl 是 NUMA 调优的主力:既能一览机器的 NUMA 拓扑,又能在启动进程时指定它跑在哪些核、内存分配到哪个节点,从而消除远程内存访问。属 numactl 包(yum install numactl / apt install numactl)。原理见 numa。
可以回答什么问题
| 问题 | 怎么用 |
|---|---|
| 这台机器是 NUMA 架构吗?几个节点? | numactl --hardware:available: 2 nodes = 是 NUMA |
| 每个节点有哪些 CPU 核?内存多大? | numactl -H 看 node N cpus 和 size |
| 远程内存访问比本地慢多少? | numactl -H 的 distances 矩阵(如 21 vs 10 = 约 2 倍) |
| 怎么把进程钉在某个 NUMA 节点? | numactl --cpunodebind=0 --membind=0 ./app |
| 怎么只绑 CPU 不绑内存? | numactl --preferred=0(软偏好) vs --membind=0(硬绑定) |
| 已运行的进程当前是什么 NUMA 策略? | numactl --show -p <PID> |
数据来源
- 查询拓扑:读内核
/sys/devices/system/node/(节点数、每节点 CPU 列表cpulist、内存meminfo、节点间距离distance)。 - 施加绑定:通过
set_mempolicy(2)/sched_setaffinity(2)等系统调用给进程设置 NUMA 内存策略和 CPU 亲和性,再exec目标程序。 - 由此决定的特性:绑定是在进程启动时施加并被子进程继承;
--hardware是纯查询、不改任何东西。
一、查看拓扑
numactl --hardware # 或 -H:节点数、每节点的核与内存、节点间距离矩阵
numactl --show # 或 -s:显示当前进程生效的 NUMA 策略(绑在哪、用什么策略)numactl -H 输出(双路机示例):
available: 2 nodes (0-1)
node 0 cpus: 0 1 2 3 4 5 6 7 8 9
node 0 size: 32143 MB
node 0 free: 10547 MB
node 1 cpus: 10 11 12 13 14 15 16 17 18 19
node 1 size: 32254 MB
node 1 free: 28741 MB
node distances:
node 0 1
0: 10 21
1: 21 10看点:几个 node、每个 node 有哪些核编号(绑定时要用)、每个 node 的 size/free(内存是否均衡)、distances 矩阵(远程访问相对代价,本地=10)。available: 1 nodes 就是非 NUMA 机器,不用往下看了。
二、绑定进程(核心用法)
启动程序时把它约束到指定节点:
# CPU 和内存都绑到 node 0(最常用:彻底本地化,无远程访问)
numactl --cpunodebind=0 --membind=0 ./myapp
# 简写:-N=cpunodebind,-m=membind
numactl -N 0 -m 0 ./myapp
# 内存就近分配到"运行所在的那个节点"(不硬绑到固定 node,跟着 CPU 走)
numactl --localalloc ./myapp # 或 -l
# 只绑内存到 node1,CPU 不限
numactl --membind=1 ./myapp
# 绑到具体几个物理 CPU 核(而非整个 node)
numactl --physcpubind=0-9 ./myapp # 或 -C 0-9
# 内存优先用 node0,不够再溢出到别处(软偏好,不像 membind 那样硬失败)
numactl --preferred=0 ./myapp几种内存策略的区别
| 选项 | 语义 | 内存不够时 |
|---|---|---|
--membind=N / -m | 强制只用节点 N 的内存 | 分配失败/触发回收,不会用别的节点 |
--preferred=N | 优先用节点 N,可溢出 | 溢出到其他节点(远程,但不失败) |
--localalloc / -l | 就近分配到运行所在节点 | 跟着线程跑的节点走 |
--interleave=all / -i | 在多个节点轮流分配 | 均摊带宽,适合大内存、访问无局部性的负载(如大型内存数据库) |
典型选择:延迟敏感、有明显数据局部性 →
--cpunodebind + --membind(绑死一个节点);吞吐型、访问遍布全内存(如某些 in-memory DB、HPC)→--interleave=all(把带宽摊到所有节点,避免单节点内存控制器成瓶颈)。
三、验证绑定生效
numactl --cpunodebind=0 --membind=0 ./myapp &
numactl --show -p $(pgrep myapp) # 看它实际的策略
numastat -p $(pgrep myapp) # 看内存是否真落在 node0(见 numastat.md)
cat /proc/$(pgrep myapp)/numa_maps | head # 每段内存落在哪个 node
taskset -cp $(pgrep myapp) # 看 CPU 亲和性(绑到哪些核)四、关键指标速查
| 指标 | 缩写/英文 | 命令 | 正常值 | 异常信号 |
|---|---|---|---|---|
| NUMA 节点数 | Node Count | numactl -H available: | ≥ 2 才需要关心 | 1 节点 → 非 NUMA,无需优化 |
| 节点间距离 | Node Distance | numactl -H distances | 本地=10,远程≤21 | 远程 > 20 → 跨节点延迟是本地 2 倍+ |
| 每节点可用内存 | Node Free Memory | numactl -H free | 均衡 | 某节点接近 0 → 新分配必然走远程 |
| 进程当前策略 | Current Policy | numactl --show | default | membind=1 但 CPU 在 node0 → 跨节点 |
| 内存是否绑在运行节点 | NUMA Hit Ratio | numastat -p <PID> | 内存集中在运行节点 | 大量内存在其他节点 → 远程访问 |
五、常见排查方法与分析
5.1 确认是否需要 NUMA 优化
numactl -H → available: 1 nodes → 不需要,只有一个节点
→ 2 nodes 以上 → 先看当前是否有跨节点访问
→ numastat → other_node 是否持续增长
→ numastat -p <PID> → 进程内存是否跨节点5.2 延迟敏感应用 → 绑死一个节点
# 确认网卡/GPU/加速器在哪,绑到同节点
numactl -H → 确认拓扑
numactl --cpunodebind=0 --membind=0 ./my_latency_app
# 验证生效
numactl --show -p <PID> # 看策略
numastat -p <PID> # 看内存分布
taskset -cp <PID> # 看 CPU 亲和性5.3 吞吐型应用 → interleave 均摊带宽
# 大内存数据库/内存池,访问模式无局部性
numactl --interleave=all ./my_db
# 验证:各节点分配应均匀
numastat -p <PID>
# interleave_hit 在各节点都应非零5.4 验证绑定效果
# 绑前
numastat -p <PID> → Node0: 800MB, Node1: 400MB(有远程)
# 绑后(--cpunodebind=0 --membind=0)
numastat -p <PID> → Node0: 1200MB, Node1: 0MB(全部本地)六、交叉引用
taskset只管 CPU 亲和性(把进程钉在哪些核),不管内存。numactl同时管 CPU 节点 + 内存策略,是 NUMA 场景更完整的工具。- 只想绑核不碰内存策略用
taskset -c 0-9 ./app;要连内存一起本地化用numactl。
CPU 亲和性(绑核)本身——为什么绑、taskset/sched_setaffinity/pthread 三层接口、绑核 vs 绑节点、isolcpus/中断亲和性、以及绑错更慢的坑——详见 thread-affinity。
numactl --cpunodebind是"绑到某节点的那组核"(节点级),更细的"钉到单个核"用那篇的 taskset/pthread 接口。
五、结合本仓库
numactl -H # 确认是不是 NUMA 机器(几个 node)
numactl --cpunodebind=0 --membind=0 ./cpu_demo # 绑到 node0 跑
numactl --show # 看默认策略⚠️ 单节点机器(
available: 1 nodes)上绑定没有意义——只有一个节点,怎么绑都是本地。NUMA 优化只在多路服务器上才有价值。绑定也可能降低灵活性(调度器不能把线程迁到空闲的其他节点),需结合负载实测,别无脑绑。
总结
numactl 是 NUMA 调优主力:-H 读 /sys 拓扑(节点、核、距离矩阵),启动时用 cpunodebind+membind 把延迟敏感进程的 CPU 和内存钉在同一节点以消除远程访问,无局部性的吞吐型负载则用 interleave=all 均摊带宽;单节点机器绑定无意义,且绑定会牺牲调度灵活性,需实测后再用。