深入理解基于华为鲲鹏处理器的极致性能优化

鲲鹏处理器为核心的华为TaiShan服务器在国产服务器中可以说是名列前茅的。不仅仅是其高效的处理性能,还有针对鲲鹏处理器进行深度优化的原生应用以及不断壮大的共建鲲鹏社区。下面以鲲鹏处理器的软硬件性能优化为例,深入理解更为底层的技术方案,给你一个选择它的理由。

以一个4800*4800矩阵乘法为例阐述性能调优的重要性

为了实现4800*4800的矩阵乘法,我们有多种方式,例如可以使用python实现,可以使用C语言实现,进一步地,还可以使用C语言中的多线程并行运算来实现。当然,不同方式实现的方法在计算性能上也是不一样的。使用python这样的解释性语言,其大概需要耗费61162秒;使用C语言大概需要耗费757秒;而将原始矩阵进行拆分,使用C语言的并行计算,则可以将计算时间缩短到47秒。如果单从实现方式上来看的话,这个47秒相较于61162秒已经是缩短了1300多倍了,但是如果我们在硬件设施层面进行有针对地优化,我们会发现另一个世界。在将C语言并行计算与高效缓存优化结合之后,该计算时间可节省至6.02秒。而如果使用鲲鹏的NEON向量指令进行计算优化,可缩短至1.99秒,这就是鲲鹏的极致性能优化。

image.png

从冯诺依曼架构看性能调优

在冯诺依曼架构下,计算机可以抽象为存储器、控制器、输入以及输出设备。存储器分为内部存储器和外部存储器,程序在未运行时存储在外部存储器中,而在运行时则是加载到内部存储器中进行各种运算和处理。简单地,我们可以将计算机调优抽象为四个部分,分别为:CPU/内存、网卡、磁盘、应用。

imaged2f3f6c96d3b3254.png

基于鲲鹏处理器的软硬加速能力概览

鲲鹏处理器可针对应用实现软加速和硬加速。其中,软加速包括单核加速和多核加速;硬加速则包括芯片级别的加速引擎。

image99de002506abd9bf.png

从编译器和JDK的优化看鲲鹏的单核软加速能力

当前市面上常见的CPU架构是多流水线架构,其CPU指令是并发执行的。在这种情况下,某两条执行流水线存在相互依赖关系,那么一条流水线出现阻塞,另一条流水线则也有可能出现阻塞。针对上述问题,华为编译器进行了多种优化,其中包括:

  1. 指令布局优化:拆分函数代码,按照冷热指令重新排序,提升指令Cache命中率
  2. 内存布局优化:按照内存数据访问频度,组合热数据区域,提升数据Cache命中率
  3. 循环优化:分析循环迭代间数据访存依赖关系,对无依赖的循环并行到多核执行,无依赖的数据自动矢量化计算,加速程序运行。

对于Java开发者来说,JDK是再熟悉不过了。华为针对鲲鹏服务器推出的毕昇JDK也进行了如下优化:

  1. JIT编译优化,GC内存回收管理优化提升内存管理性能
  2. JVM循环、向量化、序列化技术,提升程序执行性能

imageee64d7156cbe10f2.png

基于NUMA的多核性能优化

2006年之后,CPU开始迈进多核的时代,刚开始的时候核数还比较少,采用的是SMP(对称多处理器)架构。在第一代CPU架构下,多核心可在系统层面做均衡调度,也就是多个核心都可以访问所有内存区域,具体如下图所示:

image145901771862bf46.png

由上图我们也发现了一个问题,CPU核心在访问内存区域时,都是通过单一的内存控制器去做的控制。显然,当核心数多了之后,单一控制器必然制约CPU的性能。

那么针对上述问题,NUMA架构便应运而生,其架构如下图所示:

image895ca2ea22cf613a.png

在NUMA架构下,将多核分为不同的NUMA节点,各个节点有自己的内存控制器。CPU核心通过NUMA节点内的内存控制器访问属于该节点的内存区域,当然也可以通过总线访问其他NUMA节点的内存区域。在这种情况下,随着核数增多,内存控制器也随之增多,从而很好解决内存访问瓶颈问题。

然而,从上图我们也会发现NUMA架构的一个问题,由于内存在物理上是分布式的,不同的核心访问不同内存的时间是不同的。如果核心访问的是最近的内存,那么其效率必然是最高的,如下图所示,Core0访问内存区域1的成本是低于内存区域2、3、4的。

image06b56b0710658646.png

当然,鲲鹏处理器也完成了内存访问最短路径的方法。利用NUMA-Aware亲和性资源规划实现进程与内存之间的距离更短,具体如图所示。

