深挖NUMA

标签: Linux 硬件相关 服务器 系统架构 | 发表时间:2017-10-31 12:19 | 作者:litrin
出处:http://www.litrin.net

首先列出本站之前相关的几篇帖子:

这次,就来深入了解下NUMA。

就如之前说的,在若干年前,对于x86架构的计算机,那时的内存控制器还没有整合进CPU,所有内存的访问都需要通过北桥芯片来完成。此时的内存访问如下图所示,被称为UMA( uniform memory access, 一致性内存访问  )。这样的访问对于软件层面来说非常容易实现:总线模型保证了所有的内存访问是一致的,不必考虑由不同内存地址之前的差异。

之后的x86平台经历了一场从“拼频率”到“拼核心数”的转变,越来越多的核心被尽可能地塞进了同一块芯片上,各个核心对于内存带宽的争抢访问成为了瓶颈;此时软件、OS方面对于SMP多核心CPU的支持也愈发成熟;再加上各种商业上的考量,x86平台也顺水推舟的搞了NUMA(Non- uniform memory access, 非一致性内存访问)。

在这种架构之下,每个Socket都会有一个独立的内存控制器IMC( integrated memory controllers, 集成内存控制器),分属于不同的socket之内的IMC之间通过QPI link通讯。

然后就是进一步的架构演进,由于每个socket上都会有多个core进行内存访问,这就会在每个core的内部出现一个类似最早SMP架构相似的内存访问总线,这个总线被称为IMC bus。

于是,很明显的,在这种架构之下,两个socket各自管理1/2的内存插槽,如果要访问不属于本socket的内存则必须通过QPI link。也就是说内存的访问出现了本地/远程(local/remote)的概念,内存的延时是会有显著的区别的。这也就是 之前那篇文章中提到的为什么NUMA的设置能够明显的影响到JVM的性能。

回到当前世面上的CPU,工程上的实现其实更加复杂了。以 Xeon 2699 v4系列CPU的标准来看,两个Socket之之间通过各自的一条9.6GT/s的QPI link互访。而每个Socket事实上有2个内存控制器。双通道的缘故,每个控制器又有两个内存通道(channel),每个通道最多支持3根内存条(DIMM)。理论上最大单socket支持76.8GB/s的内存带宽,而两个QPI link,每个QPI link有9.6GT/s的速率(~57.6GB/s)事实上QPI link已经出现瓶颈了。

嗯,事情变得好玩起来了。

核心数还是源源不断的增加,Skylake桌面版本的 i7 EE已经有了18个core,下一代的Skylake Xeon妥妥的超越22个Core。为了塞进更多的core,原本核心之间类似环网的设计变成了复杂的路由。由于这种架构上的变化,导致内存的访问变得更加复杂。两个IMC也有了local/remote的区别,在保证兼容性的前提和性能导向的纠结中,系统允许用户进行更为灵活的内存访问架构划分。于是就有了“NUMA之上的NUMA”这种妖异的设定(SNC)。

回到Linux,内核 mm/ mmzone.c , include/ linux/ mmzone.h文件定义了NUMA的数据结构和操作方式。

Linux Kernel中NUMA的调度位于 kernel/ sched/ core.c函数int sysctl_numa_balancing

  1. 在一个启用了NUMA支持的Linux中,Kernel不会将任务内存从一个NUMA node搬迁到另一个NUMA node。
  2. 一个进程一旦被启用,它所在的NUMA node就不会被迁移,为了尽可能的优化性能,在正常的调度之中,CPU的core也会尽可能的使用可以local访问的本地core,在进程的整个生命周期之中,NUMA node保持不变。
  3. 一旦当某个NUMA node的负载超出了另一个node一个阈值(默认25%),则认为需要在此node上减少负载,不同的NUMA结构和不同的负载状况,系统见给予一个延时任务的迁移——类似于漏杯算法。在这种情况下将会产生内存的remote访问。

