# 【NO.617】Linux性能优化-CPU性能优化思路

## 1.CPU性能指标

**CPU使用率**

1.CPU使用率描述了非空闲时间占总CPU时间的百分比，根据CPU上运行任务的不同，又被分为用户CPU，系统CPU，等待I/O CPU，软中断和硬中断等

2.系统CPU使用率，表示CPU在内核态运行时间的百分比(不包括中断)，系统CPU使用率搞说明内核比较繁忙

3.等待/IO的CPU使用率，iowait，表示等待I/O的时间百分比，iowait高说明系统与硬件设备的I/O交互时间比较长

4.软中断和硬中断的CPU使用率，分别表示内核调用软中断处理程序，硬中断处理程序的时间百分比，他们的使用率高，通常说明系统发生了大量的中断

5.虚拟化中的窃取CPU使用率(steal)，表示被其他虚拟机占用的CPU时间百分比

6.客户CPU使用率(guest)，运行客户虚拟机的CPU时间百分比

**平均负载(load average)**

也就是系统平均活跃进程数，它反映了系统的整体负载情况，主要包括三个数值，分别指过去1分钟，过去5分钟，过去15分钟的平均负载

**上下文切换**

1.无法获取资源而导致的自愿上下文切换

2.被系统强制调度导致的非自愿上下文切换

上下文切换，本身是保证linux正常运行的一项核心功能，但过多的上下文切换，会将原本运行进程的CPU时间，消耗在寄存器，内核栈以及虚拟内存等数据的保存和恢复上，缩短进程真正运行的时间，成为性能瓶颈

**CPU缓存的命中率**

由于CPU发展的速度远快于内存的发展，CPU的处理速度也就比内存的访问速度快很多，这样CPU在访问内存的时候，免不了等待内存的响应，为了协调者两者的性能差距，CPU缓存(通常是多级缓存)就出现了

