性能调优之NUMA调优

news/2025/9/20 21:07:03/文章来源:https://www.cnblogs.com/HByang/p/19102783

什么是NUMA

NUMA(Non-Uniform Memory Access,非统一内存访问)是一种用于多处理器系统的内存设计架构。在NUMA系统中,每个处理器(或一组处理器)拥有自己的本地内存,处理器访问本地内存的速度比访问其他处理器的内存(远端内存)要快。

image

那你可能会有一个疑问,服务器会在什么时候出现跨NUMA的情况呢?

第一种场景:本地节点内存不足,或内存分配策略未绑定节点,导致CPU不得不访问其他节点的内存。

1、当某一节点的 CPU 进程占用内存超过其本地内存上限时,服务器会自动将超出部分的内存分配到其他 NUMA 节点的 “远程内存” 中,此时该 CPU 访问这部分内存就会触发跨 NUMA。

# 服务器有2个NUMA节点(节点0:CPU 0-7 + 128GB 本地内存;节点1:CPU 8-15 + 128GB 本地内存)。仅在节点0的CPU 0上运行一个需要150GB内存的数据库进程:节点0的128GB本地内存耗尽后,剩余22GB内存会被分配到节点1的本地内存中。此时CPU 0访问这22GB内存时,必须跨节点通过NUMA互联总线(如Intel UPI、AMD Infinity Fabric)访问节点1的内存,形成跨NUMA。

2、Linux/Unix系统默认的内存分配策略(如default策略)是 “优先分配本地内存,但本地不足时分配远程内存”;但如果未配置 “强绑定策略”(如membind),即使本地内存充足,也可能因内核调度逻辑导致内存被分配到其他节点。

# 运维未通过工具(如numactl、taskset)绑定进程的内存节点,仅绑定了CPU核心。例如:将进程绑定到节点0的CPU 0,但内存分配未限制为节点0,内核可能因 “内存碎片优化” 将部分内存分配到节点1,导致跨NUMA。
# 虚拟化场景中,虚拟机(VM)的内存未与物理NUMA节点对齐:若VM的vCPU绑定到节点0,但VM的内存被KVM分配到节点1的物理内存,vCPU访问内存时会跨NUMA。

3、当多个 NUMA 节点的 CPU 需要访问同一块共享内存(如进程间通信的shm、分布式缓存的共享段)时,若共享内存被分配到某一节点(如节点 0),则其他节点(如节点 1)的 CPU 访问该共享内存时,必然触发跨 NUMA。

# 节点0的CPU 0创建一块10GB的共享内存,用于与节点1的CPU 8通信;节点1的CPU 8读取 / 写入该共享内存时,需跨节点访问节点0的本地内存,形成跨 NUMA。

第二种场景:CPU访问非本地节点的PCIe设备

1、设备与 CPU 未绑定到同一 NUMA 节点

# 网卡场景:若网卡直连节点1的 PCIe 总线(归属节点1),但处理网卡流量的进程(如Nginx、DPDK 应用)被绑定到节点0的CPU,此时节点0的CPU需要跨节点访问节点1的网卡,导致数据传输延迟升高。
# SSD 场景:若 NVMe SSD归属节点0,但运行数据库的进程被绑定到节点1的CPU,CPU读取SSD数据时需跨NUMA,影响IO性能。

2. 多设备负载集中在单一节点,其他节点需跨节点调用

# 例如:服务器有2个NUMA节点,仅节点0连接了2块高速SSD,节点1无本地SSD。当节点1的CPU需要读取数据时,必须跨节点访问节点0的SSD,触发跨NUMA。

第三种场景:CPU核心与进程/线程的节点不匹配

1、进程未绑定 NUMA 节点,被调度到其他节点的 CPU

# 示例:某进程的内存分配在节点0,但其被调度器分配到节点1的CPU 8上运行。此时CPU 8访问该进程的内存(节点 0),就会触发跨 NUMA。
# 常见于默认调度策略(如Linux的CFS调度器):调度器优先考虑CPU负载均衡,而非NUMA节点亲和性,可能导致 “进程-内存-CPU” 跨节点。