通常情况下,用户可以通过numactl来进行NUMA访问策略的手工配置,cgroup中cpuset.mems也可以达到指定NUMA node的作用。以numactl命令为例,它有如下策略:

  • –interleave=nodes //允许进程在多个node之间交替访问
  • –membind=nodes //将内存固定在某个node上,CPU则选择对应的core。
  • –cpunodebind=nodes //与membind相反,将CPU固定在某(几)个core上,内存则限制在对应的NUMA node之上。
  • –physcpubind=cpus //与cpunodebind类似,不同的是物理core。
  • –localalloc //本地配置
  • –preferred=node //按照推荐配置

对于某些大内存访问的应用,比如Mongodb,将NUMA的访问策略制定为interleave=all则意味着整个进程的内存是均匀分布在所有的node之上,进程可以以最快的方式访问本地内存。

最后一句: 那种一个业务就能跑满整台server的时代是再也回不来了!

相关 [numa] 推荐:

NUMA微架构

- - 夏清然的日志
现在开始补日志,逐步的扫清以前写了一半的和“欠账未还的”. 半年之前开的头,今天先把NUMA说完. PC硬件结构近5年的最大变化是多核CPU在PC上的普及,多核最常用的SMP微架构:. 多个CPU之间是平等的,无主从关系(对比IBM Cell);. 多个CPU平等的访问系统内存,也就是说内存是统一结构、统一寻址的(UMA,Uniform Memory Architecture);.

深挖NUMA

- - 开源小站
首先列出本站之前相关的几篇帖子:. cgroup的cpuset问题. 这次,就来深入了解下NUMA. 就如之前说的,在若干年前,对于x86架构的计算机,那时的内存控制器还没有整合进CPU,所有内存的访问都需要通过北桥芯片来完成. 此时的内存访问如下图所示,被称为UMA( uniform memory access, 一致性内存访问  ).

NUMA技术相关笔记

- - CSDN博客架构设计推荐文章
起源于在mongo启动脚本中看到numactl --interleave=all mongod .... NUMA,非统一内存访问(Non-uniform Memory Access),介于SMP(对称多处理)和MPP(大规模并行处理)之间,各个节点自有内存(甚至IO子系统),访问其它节点的内存则通过高速网络通道.

NUMA对性能的影响

- - 开源小站
事出这一段时间做了不少基于SPECjbb2005的系统性能测试,发觉对于不少平台,可以出现相当大的采样偏差,而有这么一台主机却表现的相当稳定. 仔细排查之后,最终定位到了NUMA. 之前曾经介绍过 NUMA的原理以及基于 Cgroup的NUMA设定. 这次我采用的是通过docker封装好的SPECjbb2005,Docker从本质上说底层就是一个cgroup.

NUMA 架构中 MySQL 的 “swap insanity” 问题

- khsing - Linux@SOHU
翻译:王鑫、朱翊然、李凯、曾怀东、马少兵、林业. 在一台包括了2个4核CPU,64GB内存的服务器上,给 MySQL 配置了 48GB 之巨的 InnoDB 缓冲,随着时间的推移,尽管观察到的数据(见最后注1)表示并没有真正的内存压力,Linux 也会把大量的内存交换到磁盘上. 通过监控发现,配置的内存超过了实际所需,而且也不存在内存泄漏,mysqld的RSS占用正常且稳定.

修改numa和io调度优化mysql性能

- 高春辉 - C1G军火库
单机单实例,建议关闭NUMA,关闭的方法有三种:. 1.硬件层,在BIOS中设置关闭;. 2.OS内核,启动时设置numa=off;. 3.可以用numactl命令将内存分配策略修改为interleave(交叉). 修改mysql.server 330行加上numactl. numastat 查看内存分配.

NUMA架构的CPU -- 你真的用好了么?

- - cenalulu's Tech Blog
本文从NUMA的介绍引出常见的NUMA使用中的陷阱,继而讨论对于NUMA系统的优化方法和一些值得关注的方向. 文章欢迎转载,但转载时请保留本段文字,并置于文章的顶部. 作者:卢钧轶(cenalulu). 本文原文地址: http://cenalulu.github.io/linux/numa/.