【性能】什么是NUMA(Non-Uniform Memory Access)|什么是SMP

122 篇文章 23 订阅

目录

简略说明

什么是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 (对称多处理器)

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

什么是 NUMA?

转自:每个程序员都应该知道的 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, 非一致性内存访问)架构诞生了:

  1. CPU 厂商把内存控制器集成到 CPU 内部,一般一个 CPU socket 会有一个独立的内存控制器。
  2. 每个 CPU scoket 独立连接到一部分内存,这部分 CPU 直连的内存称为“本地内存”。
  3. CPU 之间通过 QPI(Quick Path Interconnect) 总线进行连接。CPU 可以通过 QPI 总线访问不和自己直连的“远程内存”。

和 UMA 架构不同,在 NUMA 架构下,内存的访问出现了本地和远程的区别:访问远程内存的延时会明显高于访问本地内存。

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
  1. CPU 被分成 node 0 和 node 1 两组(这台机器有两个 CPU Socket)。
  2. 一组 CPU 分配到 96 GB 的内存(这台机器总共有 192GB 内存)。
  3. node distances 是一个二维矩阵,node[i][j] 表示 node i 访问 node j 的内存的相对距离。比如 node 0 访问 node 0 的内存的距离是 10,而 node 0 访问 node 1 的内存的距离是 21。
  • 执行 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 
  • numactl 命令还有几个重要选项:
  1. --cpubind=0: 绑定到 node 0 的 CPU 上执行。
  2. --membind=1: 只在 node 1 上分配内存。
  3. --interleave=nodes:nodes 可以是 all、N,N,N 或 N-N,表示在 nodes 上轮循(round robin)分配内存。
  4. --physcpubind=cpus:cpus 是 /proc/cpuinfo 中的 processor(超线程) 字段,cpus 的格式与 --interleave=nodes 一样,表示绑定到 cpus 上运行。
  5. --preferred=1: 优先考虑从 node 1 上分配内存。
  • numactl 命令的几个例子:
# 运行 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

测试 NUMA

#include <sys/time.h>

#include <iostream>
#include <string>
#include <vector>

int main(int argc, char** argv) {
  int size = std::stoi(argv[1]);
  std::vector<std::vector<uint64_t>> data(size, std::vector<uint64_t>(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 策略

Linux 识别到 NUMA 架构后,默认的内存分配方案是:优先从本地分配内存。如果本地内存不足,优先淘汰本地内存中无用的内存。使内存页尽可能地和调用线程处在同一个 node。

这种默认策略在不需要分配大量内存的应用上一般没什么问题。但是对于数据库这种可能分配超过一个 NUMA node 的内存量的应用来说,可能会引起一些奇怪的性能问题。

下面是在网上看到的的例子:由于 Linux 默认的 NUMA 内存分配策略,导致 MySQL 在内存比较充足的情况下,出现大量内存页被换出,造成性能抖动的问题。

  • The MySQL “swap insanity” problem and the effects of the NUMA architecture4
  • A brief update on NUMA and MySQL5

参考资料

  1. UMA(Uniform Memory Access, 一致性内存访问):https://en.wikipedia.org/wiki/Uniform_memory_access
  2. NUMA(Non-Uniform Memory Access, 非一致性内存访问):https://en.wikipedia.org/wiki/Non-uniform_memory_access
  3. numactl:https://linux.die.net/man/8/numactl
  4. The MySQL “swap insanity” problem and the effects of the NUMA architecture:http://blog.jcole.us/2010/09/28/mysql-swap-insanity-and-the-numa-architecture/
  5. A brief update on NUMA and MySQL:http://blog.jcole.us/2012/04/16/a-brief-update-on-numa-and-mysql/
  6. NUMA架构的CPU -- 你真的用好了么?:http://cenalulu.github.io/linux/numa/
  7. Thread and Memory Placement on NUMA Systems: Asymmetry Matters:https://www.usenix.org/conference/atc15/technical-session/presentation/lepers
  8. NUMA (Non-Uniform Memory Access): An Overview:https://queue.acm.org/detail.cfm?id=2513149
  9. NUMA Memory Policy:https://www.kernel.org/doc/html/latest/admin-guide/mm/numa_memory_policy.html
  10. What is NUMA?:https://www.kernel.org/doc/html/latest/vm/numa.html

发布于 2020-12-12 10:19

附录1 NUMA(Non-Uniform Memory Access)

NUMA(Non-Uniform Memory Access)

由于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值越高,就要考虑绑定的问题。

关闭NUMA

方法一:通过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命令与多核调优

附录3 调优例子2

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(Non-Uniform Memory Access)

NUMA VS. UMA

NUMA(Non-Uniform Memory Access)非均匀内存访问架构是指多处理器系统中,内存的访问时间是依赖于处理器和内存之间的相对位置的。 这种设计里存在和处理器相对近的内存,通常被称作本地内存;还有和处理器相对远的内存, 通常被称为非本地内存

UMA(Uniform Memory Access)均匀内存访问架构则是与NUMA相反,所以处理器对共享内存的访问距离和时间是相同的。由此可知,不论是NUMA还是UMA都是SMP架构的一种设计和实现上的选择。

NUMA的诞生背景

作者:柴可夫斯猫
链接:https://zhuanlan.zhihu.com/p/67558970
 

在NUMA出现之前,CPU朝着高频率的方向发展遇到了天花板,转而向着多核心的方向发展。

在一开始,内存控制器还在北桥中,所有CPU对内存的访问都要通过北桥来完成。此时所有CPU访问内存都是“一致的”,如下图所示:

UMA

这样的架构称为UMA(Uniform Memory Access),直译为“统一内存访问”,这样的架构对软件层面来说非常容易,总线模型保证所有的内存访问是一致的,即每个处理器核心共享相同的内存地址空间。但随着CPU核心数的增加,这样的架构难免遇到问题,比如对总线的带宽带来挑战、访问同一块内存的冲突问题。为了解决这些问题,有人搞出了NUMA。

NUMA构架细节

NUMA 全称 Non-Uniform Memory Access,译为“非一致性内存访问”。这种构架下,不同的内存器件和CPU核心从属不同的 Node,每个 Node 都有自己的集成内存控制器(IMC,Integrated Memory Controller)。

在 Node 内部,架构类似SMP,使用 IMC Bus 进行不同核心间的通信;不同的 Node 间通过QPI(Quick Path Interconnect)进行通信,如下图所示:

什么是SMP

SMP VS. AMP

那么两者之间的主要区别是什么呢? 总结下来有这么几点,

  1. SMP的多个处理器都是同构的,使用相同架构的CPU;而AMP的多个处理器则可能是异构的。
  2. SMP的多个处理器共享同一内存地址空间;而AMP的每个处理器则拥有自己独立的地址空间。
  3. SMP的多个处理器操通常共享一个操作系统的实例;而AMP的每个处理器可以有或者没有运行操作系统,运行操作系统的CPU也是在运行多个独立的实例。
  4. SMP的多处理器之间可以通过共享内存来协同通信;而AMP则需要提供一种处理器间的通信机制。

《》https://houmin.cc/posts/b893097a/NUMA架构详解《》https://houmin.cc/posts/b893097a/ 

numa查看和命令

命令:

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)

7、 测试(访问不同节点的内存的IO)(参考linux NUMA技术_未央君x的博客-CSDN博客

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 相同。但是差距比较小。

  • 8
    点赞
  • 109
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值