2. 虚拟化环境中 vCPU 与物理 NUMA 节点错位

# 若虚拟机的vCPU配置未与物理NUMA节点 “对齐”(如vCPU跨越物理节点0和1),KVM等虚拟化层可能将vCPU调度到不同物理节点的CPU上,导致vCPU访问VM内存时跨物理NUMA节点。
# 例如:VM配置4个vCPU,被分配到物理节点0的 CPU 0-2和节点1的CPU 8,此时vCPU 3(对应物理CPU8)访问VM内存(若分配到节点0)时,会跨NUMA。

第四章场景:NUMA节点配置错误或硬件限制

1. BIOS / 固件配置错误,导致 NUMA 节点识别异常

# 若服务器BIOS中未启用 NUMA(或配置为 “UMA 模式”,即均匀内存访问),但实际硬件支持NUMA,可能导致系统误将不同节点的资源视为同一节点,或反之将同一节点拆分为多个,间接引发跨NUMA。# 例如:BIOS中 “NUMA Node Interleaving”(NUMA节点交错)被启用,会强制内存跨节点均匀分配,导致所有CPU访问内存时都可能跨NUMA(除非进程强绑定)。

2. 硬件资源不足,不得不跨节点使用

# 例如:服务器某一NUMA节点的CPU核心全部被占用(如节点0的8个CPU满负载),但仍有新进程需要运行,调度器只能将新进程分配到节点1的CPU,若新进程的内存/设备在节点0,则必然跨NUMA。

numactl工具

numactl工具可用于查看当前服务器的NUMA节点配置、状态,可通过该工具将进程 绑定到指定CPU core,由指定CPU core来运行对应进程。如果系统中没有这个命令可以通过yum -y install numactl numastat来进行安装

使用方法如下

numactl [ --interleave nodes ] [ --preferred node ] [ --membind nodes ] [ --cpunodebind nodes ] [ --physcpubind cpus ] [ --localalloc ] command {arguments ...}
# 常用参数
# --hardware 显示系统上可用节点的清单,包括节点之间的相对距离。
# -N --cpunodebind 确保指定的命令及其子进程仅在指定节点上执行。
# -l --localalloc 指定始终从本地节点分配内存。
# -i --interleave=0,1|all:设置内存交错策略,内存将在指定的节点之间循环分配。
# --preferred=node:设置首选节点,如果可能,内存将被分配到这个节点上。
# -m --membind=nodes:设置内存绑定策略,只从指定的节点分配内存。
# --cpunodebind=nodes:设置CPU节点绑定,只在指定节点的CPU上执行命令。
# -C --physcpubind=cpus:设置物理CPU绑定,只在指定的CPU上执行进程。

步骤一、通过查看当前服务器的NUMA配置。

1、检查NUMA节点的内存访问统计

[root@localhost ~]# numastat 
                           node0           node1           node2           node3
numa_hit                     414          552466             414           55540
numa_miss                      0               0               0               0
numa_foreign                   0               0               0               0
interleave_hit                 0            3005               0            2847
local_node                     0          224468               0           15870
other_node                   414          327998             414           39670# numa_hit:该节点成功分配本地内存访问的内存大小
# numa_miss:内存访问分配到另一个node的大小,该值和另一个node的numa_foreign相对应
# numa_foreign 其他节点分配失败,由本节点代为分配的次数
# interleave_hit 通过交错策略在本节点分配的次数
# local_node:该节点的进程成功在本节点上分配内存访问的大小
# other_node:该节点进程在其它节点上分配的内存访问的大小# 或者通过下面命令
[root@localhost ~]# cat /sys/devices/system/node/node*/numastat
numa_hit 210079
numa_miss 0
numa_foreign 0
interleave_hit 1412 
local_node 206615
other_node 3464 
...

