目录
简略说明
什么是SMP (对称多处理器)
什么是 NUMA?
NUMA 的设置
测试 NUMA
Linux 的 NUMA 策略
附录1 NUMA(Non-Uniform Memory Access)
NUMA(Non-Uniform Memory Access)
关闭NUMA
调优
附录3 调优例子2
旧内容
什么是NUMA(Non-Uniform Memory Access)
NUMA的诞生背景
NUMA构架细节
什么是SMP
SMP
就是 对称多处理器 ,就是所有的cpu 必须通过相同的内存总线访问相同的内存资源。所以所有cpu访问内存等资源的速度是一样的,即对称。
缺点:CPU数量的增加,内存访问冲突将迅速增加,最终会造成CPU资源的浪费,使 CPU性能的有效性大大降低
NUMA
将CPU划分到多个Node中,每个node有自己独立的内存空间。各个node之间通过高速互联通讯
CPU访问不同类型节点内存的速度是不相同的,访问本地节点的速度最快,访问远端节点的速度最慢,即访问速度与节点的距离有关,距离越远访问速度越慢,即非一致。
缺点:本node的内存不足时,需要垮节点访问内存,节点接的访问速度慢。
SMP(Symmetric Multi-Processor)对称多CPU
对称多处理器结构:
1、服务器中多个CPU对称工作,无主次或从属关系。
2、各CPU共享相同的物理内存,每个 CPU访问内存中的任何地址所需时间是相同的。
因此SMP也被称为一致存储器访问结构(UMA:Uniform Memory Access)。
SMP服务器的主要特征是共享,系统中所有资源(CPU、内存、I/O等)都是共享的。也正是由于这种特征,导致了SMP服务器的主要问题,那就是它的扩展能力非常有限。由于每个CPU必须通过相同的内存总线访问相同的内存资源,因此随着CPU数量的增加,内存访问冲突将迅速增加,最终会造成CPU资源的浪费,使 CPU性能的有效性大大降低。
有实验数据表明,SMP型的服务器CPU最好是2-4颗就OK了,多余的就浪费了。
由于SMP在扩展能力上的限制,人们开始探究如何进行有效地扩展从而构建大型系统的技术,NUMA就是这种努力下的结果之一。
(摘自:https://blog.csdn.net/qq_21127151/article/details/106822131)
转自:每个程序员都应该知道的 CPU 知识:https://zhuanlan.zhihu.com/p/336365600
早期的计算机,内存控制器还没有整合进 CPU,所有的内存访问都需要经过北桥芯片来完成。如下图所示,CPU 通过前端总线(FSB,Front Side Bus)连接到北桥芯片,然后北桥芯片连接到内存——内存控制器集成在北桥芯片里面。
这种架构被称为 UMA1(Uniform Memory Access, 一致性内存访问 ):总线模型保证了 CPU 的所有内存访问都是一致的,不必考虑不同内存地址之间的差异。
在 UMA 架构下,CPU 和内存之间的通信全部都要通过前端总线。而提高性能的方式,就是不断地提高 CPU、前端总线和内存的工作频率。
后面的故事,大部分人都很清楚:因为物理条件的限制,不断提高工作频率的路子走不下去了。CPU 性能的提升开始从提高主频转向增加 CPU 数量(多核、多 CPU)。越来越多的 CPU 对前端总线的争用,使前端总线成为了瓶颈。为了消除 UMA 架构的瓶颈,NUMA2(Non-Uniform Memory Access, 非一致性内存访问)架构诞生了:
和 UMA 架构不同,在 NUMA 架构下,内存的访问出现了本地和远程的区别:访问远程内存的延时会明显高于访问本地内存。
Linux 有一个命令 numactl3 可以查看或设置 NUMA 信息。
numactl --hardware
可以查看硬件对 NUMA 的支持信息:# numactl --hardware
available: 2 nodes (0-1)
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 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 0 size: 96920 MB
node 0 free: 2951 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 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 1 size: 98304 MB
node 1 free: 33 MB
node distances:
node 0 1
0: 10 21
1: 21 10
numactl --show
显示当前的 NUMA 设置:# numactl --show
policy: default
preferred node: current
physcpubind: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95
cpubind: 0 1
nodebind: 0 1
membind: 0 1
--cpubind=0
: 绑定到 node 0 的 CPU 上执行。--membind=1
: 只在 node 1 上分配内存。--interleave=nodes
:nodes 可以是 all、N,N,N 或 N-N,表示在 nodes 上轮循(round robin)分配内存。--physcpubind=cpus
:cpus 是 /proc/cpuinfo 中的 processor(超线程) 字段,cpus 的格式与 --interleave=nodes 一样,表示绑定到 cpus 上运行。--preferred=1
: 优先考虑从 node 1 上分配内存。# 运行 test_program 程序,参数是 argument,绑定到 node 0 的 CPU 和 node 1 的内存
numactl --cpubind=0 --membind=1 test_program arguments
# 在 processor 0-4,8-12 上运行 test_program
numactl --physcpubind=0-4,8-12 test_program arguments
# 轮询分配内存
numactl --interleave=all test_program arguments
# 优先考虑从 node 1 上分配内存
numactl --preferred=1
#include
#include
#include
#include
int main(int argc, char** argv) {
int size = std::stoi(argv[1]);
std::vector> data(size, std::vector(size));
struct timeval b;
gettimeofday(&b, nullptr);
# 按列遍历,避免 CPU cache 的影响
for (int col = 0; col < size; ++col) {
for (int row = 0; row < size; ++row) {
data[row][col] = rand();
}
}
struct timeval e;
gettimeofday(&e, nullptr);
std::cout << "Use time "
<< e.tv_sec * 1000000 + e.tv_usec - b.tv_sec * 1000000 - b.tv_usec
<< "us" << std::endl;
}
# numactl --cpubind=0 --membind=0 ./numa_test 20000
Use time 16465637us
# numactl --cpubind=0 --membind=1 ./numa_test 20000
Use time 21402436us
可以看出,测试程序使用远程内存比使用本地内存慢了接近 30%
Linux 识别到 NUMA 架构后,默认的内存分配方案是:优先从本地分配内存。如果本地内存不足,优先淘汰本地内存中无用的内存。使内存页尽可能地和调用线程处在同一个 node。
这种默认策略在不需要分配大量内存的应用上一般没什么问题。但是对于数据库这种可能分配超过一个 NUMA node 的内存量的应用来说,可能会引起一些奇怪的性能问题。
下面是在网上看到的的例子:由于 Linux 默认的 NUMA 内存分配策略,导致 MySQL 在内存比较充足的情况下,出现大量内存页被换出,造成性能抖动的问题。
参考资料
发布于 2020-12-12 10:19
由于SMP在扩展能力上的限制,人们开始探究如何进行有效地扩展从而构建大型系统的技术,NUMA就是这种努力下的结果之一。利用NUMA技术,可以把几十个CPU(甚至上百个CPU)组合在一个服务器内。NUMA服务器的基本特征是具有多个CPU模块,每个CPU模块由多个CPU(如4个)组成,并且具有独立的本地内存、I/O槽口等。
由于其节点之间可以通过互联模块(如称为Crossbar Switch)进行连接和信息交互,因此每个CPU可以访问整个系统的内存(这是NUMA系统与MPP系统的重要差别)。
显然,访问本地内存的速度将远远高于访问远地内存(系统内其它节点的内存)的速度,这也是非一致存储访问NUMA的由来。
由于这个特点,为了更好地发挥系统性能,开发应用程序时需要尽量减少不同CPU模块之间的信息交互。利用NUMA技术,可以较好地解决原来SMP系统的扩展问题,在一个物理服务器内可以支持上百个CPU。比较典型的NUMA服务器的例子包括HP的Superdome、SUN15K、IBMp690等。
每个CPU模块之间都是通过互联模块进行连接和信息交互,CPU都是互通互联的,同时,每个CPU模块平均划分为若干个Chip(不多于4个),每个Chip都有自己的内存控制器及内存插槽。
在NUMA中还有三个节点的概念:
本地节点:对于某个节点中的所有CPU,此节点称为本地节点。
邻居节点:与本地节点相邻的节点称为邻居节点。
远端节点:非本地节点或邻居节点的节点,称为远端节点。
邻居节点和远端节点,都称作非本地节点(Off Node)。
CPU访问不同类型节点内存的速度是不相同的,访问本地节点的速度最快,访问远端节点的速度最慢,即访问速度与节点的距离有关,距离越远访问速度越慢,此距离称作Node Distance。应用程序要尽量的减少不通CPU模块之间的交互,如果应用程序能有方法固定在一个CPU模块里,那么应用的性能将会有很大的提升。
原文链接:Linux numactl命令与多核调优
附录2 numactl相关命令
安装
#yum install numactl -y
验证系统是否支持numa
dmesg | grep -i numa查看输出结果:
如果输出结果为:
No NUMA configuration found
说明numa为disable,如果不是上面的内容说明numa为enable
查看numa状态
# numactl --show
policy: default
preferred node: current
physcpubind: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
cpubind: 0 1
nodebind: 0 1
membind: 0 1
1234567
列举系统上的NUMA节点
#numactl --hardware
查看详细内容
# numastat
node0 node1
numa_hit 1296554257 918018444
numa_miss 8541758 40297198
numa_foreign 40288595 8550361
interleave_hit 45651 45918
local_node 1231897031 835344122
other_node 64657226 82674322
12345678
说明:
numa_hit—命中的,也就是为这个节点成功分配本地内存访问的内存大小
numa_miss—把内存访问分配到另一个node节点的内存大小,这个值和另一个node的numa_foreign相对应。
numa_foreign–另一个Node访问我的内存大小,与对方node的numa_miss相对应
local_node----这个节点的进程成功在这个节点上分配内存访问的大小
other_node----这个节点的进程 在其它节点上分配的内存访问大小
很明显,miss值和foreign值越高,就要考虑绑定的问题。
方法一:通过bios关闭
BIOS:interleave = Disable / Enable
方法二:通过OS关闭
1、编辑 /etc/default/grub 文件,加上:numa=off
GRUB_CMDLINE_LINUX="crashkernel=auto numa=off rd.lvm.lv=centos/root rd.lvm.lv=centos/swap rhgb quiet"
2、重新生成 /etc/grub2.cfg 配置文件:
# grub2-mkconfig -o /etc/grub2.cfg
NUMA的内存分配策略
1. 缺省(default):总是在本地节点分配(分配在当前进程运行的节点上);
2. 绑定(bind):强制分配到指定节点上;
3. 交叉(interleave):在所有节点或者指定的节点上交织分配;
4. 优先(preferred):在指定节点上分配,失败则在其他节点上分配。
因为NUMA默认的内存分配策略是优先在进程所在CPU的本地内存中分配,会导致CPU节点之间内存分配不均衡,当某个CPU节点的内存不足时,会导致swap产生,而不是从远程节点分配内存。这就是所谓的swap insanity 现象。
在实际使用中,可能存在存在不同进程对内存消耗不同,可以考虑按照需求绑定到不同的核上
查看cpu和内存使用情况
# numactl --hardware
available: 2 nodes (0-1)
node 0 cpus: 0 2 4 6 8 10 12 14 16 18 20 22 24 26 28 30
node 0 size: 64337 MB
node 0 free: 1263 MB
node 1 cpus: 1 3 5 7 9 11 13 15 17 19 21 23 25 27 29 31
node 1 size: 64509 MB
node 1 free: 30530 MB
node distances:
node 0 1
0: 10 21
1: 21 10
123456789101112
cpu0 可用 内存 1263 MB
cpu1 可用内存 30530 MB
当cpu0上申请内存超过1263M时必定使用swap,这个是很不合理的。
这里假设我要执行一个java param命令,此命令需要1G内存;一个python param命令,需要8G内存。
最好的优化方案时python在node1中执行,而java在node0中执行,那命令是:
#numactl --cpubind=0 --membind=0 python param
#numactl --cpubind=1 --membind=1 java param
内核参数overcommit_memory
它是 内存分配策略,可选值:0、1、2。
它是 内存分配策略,可选值:0、1、2。
- 0:表示内核将检查是否有足够的可用内存供应用进程使用;如果有足够的可用内存,内存申请允许;否则,内存申请失败,并把错误返回给应用进程。
- 1:表示内核允许分配所有的物理内存,而不管当前的内存状态如何。
- 2:表示内核允许分配超过所有物理内存和交换空间总和的内存
内核参数zone_reclaim_mode:
可选值0、1
当某个节点可用内存不足时:
1、如果为0的话,那么系统会倾向于从其他节点分配内存
2、如果为1的话,那么系统会倾向于从本地节点回收Cache内存多数时候,Cache对性能很重要,所以0是一个更好的选择
mongodb的NUMA问题
mongodb日志显示如下:
mongodb日志显示如下:
WARNING: You are running on a NUMA machine.
We suggest launching mongod like this to avoid performance problems:
numactl –interleave=all mongod [other options]
解决方案,临时修改numa内存分配策略为 interleave=all (在所有node节点进行交织分配的策略):
1.在原启动命令前面加numactl –interleave=all
如# numactl --interleave=all ${MONGODB_HOME}/bin/mongod --config conf/mongodb.conf
2.修改内核参数
echo 0 > /proc/sys/vm/zone_reclaim_mode ; echo "vm.zone_reclaim_mode = 0" >> /etc/sysctl.conf
原文链接:Linux numactl命令与多核调优
Linux提供了一个一个手工调优的命令numactl(默认不安装),首先你可以通过它查看系统的numa状态:
root@dc-skyeye:/usr/bin# numactl --hardware
available: 2 nodes (0-1)
node 0 cpus: 0 1 2 3 4 5 6 7 16 17 18 19 20 21 22 23
node 0 size: 131037 MB
node 0 free: 3019 MB
node 1 cpus: 8 9 10 11 12 13 14 15 24 25 26 27 28 29 30 31
node 1 size: 131071 MB
node 1 free: 9799 MB
node distances:
node 0 1
0: 10 20
1: 20 10
此系统共有2个node,各领取16个CPU和128G内存。
这里假设我要执行一个java param命令,此命令需要120G内存,一个python param命令,需要16G内存。最好的优化方案时python在node0中执行,而java在node1中执行,那命令是:
# numactl --cpubind=0 --membind=0 python param
# numactl --cpubind=1 --membind=1 java param
当然,也可以自找没趣
# numactl --cpubind=0 --membind=0,1 java param
对于一口气吃掉内存大半的MongoDB,我的配置是:
# numactl --interleave=all mongod -f /etc/mongod.conf
即分配所有的node供其使用,这也是官方推荐的用法。
通过numastat命令可以查看numa状态
# numastat
node0 node1
numa_hit 1775216830 6808979012
numa_miss 4091495 494235148
numa_foreign 494235148 4091495
interleave_hit 52909 53004
local_node 1775205816 6808927908
other_node 4102509 494286252
other_node过高意味着需要重新规划numa.
NUMA VS. UMA
NUMA(Non-Uniform Memory Access)非均匀内存访问架构是指多处理器系统中,内存的访问时间是依赖于处理器和内存之间的相对位置的。 这种设计里存在和处理器相对近的内存,通常被称作本地内存;还有和处理器相对远的内存, 通常被称为非本地内存。
UMA(Uniform Memory Access)均匀内存访问架构则是与NUMA相反,所以处理器对共享内存的访问距离和时间是相同的。由此可知,不论是NUMA还是UMA都是SMP架构的一种设计和实现上的选择。
作者:柴可夫斯猫
链接:https://zhuanlan.zhihu.com/p/67558970
在NUMA出现之前,CPU朝着高频率的方向发展遇到了天花板,转而向着多核心的方向发展。
在一开始,内存控制器还在北桥中,所有CPU对内存的访问都要通过北桥来完成。此时所有CPU访问内存都是“一致的”,如下图所示:
UMA
这样的架构称为UMA(Uniform Memory Access),直译为“统一内存访问”,这样的架构对软件层面来说非常容易,总线模型保证所有的内存访问是一致的,即每个处理器核心共享相同的内存地址空间。但随着CPU核心数的增加,这样的架构难免遇到问题,比如对总线的带宽带来挑战、访问同一块内存的冲突问题。为了解决这些问题,有人搞出了NUMA。
NUMA 全称 Non-Uniform Memory Access,译为“非一致性内存访问”。这种构架下,不同的内存器件和CPU核心从属不同的 Node,每个 Node 都有自己的集成内存控制器(IMC,Integrated Memory Controller)。
在 Node 内部,架构类似SMP,使用 IMC Bus 进行不同核心间的通信;不同的 Node 间通过QPI(Quick Path Interconnect)进行通信,如下图所示:
SMP VS. AMP
那么两者之间的主要区别是什么呢? 总结下来有这么几点,
《》https://houmin.cc/posts/b893097a/NUMA架构详解《》https://houmin.cc/posts/b893097a/
命令:
yum install numactl
numastat
numactl --hardware
cat /sys/class/net/enp129s0f0/device/numa_node
mpstat -P ALL
lscpu
1、centos 安装支持numa命令
yum install numactl
2、验证系统是否支持numa
dmesg | grep -i numa查看输出结果: 如果输出结果为: No NUMA configuration found 说明numa为disable,如果不是上面的内容说明numa为enable
3、查看numa的状态 numastat
numastat
numa_hit是打算在该节点上分配内存,最后从这个节点分配的次数;
num_miss是打算在该节点分配内存,最后却从其他节点分配的次数;
num_foregin是打算在其他节点分配内存,最后却从这个节点分配的次数;
interleave_hit是采用interleave策略最后从该节点分配的次数;
local_node该节点上的进程在该节点上分配的次数
other_node是其他节点进程在该节点上分配的次数
4、查看numa相关信息,包括每个node内存大小,每个node中的逻辑cpu
numactl --hardware
lscpu命令也可以查看呢cpu和node的关系
5、查看网卡对应的numa node
enp129s0f0是网卡的名字
cat /sys/class/net/enp129s0f0/device/numa_node
6、查看cpu负载
mpstat -P ALL(需要安装sysstat)
1) write 测试
# numactl --cpubind=0 --membind=0 dd if=/dev/zero of=/dev/shm/A bs=1M count=1024
1024+0 records in
1024+0 records out
1073741824 bytes (1.1 GB) copied, 0.823497 s, 1.3 GB/s
# numactl --cpubind=0 --membind=1 dd if=/dev/zero of=/dev/shm/A bs=1M count=1024
1024+0 records in
1024+0 records out
1073741824 bytes (1.1 GB) copied, 0.936182 s, 1.1 GB/s
明显访问同一节点的内存速度比访问不同节点内存的速度快。
2) read 测试
# numactl --cpubind=0 --membind=0 dd if=/dev/shm/A of=/dev/null bs=1K count=1024K
1048576+0 records in
1048576+0 records out
1073741824 bytes (1.1 GB) copied, 1.09543 s, 980 MB/s
# numactl --cpubind=0 --membind=1 dd if=/dev/shm/A of=/dev/null bs=1K count=1024K
1048576+0 records in
1048576+0 records out
1073741824 bytes (1.1 GB) copied, 1.11862 s, 960 MB/s
结论和write 相同。但是差距比较小。