![img](https://pic3.zhimg.com/80/v2-348db0abb69fb4e17480b3af5b8f0a4a_720w.webp)

关于CPU性能分析的 指标筛选清单

![img](https://pic3.zhimg.com/80/v2-b2ce4109681c0c911419d3d233c2435a_720w.webp)

## 2.性能工具

把性能指标和性能工具联系起来

1.从CPU的性能指标出发，当需要查看某个性能指标时，要清朝哪些工具可以做到

要根据不同的性能指标，对提供指标的性能工具进行分类和理解，在实际派出性能问题时，就可以清楚知道，什么工具可以提供你想要的指标，而不是毫无根据的挨个尝试，

比如top发现了软中断CPU使用率高后，下一步就需要知道具体的软中断类型，/proc/softirqs

比如找到软中断类型是网络接收，那就继续往网络接收方向思考，系统网络接收情况是什么样，什么工具可以查看网络接收情况

根据指标查找工具

![img](https://pic1.zhimg.com/80/v2-2829656ca49dc431225becc896db29e0_720w.webp)

2.从工具出发，当安装了某个工具后，要知道这个攻击能提供哪些指标

在生产环境中，可能没有权限安装新的工具包，只能最大化利用好系统中已经安装好的工具，这就需要你对他们又足够的了解

具体到每个攻击的使用方法，一般都支持丰富的配置选项

![img](https://pic3.zhimg.com/80/v2-3b6ed43383a5c250143e52f4ef6080ee_720w.webp)

## 3.如何迅速的分析CPU性能瓶颈

实际生产环境中，我们都希望尽可能快的定位系统瓶颈，然后尽可能快的优化性能

虽然CPU性能指标很多，但他们并不是完全孤立的，很多指标间都有一定的关联，要弄清性能指标的关联性，就要知道每种性能指标的工作原理

可以通过 top，vmstat，pidstat 这三个工具来排查问题，因为这三个工具支持很多指标

![img](https://pic2.zhimg.com/80/v2-96a8691859ffac077f627068cfc80fa5_720w.webp)

top，vmstat，pidstat 分别提供了重要的CPU指标，并通过虚线表示关联关系

1.从top的输出可以得到各种CPU使用率以及僵尸进程和平均负载等信息

2.从vmstat的输出可以得到上下文切换次数，中断次数，运行状态和不可中断状态的进程数

3.从pidstat的输出可以得到进程用户CPU使用率，系统CPU使用率，自愿上下文切换和非自愿上下文切换情况

比如

1.top发现用户CPU使用率有问题，可以用pidstat接着分析是哪个进程导致的

2.top的平均负载比较高，可以跟vmstat的运行状态和不可中断状态进程数做对比，观察是哪种进程导致的负载升高

3.当top输出的软中断CPU使用率升高，可以查看/proc/softirqs中的各种类型软中断变化情况，确定是哪种软中断出的问题，比如发现网络接收中断导致的问题，可以继续用sar和tcpdump分析

## 4.性能优化方法论

1.要做性能优化，怎么判断它是不是有效？特别是优化之后，能提升多少性能？

2.性能问题通常不是独立的，如果有多个性能问题同时发生，应该先优化哪一个？

3.提升性能的方法并不是唯一的，当有多种方法可以选择时，选用哪一种？是不是总选能最大程度提升性能的方案？

比如前面例子中的一个进程使用直接I/O导致iowait很高，如果将直接I/O改成缓存I/O呢？对于上面的三问就是

1.直接I/O换成缓存I/O，可以把iowait从90%降低到接近0，性能提升很明显

2.没有发现其他性能问题，直接I/O是唯一的性能瓶颈，所以不用挑选优化对象

3.缓存I/O是目前用到的最简单的优化方法，而且这样优化并不会影响应用的功能

但实际情况中，性能评估可能有多重指标，性能问题可能会多个同时发生，而且优化某一个指标的性能，可能又会导致其他指标性能的下降

**评估性能优化的效果**

需要对系统的性能指标进行量化，并且要分别测试出优化前，优化后的性能指标，用前后指标的变化来对比呈现效果

1.确定性能的量化指标

2.测试优化前的性能指标

3.测试优化后的性能指标

对于第一点，性能的量化指标有很多，比如CPU使用率， 应用程序的吞吐量，客户端请求延迟等都可以评估性能指标，所以不要局限在单一围堵指标上，至少要从应用程序和系统资源两个维度，分别选择不同的指标，以Web应用为例子

应用程序维度，可以用 吞吐量和请求延迟 来评估应用程序的性能

系统资源维度，可以用 CPU使用率 来评估系统的CPU使用情况

**应用程序和系统资源这两者之间是相辅相成的**

好的应用程序是性能优化的最终目的和结果，系统欧化总是为应用程序服务的，所以必须要使用程序的指标，来评估性能优化的整体效果

系统资源的使用情况是影响应用程序性能的根源，需要用系统资源的指标，来观察和分析瓶颈的来源

**性能测试的时候需要注意**

1.避免性能测试工具干扰应用程序的性能

2.避免外部环境的变化影响性能指标的评估，这要求优化前，优化后的应用程序，都允许在相同配置的机器上，并且他们的外部依赖也要完全一致

**多个性能问同时存在时的选择**

根据二八原则，找出20%的位置，就可以优化80%的性能，所以并不是所有性能问题都值得优化

在优化之前应该把所有性能问题分析一遍，找出最重要的，可以最大程度提升性能的问题，从它开始优化。怎么判断哪个性能问题最重要，有一个简化的判断过程

1.如果发现系统资源达到了瓶颈，比如CPU使用率是100%，那么首先优化的一定是系统资源使用问题，

完成系统资源瓶颈的优化后，我们才要考虑其他问题

2.针对不同类型的指标，首先去优化那些由瓶颈导致的，性能指标变化幅度最大的问题，比如生产瓶颈

后用户CPU使用率升高了10%，而系统CPU使用率却升高了50%，这个时候就应该首先优化系统CPU使用

**多种优化方法时的选择**

理论上就应该选择提升性能最大的方法，但性能优化并非没有成本，性能优化会带来复杂度的提升，降低程序的可维护性，还可能在优化一个指标时，引发其他指标的异常

比如DPDK(Data Plane Development Kit)，DPDK是一种优化网络处理速度的方法，它绕开内核网络协议栈的方法，提升网络的处理能力，但他要求独占一个CPU一级一定数量的内存大页，并且总是以100%的CPU使用率运行，所以如果CPU核数很少就不行了

选择性能优化方法时，就要综合考虑，不能一步登天，试图解决所有问题

## 5.CPU优化

**应用程序优化**

从应用程序角度来说，降低CPU使用率的最好方法是派出所有不必要的工作，只保留最核心的逻辑，减少循环次数，减少递归，减少动态内存分配等，常见的优化如下

1.编译器优化，比如gcc -O2 选项，开启后会自动会应用程序的代码进行优化

2.算法优化，使用复杂度耕地的算法，可以加快处理速度，如O(nlongn)的排序算法

3.异步处理，避免程序因为等待某个资源而一直阻塞，从而提升程序的并发处理能力，比如把轮询改为

事件通知，就可以避免轮询消耗CPU的问题

4.多线程替代多进程，相对于进程的上下文切换，线程的上下文切换并不切换进程的地址空间，可以

降低上下文切换的成文

5.善用缓存，经常访问的数据或计算过程中的步骤，可以放到内存中缓存起来

**系统优化**

从系统的角度来说优化CPU的运行，一定要充分利用CPU缓存的本地性，加速缓存访问，另一方面要控制进程的CPU使用情况，减少进程间的相互影响

具体来说，有如下方法

1.CPU绑定，把进程绑定到一个或多个CPU上，可以提高CPU缓存的命中率，减少跨CPU调度带来的上下

文切换问题

2.CPU独占，跟CPU绑定类似，进一步将CPU分组，并通过CPU亲核性机制为其分配进程，这些CPU就由

指定的进程独占，不允许其他进程再来使用这些CPU

3.优先级调整，使用nice调整，正值调低优先级，负值调高优先级

4.位进程设置资源限制，使用cgroups来设置进程的CPU使用上线

5.NUMA(Non-Uniform Memory Access)优化，支持NUMA的处理器会被划分为多个node，每个node都有与

自己的本地内存空间，NUMA优化就是让CPU尽可能只访问本地内存

6.中断负载均衡，无论是软中断还是硬中断，他们的中断处理程序都可能会耗费大量的CPU，开启

irqbalance服务或者配置 smp_sffinity，就可以把中断处理过程自动负载均衡到多个CPU上

**避免过早优化**

高德纳的名言，过早优化是万恶之源

优化会带来复杂性的提升，降低可维护度，另外需求不是一成不变的，针对当前情况进行的优化，很可能并不适应快速变化的新需求，在新需求出现时，这些复杂的优化，反而可能阻碍新功能的开发

所以，性能优化最好是逐步完善，动态进行，不追求一步到位，而要首先能保证蛮族当前的性能要求，当发现性能不满足要求或者出现性能瓶颈时，再根据性能评估的结果，选择最中意的性能问题进行优化

原文地址：https://zhuanlan.zhihu.com/p/455928492

作者：linux