2、确认硬件拓扑和NUMA架构

[root@localhost ~]# lscpu | grep -i numa
NUMA 节点:                         4
NUMA 节点0 CPU:                    0-23
NUMA 节点1 CPU:                    24-47
NUMA 节点2 CPU:                    48-71
NUMA 节点3 CPU:                    72-95

3、这告诉你系统有4个NUMA节点,以及每个节点包含了哪些CPU核心。

[root@localhost ~]# numactl -H
available: 4 nodes (0-3)
node 0 cpus: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
node 0 size: 130333 MB
node 0 free: 129064 MB
node 1 cpus: 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
node 1 size: 130928 MB
node 1 free: 130552 MB
node 2 cpus: 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71
node 2 size: 130898 MB
node 2 free: 130319 MB
node 3 cpus: 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95
node 3 size: 129903 MB
node 3 free: 128242 MB
node distances:
node   0   1   2   3 0:  10  12  20  22 1:  12  10  22  24 2:  20  22  10  12 3:  22  24  12  10 

关键信息:

  • node distances:节点间的访问代价。node0访问node0的内存代价是10,访问node1的内存代价是12(越高越慢)。这清晰地显示了跨节点访问的性能 penalty。

步骤二、通过numactl将进程绑定到指定CPU core。

1、通过 numactl -C 5-15 dd命令即是将进程“dd”绑定到5~15 CPU core上执行

[root@localhost ~]# numactl -C 5-15 --membind=0 dd if=/dev/zero of=/dev/shm/A bs=1M count=1024
记录了1024+0 的读入
记录了1024+0 的写出
1073741824字节(1.1 GB,1.0 GiB)已复制,0.227962 s,4.7 GB/s
[root@localhost ~]# numactl -C 5-15 --membind=1 dd if=/dev/zero of=/dev/shm/A bs=1M count=1024
记录了1024+0 的读入
记录了1024+0 的写出
1073741824字节(1.1 GB,1.0 GiB)已复制,0.227861 s,4.7 GB/s
[root@localhost ~]# numactl -C 5-15 --membind=2 dd if=/dev/zero of=/dev/shm/A bs=1M count=1024
记录了1024+0 的读入
记录了1024+0 的写出
1073741824字节(1.1 GB,1.0 GiB)已复制,0.332766 s,3.2 GB/s
[root@localhost ~]# numactl -C 5-15 --membind=3 dd if=/dev/zero of=/dev/shm/A bs=1M count=1024
记录了1024+0 的读入
记录了1024+0 的写出
1073741824字节(1.1 GB,1.0 GiB)已复制,0.348661 s,3.1 GB/s

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/908541.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

深入解析:SpringMVC静态资源与Servlet容器指南

深入解析:SpringMVC静态资源与Servlet容器指南pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", &…

CCPC Online 2025 游寄

CCPC Online 2025 游寄 赛时 随机 roll 题,先 roll 到 \(K\) 然后没看懂,又 roll 到 \(E\) 谁家好人上来就把两道签到题就 roll 完了() 和队友讨论了一下 \(E\),发现很简单,队友推了个式子过了 回头一看,发现自…

CentOS 7 容器时遇到了 yum update 报错

