当前位置:首页>Linux>Linux NUMA node 的设置

Linux NUMA node 的设置

  • 2026-10-10 11:58:16
Linux NUMA node 的设置

做服务器测试和运维的同学,肯定都遇到过这种场景——机器配置看着挺豪华,16核32G 起步,但跑起来就是不够快。排查了半天,最后发现罪魁祸首是 NUMA 没配好。

今天这篇文章,是我之前做Linux Kernel 测试的时候使用的一些方法,我简单分享出来给大家参考。希望对你有所帮助。

一、先搞清楚:你的机器到底长啥样?

在动手调优之前,第一步是看清家底。下面这几个命令,建议每个运维同学都刻在肌肉记忆里:

命令
能干什么
什么时候用
lscpu
快速概览 CPU 信息,包括 NUMA 节点数和 CPU 分布
登录新机器第一件事
numactl -H
详细 NUMA 硬件信息:CPU 列表、内存大小、节点间访问距离矩阵
制定绑定策略前的必做诊断
lstopo
图形化输出硬件层级拓扑树状图
需要直观理解拓扑关系时
numastat
查看进程在各节点的内存分布
验证绑定策略是否生效

重点看 numactl -H 的输出:

available: 2 nodes (0-1) 
node 0 cpus: 0 1 2 3 4 5 6 7 
node 0 size: 32768 MB 
node 0 free: 16384 MB 
node 1 cpus: 8 9 10 11 12 13 14 15 
node 1 size: 32768 MB node 1 free: 20480 MB 
node distances: node    0   1 
                   0 :  10  21
                   1 :  21  10

🔑 关键解读:

  • 系统有 2 个 NUMA 节点,节点 0 管 CPU 0~7,节点 1 管 CPU 8~15
  • 每个节点各有 32GB 内存
  • 距离矩阵是最关键的
    :节点 0 访问自己 = 10(本地),访问节点 1 = 21(跨节点延迟翻倍+)

这就是为什么跨节点访问内存会拖慢性能——数据要"绕路",而且这个开销远比你想象的大。

二、实战:5 种方式把程序"钉"在正确的地方

NUMA 调优的核心思想就一句话:让程序和它的数据待在同一个节点里。

📌 方式 1:启动时绑定(最常用)— numactl

这是将单个进程绑定到特定 NUMA 节点最直接的方法。

参数
作用
--cpunodebind=N
限定进程只在节点 N 的 CPU 上运行
--membind=N
强制从节点 N 的内存分配(硬约束)
--physcpubind=CPU
直接绑定到物理 CPU 核心
--interleave=all
内存轮询分布到所有节点(适合大内存应用)

✅ 最佳实践:CPU 和内存绑到同一个节点,效果最好。

🔧 MySQL 绑定示例(CPU + 内存全绑定):

CPU 和内存都锁定在节点 1 # numactl --cpunodebind=1 --membind=1 \   /usr/local/mysql/bin/mysqld \ --defaults-file=/etc/my.cnf  
只绑定 CPU,内存使用本地分配策略 # numactl --cpunodebind=1 --localalloc \   /usr/local/mysql/bin/mysqld \ --defaults-file=/etc/my.cnf

📌 方式 2:运行中调整 — taskset

程序已经跑起来了?没问题,taskset 可以随时调整 CPU 亲和性:

绑定到单核 CPU 2 # taskset -pc 2 1234  
绑定到多个离散核心 0、2、4 # taskset -pc 0,2,4 1234  
绑定到一段连续核心 0~3 # taskset -pc 0-3 1234

💡 提示:taskset -pc 后面第一个参数是 CPU 列表,第二个参数是 PID。

📌 方式 3:批量管理 — cgroup (cpuset)

需要同时管控多个进程或容器?cgroup 的 cpuset 子系统是你的不二之选:

  • cpuset.cpus
     — 指定可用 CPU 核心
  • cpuset.mems
     — 指定可用 NUMA 内存节点

Kubernetes 用户应该对这个很熟悉——底层原理一模一样。

📌 方式 4:容器环境 — Docker 参数

Docker 原生支持 NUMA 绑定,一行命令搞定:

绑定到 CPU 核心 0 和 1 # docker run --cpuset-cpus="0,1" -d image_name  绑定到 NUMA 节点 0 的内存 # docker run --cpuset-mems="0" -d image_name

📌 方式 5:全局策略 — systemd 配置

不想每次手动绑定?可以在 systemd 层面设置全局 NUMA 策略:

# vim /etc/systemd/system.conf 
[Manager] 
NUMAPolicy=bind (或 interleave) 
NUMAMask=0,1  
# sudo systemctl daemon-reload sudo reboot

三、进阶:MySQL 的 NUMA 专项优化

MySQL 是 NUMA 调优的重灾区——数据库对内存访问延迟极度敏感。这里给两个经过验证的方案:

方案 A:内存交错模式(Interleave)

适合 MySQL 这种大内存、多线程的场景,让内存均匀分布在所有节点:

# 编辑 /usr/bin/mysqld_safe 
# 找到启动 mysqld 的那一行,在前面加上: numactl --interleave=all  
# 重启 MySQL 生效

方案 B:my.cnf 直接配置(推荐)

MySQL 5.6.27 / 5.7.9 以上版本原生支持:

# my.cnf 中添加 
[mysqld] innodb_numa_interleave = ON

✅ 不用改启动脚本,干净利落。

四、踩过坑才知道的注意事项

⚠️ 避免过度绑定

绑得太死,一旦目标 CPU 繁忙,进程无法迁移到空闲核心,反而会造成排队等待。适度绑定,留有余量。

🐳 容器场景要注意

容器内看到的 CPU 编号和宿主机可能不一致,--cpuset-mems 的节点 ID 要对应宿主机的实际拓扑,别想当然。

☁️ 云虚拟机要小心

云 VM 的 NUMA 拓扑和物理宿主机往往不一致,生产环境中直接 numa=off 反而可能是更稳妥的选择。

🔧 BIOS 别忘了关节能

做 NUMA 优化前,先去 BIOS 把 Node Interleaving 关掉,再把 C1E / C States 这些节能模式禁了。不然 CPU 频率忽高忽低,调了也白调。

五、怎么确认生效了?验证清单

验证项
命令
预期结果
进程内存分布
numastat -p <PID>
内存集中在目标节点
当前策略状态
numactl --show
显示已生效的策略
系统级影响评估
vmstat / perf
上下文切换减少、cache miss 降低

觉得有用?转发给你的运维或者服务器测试小伙伴吧 🚀

最新文章

随机文章