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机制被关闭,需要打开。修改方法如下:

修改前后,可以通过如下命令观察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内核编译选项,并重新编译:

修改前后可以通过如下命令观察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参数设置并发的进程个数。

作者:莱德汪汪队

鲲鹏性能优化十板斧(二)——CPU与内存子系统性能调优的更多相关文章

  1. 鲲鹏性能优化十板斧——鲲鹏处理器NUMA简介与性能调优五步法

    TaiShan特战队六月底成立,至今百日有余,恰逢1024程序员节,遂整理此文,献礼致敬!希望能为广大在鲲鹏处理器上开发软件.性能调优的程序员们,提供一点帮助.从今天开始,将陆续推出性能调优专题文章. ...

  2. 鲲鹏性能优化十板斧之前言 | 鲲鹏处理器NUMA简介与性能调优五步法

    鲲鹏处理器NUMA简介 随着现代社会信息化.智能化的飞速发展,越来越多的设备接入互联网.物联网.车联网,从而催生了庞大的计算需求.但是功耗墙问题以功耗和冷却两大限制极大的影响了单核算力的发展.为了满足 ...

  3. Android性能优化典范(二)

    Google前几天刚发布了Android性能优化典范第2季的课程,一共20个短视频,包括的内容大致有:电量优化,网络优化,Wear上如何做优化,使用对象池来提高效率,LRU Cache,Bitmap的 ...

  4. 【性能优化】404- 从 12.67s到1.06s 性能优化实战

    作者:jerryOnlyZRJ 来源:https://juejin.im/post/5b6fa8c86fb9a0099910ac91 本文是对之前同名文章的修正,将所有webpack3的内容更新为we ...

  5. CentOS7安装CDH 第十二章:YARN的资源调优

    相关文章链接 CentOS7安装CDH 第一章:CentOS7系统安装 CentOS7安装CDH 第二章:CentOS7各个软件安装和启动 CentOS7安装CDH 第三章:CDH中的问题和解决方法 ...

  6. Java程序性能优化读书笔记(一):Java性能调优概述

    程序性能的主要表现点: 执行速度:程序的反映是否迅速,响应时间是否足够短 内存分配:内存分配是否合理,是否过多地消耗内存或者存在内存泄漏 启动时间:程序从运行到可以正常处理业务需要花费多少时间 负载承 ...

  7. JVM性能优化系列-(2) 垃圾收集器与内存分配策略

    2. 垃圾收集器与内存分配策略 垃圾收集(Garbage Collection, GC)是JVM实现里非常重要的一环,JVM成熟的内存动态分配与回收技术使Java(当然还有其他运行在JVM上的语言,如 ...

  8. 优化.NET 应用程序 CPU 和内存的11 个实践

    https://michaelscodingspot.com/cpu-bound-memory-bound/ 优化.NET 应用程序 CPU 和内存的11 个实践 凡事都有其限度,对吧?汽车只能开这么 ...

  9. CPU 架构SMP/NUMA,调优

    CPU 架构SMP/NUMA,调优 SMP:全称是"对称多处理"(Symmetrical Multi-Processing)技术 . 是指在一个计算机上汇集了一组处理器(多CPU) ...

随机推荐

  1. [考试反思]1024csp-s模拟测试86:消耗

    %%%两个没素质的和一个萌两小时AK 最近貌似总是可以比较快速的拿下T1,然后T2打到考试结束... T1是套路题没什么好说的. T2是一个比较蠢的博弈题,我花了很长时间干各种乱七八糟的事 什么打表啊 ...

  2. P4873 [USACO14DEC] Cow Jog_Gold 牛慢跑(乱搞?二分?)

    (话说最近写的这类题不少啊...) 化简:给定数轴上一系列点,向正方向移动,点不能撞在一起,如果碰到一起就需要放到另外一行,求要多少行才能满足所有点不相撞的条件. (被标签误解,老是想到二分答案... ...

  3. 8.5 NOIP 模拟测试 13

    今天的考试说实话T1很简单没A,我是傻X.T2T3难得一批,但是暴力的分还是拿了! 总结一下就是:骗分过样例,暴力出奇迹!只要瞎搞就行了! 话说现在终于不像之前那么傻了,终于知道打暴力了,因为之前暴力 ...

  4. 如何把链表以k个结点为一组进行翻转

    [MT笔试题] 题目描述: K 链表翻转是指把每K个相邻的结点看成一组进行翻转,如果剩余结点不足 K 个,则保持不变.假设给定链表 1 -> 2 -> 3 -> 4 -> 5 ...

  5. php nginx反向代理获取真实ip的教程

    php nginx反向代理获取真实ip的教程 <pre> location /getip { proxy_pass http://newmiracle.cn/ip.php; } proxy ...

  6. 深入理解java多态没有烤山药的存在,java就不香了吗?

    目录 1. 从吃烤山药重新认识多态 2. 多态前提条件[重点] 3. 多态的体现 4. 多态动态绑定与静态绑定 5. 多态特性的虚方法(virtual) 7. 向上转型 8. 向下转型 9. 向上向下 ...

  7. Uber Go 语言编码规范

    Uber Go 语言编码规范 Uber 是一家美国硅谷的科技公司,也是 Go 语言的早期 adopter.其开源了很多 golang 项目,诸如被 Gopher 圈熟知的 zap.jaeger 等.2 ...

  8. 201871010114-李岩松《面向对象程序设计(java)》第二周学习总结

    项目 内容 这个作业属于哪个课程 https://www.cnblogs.com/nwnu-daizh/ 这个作业的要求在哪里 https://www.cnblogs.com/nwnu-daizh/p ...

  9. thinkphp分页样式css代码

    <style type="text/css"> .Pagination a:hover,.current{background-color: #f54281;borde ...

  10. C++中对C的扩展学习新增语法——动态内存管理

    1.C语言动态内存管理的缺点: 1.malloc对象的大小需要自己计算. 2.需要手动转换指针类型. 3.C++的对象不适合使用malloc和free. 2.C++中new/delete基本使用: 3 ...