当前位置: 首页 > news >正文

性能调优之NUMA调优

什么是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.zskr.cn/news/8695.html

相关文章:

  • 实用指南:光学神经网络与人工智能应用
  • Zabbix 企业级监控架构实战指南:从搭建、可视化到智能告警
  • U522155 数据生成(小心电脑)
  • 实用指南:OSG中osgFX库
  • 2025.9.20——1橙
  • 用 PHP 和 Tesseract OCR 识别英文数字验证码
  • 凝望深渊时,深渊也凝望着你(黑洞与摇钱树)
  • spring项目部署后为什么会生成 logback-spring.xml记录
  • 202509_NBWS_logbool
  • Kubernetes权威指南-深入理解Pod Service
  • 4980:拯救行动
  • java03-wxj
  • AI 智能体与 Coze 工作流实践:小红书对标账号采集 - 实践
  • 对比六种JavaScript全文搜索库 fuse.js 、 lunr 、 flexsearch 、 minisearch 、 search-index 、 js-sea
  • 从零开始: c#纯代码实现完整Json解析器的全过程及注释与自定义格式的支持实现
  • 大模型服务之下的新旧政务智能系统比较 - 指南
  • CentOS7.9上安装MySQL8.4
  • JBoltAI框架:企业级AI开发的革新路径与行业实践 - 那年-冬季
  • JBoltAI:重塑视频创作,开启零门槛智能混剪新时代 - 那年-冬季
  • 12,FreeRTOS队列执行
  • 2025csp初赛
  • 第一节计算机硬件基本组成
  • PyTorch深度学习实战【11】之神经网络的学习和训练 - 详解
  • strtol() 函数 - 字符串转长整数(long int)
  • 对Transformer的个人理解
  • 最小生成树MST-07 - jack
  • 不定高元素动画实现方案(上)
  • 详细介绍:Node.js中Express框架入门教程
  • 基于LlamaIndex的相似性搜索
  • 编写代码时遇到的checkstyle问题归纳