CentOS 7 容器时遇到了 yum update 报错你在 CentOS 容器中执行 yum update -y 时遇到的错误, ` Loaded plugins: fastestmirror, ovl Determining fastest mirrors Could not retrieve mirrorlist http://mirrorlist…

MIT新论文:数据即上限,扩散模型的关键能力来自图像统计规律,而非复杂架构

现在的文生图模型已经十分强大了,例如我们在输入框敲下 “a photorealistic astronaut riding a horse on the moon”,几秒钟后屏幕生成从未出现过的图像,细节丰富,几近完美。扩散模型(diffusion models)推动了这…

实用指南:光学神经网络与人工智能应用

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

Zabbix 企业级监控架构实战指南:从搭建、可视化到智能告警

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

基于MATLAB的视频动态目标跟踪检测搭建方案

基于MATLAB的视频动态目标跟踪检测搭建方案pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "…

第三篇:Windows10/11软件集成与系统优化 - 教程

第三篇:Windows10/11软件集成与系统优化 - 教程2025-09-20 20:21 tlnshuju 阅读(0) 评论(0) 收藏 举报pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display…

U522155 数据生成(小心电脑)

// code by 樓影沫瞬_Hz17 #include <bits/stdc++.h> using namespace std;#define getc() getchar_unlocked() #define putc(a) putchar_unlocked(a) #define en_ putc(\n) #define e_ putc( )using pii = pair…

Windows-Appx

Windows-Appx导航 (返回顶部)1. PS_modules 2. Appx 3. Get-AppxPackage3.1 Syntax 语法 3.2 Description 描述 3.3 Examples 3.4 Parameters 参数4. Remove-AppxPackage4.1 Syntax 4.2 Description 4.3 Parameters5. …

实用指南:OSG中osgFX库

实用指南:OSG中osgFX库pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", &qu…

2025.9.20——1橙

终于结束初赛,可以好好写写编程题了。 普及- P10108 [GESP202312 六级] 闯关游戏 很简单的一道dp题,但我因为没考虑到答案可能是负数,卡了好几次。

CSP 2025 游记

前言 被迫报了 J 组,不好评价。 初赛 J 组 上午坐大巴在车上睡着了,然后正好在考点门口被颠醒了…… 提前半个小时到了考点,又在桌子上趴了一会,不过没睡着。两个监考老师左右脑互搏,至今不知道准考证号前四位要填…

配置Spring框架以连接SQL Server数据库

Spring框架是一个开源的企业级应用框架,用于简化Java开发工作,通过依赖注入(DI)和面向切面编程(AOP)等核心功能支持程序的健壮性和易维护性。要配置Spring框架以连接SQL Server数据库,需要遵循几个关键步骤,从…

这一辈子大多数日子是无聊的

本文纯属个人观点,搏您一笑,请勿上升至道德高度今天晚上去食堂吃饭的路上拍下了这张照片(图一):密密麻麻的不知道什么植物,如同校园里的学生一样多,它们占领了照片的下部。岸边的树、教学楼,乃至于远方的天空,天…

Elasticsearch面试精讲 Day 11:索引模板与动态映射 - 指南

Elasticsearch面试精讲 Day 11:索引模板与动态映射 - 指南2025-09-20 19:44 tlnshuju 阅读(0) 评论(0) 收藏 举报pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !importan…

Go 实现验证码识别

步骤 1:安装 Go 语言 首先,确保你的系统已经安装了 Go 语言。如果没有安装,可以从 Go 官网 下载并安装。 安装后,验证是否成功: 更多内容访问ttocr.com或联系1436423940 go version 步骤 2:安装 Tesseract OCR 我…

跳出 AI 编程的「兔子洞」,4 个实战策略帮你解决90%的死循环

在和 AI 协作编程的时候,你肯定遇到过这样一种情况: 使用 Claude Code 或者 Codex 信心满满的实现一个功能之后,结果你一运行,直接报错。 于是你把错误信息直接复制粘贴回给 AI,它态度好的一笔,立马道歉:非常抱…

用 PHP 和 Tesseract OCR 识别英文数字验证码

验证码是网页中常见的防止自动化攻击的工具,通常它们由一串字母和数字组成,目的是确认用户是人类而不是机器人。很多情况下,验证码都是扭曲、加噪音的图像,这让计算机很难直接读取。幸运的是,借助 OCR(Optical C…

凝望深渊时,深渊也凝望着你(黑洞与摇钱树)

/dev/null与/dev/zero在 Linux 系统中,/dev/null 和 /dev/zero 是两个特殊的设备文件,由内核提供,用于特定的数据处理目的。 /dev/null 是“只进不出”的黑洞,用于丢弃数据。 /dev/zero 是“只出不进”的零源,用于…