imagedd36276f5be05a34.png

以Nginx为例展示NUMA的优化效果

NGINX 是用于 Web 服务、反向代理、缓存、负载平衡、媒体流等的开源软件。 它最初是为实现最高性能和稳定性而设计的 Web 服务器。 除了 HTTP 服务器功能,NGINX 还可以用作电子邮件(IMAP、POP3 和 SMTP)的代理服务器以及 HTTP、TCP 和 UDP 服务器的反向代理和负载平衡器。

image9d801c912b6d3f36.png

从数据传输角度来说,数据到达业务进程中需要进行两次拷贝,第一次是通过网口拷贝到内核进程,第二次是将内核进程中的的数据再拷贝的业务进程中,由上图可见,两阶段的数据拷贝是离散的。而在NUMA优化情况下,可将网口、内核进程以及Nginx业务进程进行绑定。经实验验证,经过优化的Nginx端到端的时延可以有15%左右的提升。

image2a9757df846ce8cf.png
具体来说,可通过如下三种方式实现NUMA绑核配置方法:

  1. 使用系统工具numactl设置:numactl -C 0-15 process name -C: Core scope
  2. 在代码中调用亲和性设置参数:int sched_setaffinity(pid_t pid, size_t cpusetsize, cpu_set_t*mask)
  3. 多数开源软件中提供了配置接口:nginx中可在其配置文件nginx.conf中调整worker_cpu_affinity参数

基于鲲鹏技术优势构建加速库

除了上述描述的软加速能力之外,鲲鹏还提供了硬加速能力,针对基础加速、压缩加速、加解密加速、多媒体加速四类业务提供了9大加速库,典型场景达到了10%-100#的性能提升,具体如下图所示。

image8725598b9ba02cdf.png

以OpenSSL和压缩算法为例介绍加速库实现原理

如下图所示,当Web调用OpenSSL时,在不修改代码的情况下,通过路径2加载硬件加速库将计算卸载到芯片中做计算。

imagefc807ffb27b46704.png

在压缩算法中,鲲鹏支持gzip/zlib、ZSTD以及snappy压缩算法,基于高效的压缩引擎,鲲鹏处理器可大幅缩短文件的压缩时间,具体如下图所示:

image4371c3884d80ea0d.png

京东以鲲鹏RSA加密加速引擎,提升Web应用Https性能

京东的Web应用在未切换到鲲鹏加速方案之前,其使用的是传统的加速方案,通过QAT卡进行加密加速,其性能是相对较低的。而在使用鲲鹏加速方案之后,其HTTPS短连接性能提升了33%,具体如下图所示:

image310c704e79575d0b.png

优化磁盘与网卡,给鲲鹏处理器一个更好的运行环境

在前面提到的冯诺依曼架构中我们说到,除了CPU/内存以外,磁盘加载到内存过程的快慢也会影响业务的性能。下图展示了磁盘数据加载到应用内存中的流程。可以通过选用XFS文件系统、设置文件预读、脏数据刷新以及IO优化提高内存读取速度。

image0f84163497e8afe8.png

网卡中断产生频率也会影响应用的吞吐和延迟。下图展示了数据包请求到来之后的抽象逻辑图。简单来说,当数据到达网卡时,网卡会通知CPU其接收到了数据包,同时产生中断。

image8d5dc990d4942a23.png

而通过调整网卡中断策略,可以在低时延和高吞吐之间取更好的平衡点。

image4747fedd568d4354.png

通过应用调优充分发挥硬件性能

从一般的应用调优角度来说,我们可以通过提高并发、数据缓存以及异步读写的方式来提高应用的性能。然而我们也会发现一个问题,如果我们CPU核心很多,那是不是并发越多越好,如果我们内存很大,那是不是数据缓存越多越好呢?其实不一定,软件在适配硬件的同时,也要注意几点细节,比如说,锁机制以及Cache机制。

在多线程中,多个线程在访问一些公共变量时会出现抢锁的情况,而抢锁则会带来CPU时间片消耗。当线程数越来越多时,抢锁可能带来的CPU时间片消耗也越多,从而导致性能下降。针对该情况,我们需要通过无锁编程、大锁变小锁或者高性能原子操作指令等方式来优化并发性能。

imagec3d416b55d61f21a.png

在锁与内存优化中,Tcmalloc通过减少内存分配中的锁以提升高并发下的性能。

imagea3b095fefb0f5ae3.png

再来说一下针对鲲鹏的Cache机制优化来避免内存中伪共享的访问。CPU在将数据读取到CPU内存中时是以CacheLine大小进行读取的。在鲲鹏CPU中,CacheLine大小为128字节。在该128字节中,任何一个数据发生变化,那么整个CacheLine都会被置为无效。以下图为例,当有一个写频繁的变量和一个读频繁的变量放在一个CacheLine中,当写频繁的变量发生变化,会导致整个CacheLine失效,使得需要读取读频繁的变量时不得不再从外部区域进行加载。

image8335df4a8a29a35d.png

以MySQL 5.7.12为例,我们发现其内存对CacheLine进行硬编码,并设置为64,在进行调优并将其设置为鲲鹏的CacheLine大小之后,整体性能提升了5%。

imagef8e484c80eaddb3d.png

鲲鹏性能调优十板斧

鲲鹏社区根据使用经验,总结了性能调优十板斧。

在CPU和内存方面,可针对如下方面进行调整:

  1. 调整内存页大小
  2. CPU预取
  3. 修改线程调度策略

在磁盘方面可针对如下方面进行调整:

  1. 脏数据刷新
  2. 异步文件操作(libaio)
  3. 文件系统参数

在网卡方面可针对如下方面进行调整:

  1. 网卡多队列
  2. 开启网卡TSO
  3. 开启网卡CSUM

在应用方面,可针对如下方面进行调整:

  1. 优化编译选项
  2. 文件缓存机制
  3. 缓存执行结果
  4. NENO指令加速

当然,上述仅仅是粗略概括性能调优经验,详细可参考官方社区鲲鹏调优十板斧指南,链接为:https://bbs.huaweicloud.com/blogs/126788

以MariaDB为例看性能调优流程

性能调优三步法

通常来说,性能调优可以分为三个步骤:监控、分析以及优化。在优化之后,如果未达预期,那么我们还需要再进行监控、分析以及优化,如此反复。具体如下图所示:

image470439e2b7c7c70d.png

在监控阶段,我们需要使用监控工具针对CPU、内存、磁盘以及网卡各项指标进行记录。CPU的记录指标包括硬中断、软中断以及动态的CPU时间片占比;内存的记录指标包括numa内存访问命中率,内存是否足够;磁盘的记录包括iowait以及磁盘使用率等;网卡则需记录其传输带宽等。通过上述收集的指标分析判断优化方向。

在优化阶段,CPU方面可通过提高并发和线程绑核的方式,内存方面可通过减少跨numa访问、大页内存的方式,磁盘方面可通过I/O调度策略以及异步I/O的方式,而网卡方面则可通过中断聚合、网卡中断绑核的方式进行。

MariaDB性能优化-监控

sysbench压测MariDB 10.3.8数据库,OLTP模型读写比例为1:1。下图为监控示意图:

image3cd609af58af2a40.png

基于上图,我们可以发现一个问题,当线程数增多时,CPU使用率越来越高,而TPS在到达顶点之后反而下降了。在综合磁盘和网卡未到达性能瓶颈的情况下,我们可以得出CPU的使用瓶颈。

MariaDB性能优化-分析

当CPU时业务的性能瓶颈时,可通过分析进程热点函数来寻找优化空间,使用perf工具对本测试用例中的热点函数分析如下:随着并发线程数的增多,CPU的时间片集中在了锁的争抢中,这部分无用功造成了CPU资源的浪费。

image3b1c833ba8f3b0de.png

MariaDB性能优化-优化

通过查阅MariaDB资料,我们可以通过调整一下参数提高性能。

  1. innodb_thread_concurrency:控制并发线程数,默认值0表示,不限制并发
  2. innodb_sync_spin_loops:减少原子操作轮休次数
  3. innodb_spin_wait_delay:增加原子操作轮休间隔时间

image.png

总结

  1. CPU/内存、磁盘、网卡、应用,是我们性能调优的四个主要方向
  2. 采集性能指标、分析性能瓶颈、优化相关参数代码,是调优的基本思路
  3. 充分利用硬件资源才能发挥软件的最优性能
  4. 时延、吞吐、并发需要寻找一个均衡点

本文参考HDZ研习社学习视频《HDZ研习社07 发挥鲲鹏极致性能的软件优化》,链接为:https://bbs.huaweicloud.com/videos/102811

0 0 投票数
文章评分

本文为从大数据到人工智能博主「xiaozhch5」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。

原文链接:https://lrting.top/backend/4046/

(0)
上一篇 2022-03-09 00:40
下一篇 2022-03-10 01:38

相关推荐

订阅评论
提醒
guest

0 评论
内联反馈
查看所有评论
0
希望看到您的想法,请您发表评论x