本文参考了以下文章、视频:
一句话
NUMA 指的是针对某个 CPU,内存访问的距离和时间是不一样的。是为了解决多 CPU 系统下共享 BUS 带来的性能问题。(这句话可能不太严谨,不是为了解决,而是事实上解决了。)
NUMA 架构图
从最简单的开始,一个 CPU(注意:这里指的是物理 CPU,不是核。需要注意的一点是NUMA 是针对多物理 CPU 而言的,而不是多核。),通过 bus 和 RAM 相连。
接下来多CPU 出现了(再说一次,不是多核单CPU!),如果还是像之前那样将所有的CPU 通过一个 BUS 和 RAM 相连,BUS 会成为性能的杀手。而且,加的 CPU 越多,性能损耗会越高。
这时候 NUMA 架构就展露身手了:通过把 CPU 和临近的 RAM 当做一个 node,CPU 会优先访问距离近的 RAM。同时,CPU 直接有一个快速通道连接,所以 每个CPU 还是访问到所有的 RAM 位置(只是速度会有差异)。
实际中,一个不一定单独占有一个 RAM,可以有下面这些很多种组合:
浅看 Linux 中的NUMA架构
以下操作在阿里云云服务器 Ubuntu18.04环境下运行
首先通过dmesg | grep -i numa
查看一下系统是不是支持numa:可见当前系统不支持 :)
然后使用一个工具: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。
上面两段翻译自: ,如有不清晰的地方,请移步原文。
看一个MySQL 的实例
优质好文,有能力的同学最好还是直接看原文: 我这里简单翻译一下。
文中提到了一个问题:在一个有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: