在Linux服务器运维、高性能程序开发、分布式服务部署中,NUMA绝对是绕不开的核心知识点。很多人对它一知半解,要么遇到性能瓶颈无从下手,要么盲目调优踩坑,甚至不知道编程里还能和NUMA打交道。
这篇文章就从原理讲解、状态查询、配置修改、命令行指定、编程适配五个维度,把Linux NUMA彻底讲清楚,不管是运维还是开发,看完都能直接上手用。
一、先搞懂:NUMA到底是什么?原理一文讲透
1. 为什么会有NUMA?
早期服务器采用UMA(均匀内存访问)架构,所有CPU核心共享一条总线,访问任意内存地址的速度都一样。但随着CPU核心数越来越多,共享总线会变成严重瓶颈,大量核心同时访问内存时,总线拥堵,延迟急剧升高,多核性能完全发挥不出来。
为了解决这个问题,NUMA(Non-Uniform Memory Access,非均匀内存访问)架构应运而生,成为现代x86、ARM服务器的标配。
2. NUMA核心原理
NUMA的核心设计是分节点管理:
- 把服务器的CPU、内存划分为多个NUMA Node(节点),每个Node包含专属的CPU核心、本地内存,Node之间通过高速互联总线(Intel QPI、AMD Infinity Fabric)连接。
- 本地内存访问:CPU访问自己所属Node的内存,速度最快、延迟最低、带宽最大。
- 远端内存访问:CPU访问其他Node的内存,需要经过互联总线,延迟大幅增加,性能下降30%-100%。
简单来说:NUMA让CPU优先就近取内存,减少跨节点访问,最大化多核性能,Linux内核从2.5版本就开始全面支持NUMA,内存管理、CPU调度都围绕它设计。
3. 关键术语梳理
- NUMA Node:最小管理单元,CPU+本地内存的组合。
- Core/Thread:Node内部的CPU核心、超线程。
- Local Distance:节点间访问距离,数值越小,访问速度越快。
- Affinity(亲和性):将进程/内存绑定到指定Node,避免跨节点访问。
二、Linux下NUMA状态查询:快速摸清服务器拓扑
想要操作NUMA,第一步先学会查询服务器的NUMA配置,Linux提供了专用工具,安装后即可使用。
1. 安装NUMA相关工具
# CentOS/RHEL/Oracle Linux
yum install numactl hwloc numastat -y
# Ubuntu/Debian
apt update && apt install numactl hwloc numastat -y
2. 核心查询命令
(1)查看完整NUMA硬件信息
numactl --hardware
# 简写
numactl -H
执行后会显示:NUMA节点数量、每个Node的CPU核心列表、内存总量/可用量、节点间访问距离,一眼就能看清服务器NUMA架构。
(2)可视化NUMA拓扑结构
lstopo
# 文本模式输出,更适合终端查看
lstopo-no-graphics
直观展示CPU、NUMA Node、内存、PCI设备的层级关系,新手也能快速理解硬件布局。
(3)查看NUMA运行状态统计
numastat
# 实时刷新监控
numastat -c 1
重点关注 numa_hit (本地内存分配成功次数)、 numa_miss (本地内存不足,分配远端内存次数)、 numa_foreign (进程被调度到其他Node次数),这三个指标是判断NUMA性能问题的关键。
(4)查看系统NUMA开启状态
dmesg | grep -i numa
如果输出显示 NUMA: Enabled ,说明NUMA已开启;若显示 Disabled ,则是关闭状态。
三、NUMA改配:全局配置与内核参数调整
1. 临时修改NUMA策略(重启失效)
通过 sysctl 临时调整内核参数,适合测试调优:
# 允许内存跨节点分配(默认0开启,1为强制本地回收)
sysctl vm.zone_reclaim_mode=0
# 查看当前参数
sysctl vm.zone_reclaim_mode
2. 永久修改NUMA配置(重启生效)
编辑内核参数配置文件:
# 编辑sysctl配置
echo "vm.zone_reclaim_mode=0" >> /etc/sysctl.conf
# 生效配置
sysctl -p
3. BIOS级关闭/开启NUMA(慎用)
如果特殊场景需要关闭NUMA,需在服务器BIOS中设置(不推荐,会损失多核性能):
- 重启服务器,进入BIOS设置,找到 NUMA Node 选项,选择 Disable 关闭/ Enable 开启。
- 关闭后系统识别为UMA架构,所有CPU共享内存,性能会大幅下降,仅特殊兼容场景使用。
4. numad服务:自动NUMA优化
Linux自带 numad 自动调优服务,可根据负载自动绑定进程到NUMA Node,减少跨节点访问:
# 启动numad服务
systemctl start numad
# 设置开机自启
systemctl enable numad
# 查看状态
systemctl status numad
四、命令行指定NUMA:进程/程序绑定Node实战
日常运维中,最常用的就是通过 numactl 命令,手动指定进程运行的CPU Node和内存Node,强制本地访问,提升性能。
1. numactl核心参数
- --cpunodebind=NODE :绑定进程到指定NUMA Node的CPU核心
- --membind=NODE :仅使用指定Node的本地内存,不足则报错
- --preferred=NODE :优先使用指定Node内存,不足则使用远端内存
- --localalloc :强制使用本地Node内存
- --show :查看当前进程的NUMA绑定状态
2. 常用实战命令
(1)绑定进程到NUMA Node 0,仅使用Node 0内存
numactl --cpunodebind=0 --membind=0 ./test_app
适合MySQL、Redis、NCCL这类对内存延迟敏感的服务。
(2)优先使用Node 1内存,允许跨节点
numactl --cpunodebind=1 --preferred=1 ./backend_service
适合内存占用大,单Node内存不足的场景。
(3)查看指定进程的NUMA绑定
# 先查进程PID
ps -ef | grep test_app
# 查看NUMA状态
numactl --show -p 进程PID
(4)运行shell命令绑定NUMA
numactl -N 0 -m 0 ls /home
直接给临时命令绑定NUMA Node,简单高效。
五、编程开发:如何获取和使用NUMA信息?
很多开发者会疑惑:写代码的时候,需要处理NUMA吗?
答案是:高性能程序、底层服务、并行计算程序,必须适配NUMA,普通业务代码可借助系统自动调度,但掌握NUMA编程能大幅提升程序性能。
1. 编程获取NUMA信息的方式
(1)C语言编程(Linux原生)
Linux提供 numaif.h 、 sched.h 头文件,可调用系统API获取NUMA信息、绑定CPU/内存:
- 获取当前进程所属NUMA Node:
get_mempolicy()
- 绑定进程到指定Node:
mbind() 、 sched_setaffinity()
- 查询系统NUMA节点数:
numa_num_configured_nodes()
示例代码片段:
#include<numaif.h><stdio.h>
int main() {
int node;
// 获取当前内存所在Node
if (get_mempolicy(&node, NULL, 0, NULL, 0) == 0) {
printf("当前进程所属NUMA Node: %d\n", node);
}
return 0;
}
编译时需链接numa库:
gcc test.c -o numa_test -lnuma
(2)Python编程
借助 psutil 、 numa 第三方库,可快速获取NUMA信息:
import psutil
# 获取NUMA节点总数
print(f"NUMA节点数:
{psutil.NUMA_NUM_NODES}")
# 获取每个节点的CPU核心
print(f"Node 0核心:
{psutil.NUMA_NODE_CPUS[0]}")
(3)Java编程
通过 OperatingSystemMXBean 获取系统NUMA相关信息,或调用JNI调用C语言NUMA API,适合大数据、分布式Java服务。
2. 编程适配NUMA的核心原则
- 多核并行程序,将线程绑定到同一NUMA Node,减少线程间跨节点数据同步。
- 内存密集型程序,优先申请本地Node内存,避免大量跨节点访问。
- 数据库、缓存类程序,固定进程到单个NUMA Node,提升缓存命中率。
六、NUMA常见避坑指南
1. 别盲目关闭NUMA:关闭后多核服务器性能损失极大,除非软件兼容性要求,否则务必开启。
2. 避免进程跨节点漂移:不设置亲和性时,进程会在不同Node间调度,导致缓存失效、延迟升高。
3. 关注numa_miss指标:该指标过高,说明本地内存不足,需调整内存分配或进程绑定。
4. 容器化场景别忽略:Docker/K8s部署服务时,需配置NUMA亲和性,否则容器内进程NUMA失控。
七、总结
NUMA是Linux高性能架构的核心,不懂NUMA,就做不好Linux性能调优,也写不出极致的高性能程序。
关注我,一起深入了解嵌入式linux系统