NUMA

NUMA由来

NUMA(Non-Uniform Memory Access),即非一致性内存访问,是一种关于多个CPU如何访问内存的架构模型,早期,在计算机系统中,CPU是这样访问内存的:

image

在这种架构中,所有的CPU都是通过一条总线来访问内存,我们把这种架构叫做SMP架构(Symmetric Multi-Processor),也就是对称多处理器结构。可以看出来,SMP架构有下面4个特点:

  • CPU和CPU以及CPU和内存都是通过一条总线连接起来
  • CPU都是平等的,没有主从关系
  • 所有的硬件资源都是共享的,即每个CPU都能访问到任何内存、外设等
  • 内存是统一结构和统一寻址的(UMA, Uniform Memory Architecture)

SMP架构在CPU核不多的情况下,问题不明显,有实验证明,SMP服务器CPU利用率最好的情况是2至4个CPU:

image

但是随着CPU多核技术的发展,一颗物理CPU中集成了越来越多的core,导致SMP架构的性能瓶颈越来越明显,因为所有的处理器都通过一条总线连接起来,因此随着处理器的增加,系统总线成为了系统瓶颈,另外,处理器和内存之间的通信延迟也较大。

为了解决SMP架构下不断增多的CPU Core导致的性能问题,NUMA架构应运而生,NUMA调整了CPU和内存的布局和访问关系,具体示意如下图:image

在NUMA架构中,将CPU划分到多个NUMA Node中,每个Node有自己独立的内存空间和PCIE总线系统。各个CPU间通过QPI总线进行互通。

CPU访问不同类型节点内存的速度是不相同的,访问本地节点的速度最快,访问远端节点的速度最慢,即访问速度与节点的距离有关,距离越远访,问速度越慢,所以叫做非一致性内存访问,这个访问内存的距离我们称作Node Distance。

虽然NUMA很好的解决了SMP架构下CPU大量扩展带来的性能问题,但是其自身也存在着不足,当Node节点本地内存不足时,需要跨节点访问内存,节点间的访问速度慢,从而也会带来性能的下降。所以我们在编写应用程序时,要充分利用NUMA系统的这个特点,尽量的减少不同CPU模块之间的交互,避免远程访问资源,如果应用程序能有方法固定在一个CPU模块里,那么应用的性能将会有很大的提升。

NUMA架构下的CPU和内存分布

在Linux系统上,可以查看到NUMA架构下CPU和内存的分布情况,不过在这之前,我们先得理清几个概念:

  • Socket:表示一颗物理 CPU 的封装(物理 CPU 插槽),简称插槽。为了避免将逻辑处理器和物理处理器混淆,Intel 将物理处理器称为插槽,Socket表示可以看得到的真实的CPU核 。
  • Core:物理 CPU 封装内的独立的一组程序执行的硬件单元,比如寄存器,计算单元等,Core表示的是在同一个物理核内逻辑层面的核。同一个物理CPU的多个Core,有自己独立的L1和L2 Cache,共享L3 Cache
  • Thread:使用超线程技术虚拟出来的逻辑 Core,需要 CPU 支持。为了便于区分,逻辑 Core 一般被写作 Processor。在具有 Intel 超线程技术的处理器上,每个内核可以具有两个逻辑处理器,这两个逻辑处理器共享大多数内核资源(如内存缓存和功能单元)。此类逻辑处理器通常称为 Thread 。超线程可以在一个逻辑核等待指令执行的间隔(等待从cache或内存中获取下一条指令),把时间片分配到另一个逻辑核。高速在这两个逻辑核之间切换,让应用程序感知不到这个间隔,误认为自己是独占了一个核。对于每个逻辑线程,拥有完整独立的寄存器集合和本地中断逻辑,共享执行单元和一二三级Cache,超线程技术可以带来20%~30%的性能提升。
  • Node:即NUMA Node,包含有若干个 CPU Core 的组。

numactl命令

numactl --hardware(numactl -H)

available: 1 nodes (0)
node 0 cpus: 0 1
node 0 size: 1756 MB
node 0 free: 147 MB
node distances:
node   0 
  0:  10 

这个主机上面的node节点只有一个,不太容易得到真实的架构

node distances:
node   0   1   2   3
  0:  10  20  30  40
  1:  20  10  50  60
  2:  30  50  10  70
  3:  40  60  70  10
可以得到如下图
+----------------+       +----------------+
| Node 0         |       | Node 1         |
| CPUs: 0-3      |<----->| CPUs: 4-7      |
| Mem: 32GB      | 20    | Mem: 32GB      |
+----------------+       +----------------+
      | 30                    | 50
      v                       v
+----------------+       +----------------+
| Node 2         |       | Node 3         |
| CPUs: 8-11     |<----->| CPUs: 12-15    |
| Mem: 32GB      | 70    | Mem: 32GB      |
+----------------+       +----------------+
其中访问本地内存的延迟为10,数值代表访问延时

numactl --cpunodebind=0 --membind=1 myprogram

分开指定cpu和内存

  • 高 CPU 密集型任务:绑定 CPU 到特定节点(--cpunodebind)。
  • 高内存带宽需求任务:绑定内存到特定节点(--membind)。

numactl --cpunodebind=0,1 --membind=0 myprogram:绑定两个cpu

posted @ 2025-08-26 16:24  pointarray  阅读(23)  评论(0)    收藏  举报