zoukankan      html  css  js  c++  java
  • 鲲鹏性能优化十板斧(二)——CPU与内存子系统性能调优

    1.1 CPU与内存子系统性能调优简介

    调优思路

    性能优化的思路如下:

          l   如果CPU的利用率不高,说明资源没有充分利用,可以通过工具(如strace)查看应用程序阻塞在哪里,一般为磁盘,网络或应用程序的业务处理中存在休眠或信号等待,这些优化措施在后续其它章节描述。

          l   如果CPU利用率高,通过优化软件硬件的配置参数来更好适配业务场景,减少CPU占用率,让整个系统有更多的CPU时间来处理业务。

    我们也可以选择更好的硬件,根据CPU的能力配置合适的内存条,建议内存满通道配置,发挥内存最大带宽:一颗鲲鹏920处理器的内存通道数为8,两颗鲲鹏920处理器的内存通道数为16;建议选择高频率的内存条,提升内存带宽:鲲鹏920在1DPC配置时,支持的内存最高频率为2933MHz。

    主要优化参数

    优化项

    优化项简介

    默认值

    生效范围

    鲲鹏916

    鲲鹏920

    优化应用程序的NUMA配置

    在NUMA架构下,CPU core访问临近的内存时访问延迟更低。将应用程序绑在一个NUMA节点,可减少因访问远端内存带来的性能下降。

    默认不绑定核

    立即生效

    yes

    yes

    修改CPU预取开关

    内存预取在数据集中场景下可以提前将要访问的数据读到CPU cache 中,提升性能;若数据不集中,导致预取命中率低,则浪费内存带宽。

    on

    重启生效

    no

    yes

    调整定时器机制

    nohz机制可减少不必要的时钟中断,减少CPU调度开销。

    不同OS默认配置不同

    Euler:nohz=off

    重启生效

    yes

    yes

    调整内存的页大小为64K

    内存的页大小越大,TLB中每行管理的内存越多,TLB命中率就越高,从而减少内存访问次数。

    不同OS默认配置不同:

    4KB或64K

    重新编译内核、更新内核后生效

    yes

    yes

    优化应用程序的线程并发数

    适当调整应用的线程并发数,使得充分利用多核能力和资源争抢之间达到平衡。

    由应用本身决定

    立即生效或重启生效(由应用决定)

    yes

    yes

    1.2 常用性能监测工具

    1.2.1 top工具

    介绍

    top是最常用的Linux性能监测工具之一。通过top工具可以监视进程和系统整体性能。

    命令参考举例:

    命令

    说明

    top

    查看系统整体的CPU、内存资源消耗。

    top执行后输入1

    查看每个CPU core资源使用情况。

    top执行后输入F,并选择P选项

    查看线程执行过程中是否调度到其它CPU core。

    top -p $PID -H

    查看某个进程内所有线程的CPU资源占用。

    安装方式

    系统自带,无需安装。

    使用方法

                                    步骤 1      使用top命令统计整体CPU、内存资源消耗。

    l   CPU项:显示当前总的CPU时间使用分布。

    • us表示用户态程序占用的CPU时间百分比。

    • sy表示内核态程序所占用的CPU时间百分比。

    • wa表示等待IO等待占用的CPU时间百分比。

    • hi表示硬中断所占用的CPU时间百分比。

    • si表示软中断所占用的CPU时间百分比。

    通过这些参数我们可以分析CPU时间的分布,是否有较多的IO等待。在执行完调优步骤后,我们也可以对CPU使用时间进行前后对比。如果在运行相同程序、业务情况下CPU使用时间降低,说明性能有提升。

    l   KiB Mem:表示服务器的总内存大小以及使用情况。

    l   KiB Swap:表示当前所使用的Swap空间的大小。Swap空间即当内存不足的时候,把一部分硬盘空间虚拟成内存使用。如果当前所使用的Swap空间大于0,可以考虑优化应用的内存占用或增加物理内存。

                                    步骤 2      在top命令执行后按1,查看每个CPU core的使用情况。

    通过该命令可以查看单个CPU core的使用情况,如果CPU占用集中在某几个CPU core上,可以结合业务分析触发原因,从而找到优化思路。

        步骤 3      选中top命令的P选项,查看线程运行在哪些 CPU core上。

    在top命令执行后按F,可以进入top命令管理界面。在该界面通过上下键移动光标到P选项,通过空格键选中后按Esc退出,即可显示出线程运行的CPU核。观察一段时间,若业务线程在不同NUMA节点内的CPU core上运行,则说明存在较多的跨NUMA访问,可通过NUMA绑核进行优化。

     步骤 4      使用top -p $PID -H命令观察进程中每个线程的CPU资源使用。

    “-p”后接的参数为待观察的进程ID。通过该命令可以找出消耗资源多的线程,随后可根据线程号分析线程中的热点函数、调用过程等情况

    ----结束

    1.2.2 Perf工具

    介绍

    Perf工具是非常强大的Linux性能分析工具,可以通过该工具获得进程内的调用情况、资源消耗情况并查找分析热点函数。

    命令参考举例:

    命令

    说明

    perf top

    查看当前系统中的热点函数。

    perf sched record -- sleep 1 -p $PID

    记录进程在1s内的系统调用。

    perf sched latency --sort max

    查看上一步记录的结果,以调度延迟排序。

    安装方式

    以CentOS为例,使用如下命令安装:

    # yum -y install perf

    使用方法

                                    步骤 1      通过perf top命令查找热点函数。

    该命令统计各个函数在某个性能事件上的热度,默认显示CPU占用率,可以通过“-e”监控其它事件。

    l   Overhead表示当前事件在全部事件中占的比例。

    l   Shared Object表示当前事件生产者,如kernel、perf命令、C语言库函数等。

    l   Symbol则表示热点事件对应的函数名称。

    通过热点函数,我们可以找到消耗资源较多的行为,从而有针对性的进行优化。

     步骤 2      收集一段时间内的线程调用。

    perf sched record命令用于记录一段时间内,进程的调用情况。“-p”后接进程号,“sleep”后接统计时长,单位为秒。收集到的信息自动存放在当前目录下,文件名为perf.data。

       步骤 3      解析收集到的线程调度信息。

    perf sched latency命令可以解析当前目录下的perf.data文件。“-s”表示进行排序,后接参数“max”表示按照最大延迟时间大小排序。

    ----结束

    1.2.3 numactl工具

    介绍

    numactl工具可用于查看当前服务器的NUMA节点配置、状态,可通过该工具将进程绑定到指定CPU core,由指定CPU core来运行对应进程。

    命令参考举例:

    命令

    说明

    numactl -H

    查看当前服务器的NUMA配置。

    numactl -C 0-7 ./test

    将应用程序test绑定到0~7核运行。

    numastat

    查看当前的NUMA运行状态。

    安装方式

    以CentOS为例,使用如下命令安装:

    # yum -y install numactl numastat

    使用方法

                                    步骤 1      通过numactl查看当前服务器的NUMA配置。

    从numactl执行结果可以看到,示例服务器共划分为4个NUMA节点。每个节点包含16个CPU core,每个节点的内存大小约为64GB。同时,该命令还给出了不同节点间的距离,距离越远,跨NUMA内存访问的延时越大。应用程序运行时应减少跨NUMA访问内存。

    步骤 2      通过numactl将进程绑定到指定CPU core。

    通过 numactl -C 0-15 top 命令即是将进程“top”绑定到0~15 CPU core上执行。

    可以通过numastat命令观察各个NUMA节点的状态。

    l   numa_hit表示节点内CPU核访问本地内存的次数。

    l   numa_miss表示节点内核访问其他节点内存的次数。跨节点的内存访问会存在高延迟从而降低性能,因此,numa_miss的值应当越低越好,如果过高,则应当考虑绑核。

    ----结束

    1.3 优化方法

    1.3.1 NUMA优化,减少跨NUMA访问内存

    原理

    通过1.1 鲲鹏处理器NUMA简介章节可以看到不同NUMA内的CPU core访问同一个位置的内存,性能不同。内存访问延时从高到低为:跨CPU > 跨NUMA不跨CPU > NUMA内

    因此在应用程序运行时要尽可能的避免跨NUMA访问内存,我们可以通过设置线程的CPU亲和性来实现。

    修改方式

    l   网络可以通过如下方式绑定运行的CPU core,其中$cpuMask是16进制的数,最右边的bit表示core0;$irq为网卡队列中断号。

    echo $cpuMask > /proc/irq/$irq/smp_affinity_list

    l   通过numactl启动程序,如下面的启动命令表示启动test程序,只能在CPU core 28到core31运行(-C控制)。

    numactl -C 28-31 ./test

    l   在C/C++代码中通过sched_setaffinity函数来设置线程亲和性。

    l   很多开源软件已经支持在自带的配置文件中修改线程的亲和性,例如nginx可以修改nginx.conf文件中的worker_cpu_affinity参数来设置nginx线程亲和性。

    1.3.2 修改CPU的预取开关

    原理

    局部性原理分为时间局部性原理和空间局部性原理:

    l   时间局部性原理(temporal locality):如果某个数据项被访问,那么在不久的将来它可能再次被访问。

    l   空间局部性原理(spatial locality):如果某个数据项被访问,那么与其地址相邻的数据项可能很快也会被访问。

    CPU将内存中的数据读到CPU的高速缓冲Cache时,会根据局部性原理,除了读取本次要访问的数据,还会预取本次数据的周边数据到Cache里面,如果预取的数据是下次要访问的数据,那么性能会提升,如果预取的数据不是下次要取的数据,那么会浪费内存带宽。

    对于数据比较集中的场景,预取的命中率高,适合打开CPU预取,反之需要关闭CPU预取。目前发现speccpu和X265软件场景适合打开CPU预取,STREAM测试工具、Nginx和数据库场景需要关闭CPU预取。

    修改方式

    按照B 进入BIOS界面的步骤进入BIOS,然后在BIOS的如下位置设置CPU的预取开关。

    1.3.3 定时器机制调整,减少不必要的时钟中断

    原理

    在Linux内核2.6.17版本之前,Linux内核为每个CPU设置一个周期性的时钟中断,Linux内核利用这个中断处理一些定时任务,如线程调度等。这样导致就算CPU不需要定时器的时候,也会有很多时钟中断,导致资源的浪费。Linux 内核2.6.17版本引入了nohz机制,实际就是让时钟中断的时间可编程,减少不必要的时钟中断。

    修改方式

    执行cat /proc/cmdline查看Linux 内核的启动参数,如果有nohz=off关键字,说明nohz机制被关闭,需要打开。修改方法如下:

    image.png

    修改前后,可以通过如下命令观察timer_tick的调度次数,其中$PID为要观察的进程ID,可以选择CPU占用高的进程进行观察:

    perf sched record -- sleep 1 -p $PID

    perf sched latency -s max

    输出信息中有如下信息,其中591字段表示统计时间内的调度次数,数字变小说明修改生效。

    timer_tick:(97) | 7.364 ms | 591 | avg: 0.012 ms | max: 1.268 ms

                                    步骤 1      在“/boot”目录下通过find -name grub.cfg找到启动参数的配置文件。

                                    步骤 2      在配置文件中将nohz=off去掉。

                                    步骤 3      重启服务器。

    ----结束

    1.3.4 调整内存页的大小为64K,提升TLB命中率

    原理

    TLB(Translation lookaside buffer)为页表(存放虚拟地址的页地址和物理地址的页地址的映射关系)在CPU内部的高速缓存。TLB的命中率越高,页表查询性能就越好。

    TLB的一行为一个页的映射关系,也就是管理了一个页大小的内存:

    TLB管理的内存大小 = TLB行数 x 内存的页大小

    同一个CPU的TLB行数固定,因此内存页越大,管理的内存越大,相同业务场景下的TLB命中率就越高。

    修改方式

    修改Linux内核编译选项,并重新编译:

    image.png

    修改前后可以通过如下命令观察TLB的命中率($PID为进程ID):

    perf stat -p $PID -d -d -d

    输出结果包含如下信息,其中1.21%和0.59%分别表示数据的miss率和指令的miss率。

    1,090,788,717      dTLB-loads                #  520.592 M/sec
    13,213,603      dTLB-load-misses          #    1.21% of all dTLB cache hits
    669,485,765      iTLB-loads                #  319.520 M/sec
    3,979,246      iTLB-load-misses          #    0.59% of all iTLB cache hits

                                    步骤 1      执行make menuconfig。

                                    步骤 2      选择PAGESIZE大小为64K。

    Kernel Features-->Page size(64KB)

                                    步骤 3      编译和安装内核。

    参考https://bbs.huaweicloud.com/forum/thread-24362-1-1.html

    ----结束

    1.3.5 调整线程并发数

    原理

    程序从单线程变为多线程时,CPU和内存资源得到充分利用,性能得到提升。但是系统的性能并不会随着线程数的增长而线性提升,因为随着线程数量的增加,线程之间的调度、上下文切换、关键资源和锁的竞争也会带来很大开销。当资源的争抢比较严重时,甚至会导致性能明显降。下面数据为某业务场景下,不同并发线程数下的TPS,可以看到并发线程数达到128后,性能达到高峰,随后开始下降。我们需要针对不同的业务模型和使用场景做多组测试,找到适合本业务场景的最佳并发线程数。

    修改方式

    不同的软件有不同的配置,需要根据代码实现来修改,这里举例几个常用开源软件的修改方法:

    • MySql可以通过innodb_thread_concurrency设置工作线程的最大并发数。

    • Nginx可以通过worker_processes参数设置并发的进程个数。

    作者:莱德汪汪队

  • 相关阅读:
    记录。短信网关.
    TP 笔记~
    FUCK IE FLASH(inline hook)
    API HOOK(MessageBoxA)
    inline hook MessageBox(2)
    c#线程中使用 dataset
    匈牙利算法解决二分图最大匹配
    C#:Array类的排序
    C#:属性
    C#:结构
  • 原文地址:https://www.cnblogs.com/2020-zhy-jzoj/p/13165206.html
Copyright © 2011-2022 走看看