暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

系统性能优化的一些细节

一十二章经 2021-04-17
1199

现代CPU大部分都采用NUMA(Non-Uniform Memory Access)架构,非一致性内存访问。在NUMA架构下我们的应用服务又应该注意什么细节?本篇主要说明NUMA架构下Java的JVM会遇到什么处境,又该如何优化。在开始之前可以先看一下以前写的这篇关于机器的硬件架构

什么是NUMA

NUMA称为非统一内存访问,在此之前也就是统一内存访问UMA(Uniform Memory Access),在UMA时代,所有的CPU访问内存都是通过系统总线到到北桥芯片然后访问内存,因此所有访问内存必须通过这条系统总线(也称前端总线)。这势必前端总线的带宽就成了整个系统的瓶颈。以下是UMA示意图:

NUMA架构则把多个处理器被划分到不同 Node 上,且每个 Node 都拥有自己的本地内存空间。Node中的CPU通过集成内存控制器通信(IMC,Integrated Memory Controller)。而不同的Node则通过QPI(Quick Path Interconnect)进行通信,如下所示:

在Linux系统中可以通过numactl --hardware是否关于NUMA节点的相关信息

[root@localhost ~]# numactl --hardware
available: 1 nodes (0)
node 0 cpus: 0 1 2 3 4 5 6 7
node 0 size: 6423 MB
node 0 free: 6078 MB
node distances:
node   0
  0:  10

我手头上是一颗4核8线程的CPU,可以看到上面输出的信息中1~7个逻辑处理器全部位于node节点上,因此当前机器上所有CPU核心共用一条IMC和一块内存。

NUMA架构下会造成什么问题

因为NUMA架构CPU是把多个核心与相关的内存绑定在一起了,以上图NUMA为例,CPU0和CPU1访问Node0本地内存是要快于访问Node1中的内存的。因此Linux采用了CPU亲和的内存分配策略,优先把应用所需内存分配到本地的内存而不是隔壁的Node的本地内存。

这样就可能会造成一个奇特的现象,Node0中的本地内存可能被占的很满而Node1的本地内存却free还很多。而又因为Linux的内存回收策略会导致Swap发生的很频繁,可是系统剩余可用内存却很多。

Swap机制是Linux内存回收方式之一,其工作原理是将内存中一些不活跃的匿名页刷入磁盘中,等到再次访问相关程序时再IO进内存。Swap涉及到磁盘的IO,如果过于频繁,也是极其损耗系统的性能。

如何设置JVM才能更好的适配NUMA架构

通过以上分析,采用NUMA架构的最主要问题就是内存占用不均匀导致Swap机制频繁发生,触发磁盘的IO。那么怎么样避免这个Swap频繁发生呢?

可以设置Linux的系统参数 /proc/sys/vm/swappiness。swappiness 默认值为60,数值越大,当内存紧张时越积极采用Swap释放内存,数值越小更倾向于释放文件页内存。至于释放文件页内存的过程,只要知道这个过程不涉及IO磁盘,只是回收系统一些cache或者buffer,开销比Swap小很多。

在JVM启动参数中有一个-XX:+UseNUMA,且该参数也只有在-XX:+UseParallelGC下起作用,也就是在Parallel Scavenge垃圾收集器下才能发挥NUMA架构CPU亲和的内存分配带来的性能提升。该参数也只能作用于Eden区,启用该参数,当需要分配内存空间给Java对象时,线程会到最近的CPU所属Node中的Eden区进行分配。从而获得最经济、快捷的内存访问。这个过程又涉及到把当前线程绑定到一颗CPU上运行还必须控制线程调度才能保证线程切换时不会切到另一颗CPU上运行,这也体现了CPU亲和性

通过上述分析知道了JVM为了适配NUMA架构做了一些优化。当然Swap机制释放内存还是不可避免的,我们可以手动关闭Swap分区,不发生内存换出。实际生产环境也是建议这么做的。最主要原因还是GC问题,假如把一个对象通过Swap刷入磁盘中,那么发生GC的时候就有可能去IO磁盘。

另外对于数据库系统(比如MySQL)都有着自己的Buffer Pool内存管理,比如InnoDB通过的URL、Free、Flush列表管理内存中的数据页。如果错误的将数据页Swap进磁盘将浪费很多CPU和IO资源。同样还是建议关闭Swap或设置/proc/sys/vm/swappiness = 0

总结

为了进一步提升机器的性能,使总线不要成为系统瓶颈,CPU从UMA转向了NUMA。但随之出现的问题就是内存分配不均匀导致Linux系统中的Swap机制频繁发生,但可用内存还非常多的尴尬局面。JVM为了迎合NUMA架构CPU也通过启用-XX:+UseNUMA参数来优化内存分配提升性能。在线上生产中,我们更多的会把Swap发生的活跃度调低甚至关闭以防频繁的发生IO,另外,通过本篇我们在分析内存的使用时,我们也应该针对每个 Node 单独分析。


参考:

https://www.zhihu.com/question/28540050?sort=created

http://cenalulu.github.io/linux/numa/

http://blog.chinaunix.net/uid-20737871-id-3446972.html

文章转载自一十二章经,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论