Linux 内核 101:NUMA架构

本文参考了如下文章、视频:node

一句话

NUMA 指的是针对某个 CPU,内存访问的距离和时间是不同的。是为了解决多 CPU 系统下共享 BUS 带来的性能问题。(这句话可能不太严谨,不是为了解决,而是事实上解决了。)mysql

NUMA 架构图

从最简单的开始,一个 CPU(注意:这里指的是物理 CPU,不是核。须要注意的一点是NUMA 是针对多物理 CPU 而言的,而不是多核。),经过 bus 和 RAM 相连。git

接下来多CPU 出现了(再说一次,不是多核单CPU!),若是仍是像以前那样将全部的CPU 经过一个 BUS 和 RAM 相连,BUS 会成为性能的杀手。并且,加的 CPU 越多,性能损耗会越高。github

这时候 NUMA 架构就展露身手了:经过把 CPU 和临近的 RAM 当作一个 node,CPU 会优先访问距离近的 RAM。同时,CPU 直接有一个快速通道链接,因此 每一个CPU 仍是访问到全部的 RAM 位置(只是速度会有差别)。算法

实际中,一个不必定单独占有一个 RAM,能够有下面这些不少种组合:sql

浅看 Linux 中的NUMA架构

如下操做在阿里云云服务器 Ubuntu18.04环境下运行数据库

首先经过dmesg | grep -i numa查看一下系统是否是支持numa:可见当前系统不支持 :)bash

而后使用一个工具:numactl,能够经过 apt install numactl进行安装。而后运行:服务器

numactl --hardware
复制代码

还有一个实用工具:lstopo,经过 apt install lstopo微信

lstopo --of png > server.png
复制代码

从图中能够看到,有一个node 节点。为何个人系统不支持 numa,Linux 仍是把全部的 CPU 和全部的 RAM 组合到一块儿成为一个 node 呢?这不是闲的没事干嘛?

关于这一点,《Understanding the Linux Kernel》一书里面这么说:

这主要是出于代码可扩展性的考虑,这样一套代码就能够在不支持 numa 和支持 numa 的环境下运行了。

若是是支持 numa 架构的服务器,看到的图会是这样的:

NUMA 对Linux 会产生什么影响?

系统 boot 的时候,硬件会把 numa 信息发送给 os,若是系统支持 numa,会发生如下几件事:

  • 获取 numa 配置信息
  • 将 processors(不是 cores) 分红不少 nodes,通常是一个 processor 一个 node。
  • 将 processor 附近的 memory 分配给它。
  • 计算node 间通讯的cost(距离)。

若是你只是把 CPU 和内存看成是黑盒子,简单地期待它 work 的话,可能会发生意想不到的事情。

  • 每一个进程、线程都会继承一个 numa policy,定义了可使用那些CPU(甚至是那些 core),哪些内存可使用,以及 policy 的强制程度,便是优先仍是强制性只容许。
  • 每一个 thread 被分配到了一个”优先” 的 node 上面运行,thread 能够在其余地方运行(若是 policy 容许的话),可是 os 会尝试让他在优先地 node 上面去运行。
  • 内存分配:默认内存从同一个 node 里面进行分配。
  • 在一个 node 上面分配地内存不会被移动到其余node。

上面两段翻译自: blog.jcole.us/2010/09/28/… ,若有不清晰的地方,请移步原文。

看一个MySQL 的实例

优质好文,有能力的同窗最好仍是直接看原文: blog.jcole.us/2010/09/28/… 我这里简单翻译一下。

文中提到了一个问题:在一个有64G 内存、2个 4核 CPU 的 Linux 服务器中运行 MySQL 服务,MySQL 配置了48G 的 innodb buffer pool。而后发现,尽管系统还有不少空余的内容,不少内存被 swap 出去了。

这带来了极大的性能问题,由于query 的时候若是须要的内容被 swap 出去了。。就须要再 load 回来。这也是困恼了MySQL 社区很长时间的问题。

前面说到 Linux 有一个 numa policy,这个是能够人为控制的。

  • —localalloc ,使用当前 node,默认。
  • --preferred=node,优先实用指定的 node,实在不行用其余的 nod 也能够。
  • --membind=nodes,老是使用人为指定一个或多个 nodes。
  • --interleaved=all,采用round-robin算法轮流使用不一样的 node。

从 Linux os 的角度来看,MySQL 数据库就是一个进程,会优先让他在某一个 node 中运行。若是只是使用少部份内存,这没什么问题,可是当你要占用系统大多数内存的时候,问题就来了:

因为 os 会试图让你在某个『优先』的node里面运行,就会产生内存分配不均匀的状况:

Node0 已经快被占满了,Node1还剩下不少。因为 node0和 node1是独立的,尽管 node1里面有空余内存,node0里面的内存仍是会被 swap 出去。这就是前面提到的问题的根源。

那么怎么解决呢?

numactl --interleave all command
复制代码

用前面提到的--interleave all numa policy,将这段添加到mysqld_save 语句前面。事后,内存分配就是均匀的了,内存足够的状况下,就不会出现异常的 swap 现象了。

固然这只是一个最简单粗暴的解决方案,还有其余更好的,原文有说起,可是不是本文的重点,因此就不深刻探讨了。

总结一下

摩尔定律正在失效,当 CPU 的性能总会有极限的那一天,多 CPU 才是将来。做为一个有理想的搬砖工人,至少仍是应该多了解一下多 CPU 系统架构。做为一个系统软件开发者,更应该熟悉多 CPU 架构,让本身开发的应用充分利用硬件福利。

广告时间,欢迎你们关注个人微信公众号。同时本文同步于 github: github.com/liaochangji…