Linux进程与模块的NUMA节点选择机制及Ubuntu 22.04节点0内存占用过高问题咨询
Linux进程与模块的NUMA节点选择机制及Ubuntu 22.04节点0内存占用过高问题咨询
嗨,这个问题挺常见的,我来给你拆解一下为什么默认情况下系统服务、二进制文件和关联库会扎堆在node0上,哪怕你没手动配置任何NUMA策略~
核心原因其实和系统启动流程、默认NUMA策略的继承性有关,具体可以分成这几点来看:
- 内核与初始进程的启动节点绑定:系统启动时,BIOS/UEFI通常会把内核镜像加载到node0的内存区域中,后续启动的第一个用户态进程(Ubuntu 22.04里是
systemd)会直接继承内核的NUMA亲和性——也就是默认运行在node0上。而所有系统服务都是systemd的子进程,自然也会继承这个节点偏好,优先在node0分配内存。 - 系统二进制与库的缓存逻辑:
/bin、/lib、/usr这些目录下的系统二进制和库文件,在系统启动后会被内核缓存到内存中(也就是页缓存)。由于内核本身运行在node0,为了获取最快的访问速度,页缓存会优先分配到node0的内存里,这就进一步拉高了node0的内存占用。 - 默认NUMA内存分配策略:Linux默认的内存分配策略是
localalloc,简单说就是进程会优先从自己当前运行的NUMA节点申请内存。既然大部分系统服务都在node0运行,它们的内存自然也会优先落在node0上,形成“越用越多”的局面。 - 无显式配置时的亲和性继承:如果没有通过
numactl、taskset或者systemd的NUMA配置项修改进程的节点偏好,所有进程都会继承父进程的NUMA亲和性。而整个系统的进程树最终都追溯到初始的systemd,所以几乎所有系统级进程都会默认绑定node0。
你可以用这些命令验证一下当前的状态:
- 查看各NUMA节点的内存使用情况:
numastat - 查看某个进程的NUMA节点绑定:
ps -eo pid,cmd,numa_node | grep <进程名> - 查看系统默认的NUMA策略:
numactl --show - 查看进程的CPU亲和性(间接对应NUMA节点):
taskset -c <进程PID>
如果想平衡各节点的负载,你可以试试这些方法:
- 对特定服务,用
numactl指定启动时的NUMA节点,比如:numactl --cpunodebind=1 --membind=1 systemctl start <服务名> - 在systemd服务配置文件中添加
NUMAPolicy=spread或者指定CPUAffinity,让服务分散到不同节点运行 - 开启内核的NUMA自动平衡(默认可能已开启):
echo 1 > /proc/sys/kernel/numa_balancing,不过这个对已经启动的进程效果有限,主要影响新启动的进程
备注:内容来源于stack exchange,提问作者Rama




