关键在于让CPU访问本NUMA节点内存,跨节点访问延迟高、带宽低;需用numactl --hardware确认拓扑,再以--cpubind与--membind同步绑定CPU和内存,网卡中断与应用也须对齐同一节点,并用numastat和perf验证本地访问占比≥85%。

关键在于让 CPU 访问离它最近的内存——也就是本 NUMA 节点上的内存。跨节点访问延迟高、带宽低,不加干预时系统默认行为很容易导致“CPU 在 node 0 运行,内存却分在 node 1”,性能直接打七折。
确认 NUMA 拓扑结构
先看清硬件布局,这是所有优化的前提:
- 运行 numactl --hardware 查看节点数量、每个节点挂载的 CPU 核心和内存容量
- 重点关注 node distances 表格:本地访问延迟是 10,远端是 20,就说明跨节点代价翻倍
- 用 lscpu | grep -i numa 辅助验证 CPU 分组情况
绑定 CPU 与内存到同一节点
不能只绑 CPU,必须同步指定内存分配策略:
- 启动进程时用 numactl --cpubind=0 --membind=0 ./app,强制线程在 node 0 执行,且只从 node 0 分配内存
- 避免只用
--cpubind不配--membind:线程被调度到 node 0,但 malloc 出来的内存可能还在 node 1,反而更慢 - 对多进程服务(如数据库多 worker),按节点轮询分配:
numactl --cpubind=0 --membind=0 proc1 & numactl --cpubind=1 --membind=1 proc2 &
关注网卡与内存的 NUMA 对齐
网络密集型应用常被忽略的一环:
- 查看网卡所在 NUMA 节点:cat /sys/class/net/eth0/device/numa_node
- 将处理该网卡中断的 CPU 和应用线程绑定到同一节点(例如通过
irqbalance关闭 + 手动写/proc/irq/*/smp_affinity_list) - 确保 socket 接收缓冲区、零拷贝内存池等也分配在对应节点,避免 DMA 写入 node 0 内存后,node 1 的 CPU 去读取
监控与验证是否生效
调完不验证,等于没调:
- 用 numastat -p <PID> 检查
local_node占比是否 ≥ 85%,other_node是否 ≤ 5% -
numa_miss超过 10% 就要排查——可能是子进程未继承绑定,或 mmap/malloc 时用了非本地策略 - 配合 perf stat -e uncore_imc/data_reads/,uncore_imc/data_writes/ 看各节点内存控制器流量,确认数据真的走本地通道


















