CPU性能篇:套路篇:CPU问题排查思路及优化思路
倪朋飞 《Linux 性能优化实战》
11 | 套路篇:如何迅速分析出系统CPU的瓶颈在哪里?
12 | 套路篇:CPU 性能优化的几个思路
13 | 答疑(一):无法模拟出 RES 中断的问题,怎么办?
14 | 答疑(二):如何用perf工具分析Java程序?
CPU 性能指标

CPU 使用率;平均负载(Load Average);进程上下文切换;CPU 缓存的命中率 ================================================================================================== CPU 使用率 CPU 使用率描述了非空闲时间占总 CPU 时间的百分比,根据 CPU 上运行任务的不同,又被分为用户 CPU、系统 CPU、等待 I/O CPU、软中断和硬中断等。 1.用户 CPU 使用率,包括用户态 CPU 使用率(user)和低优先级用户态 CPU 使用率(nice),表示 CPU 在用户态运行的时间百分比。用户 CPU 使用率高,通常说明有应用程序比较繁忙。 2.系统 CPU 使用率,表示 CPU 在内核态运行的时间百分比(不包括中断)。系统 CPU 使用率高,说明内核比较繁忙。 3.等待 I/O 的 CPU 使用率,通常也称为 iowait,表示等待 I/O 的时间百分比。iowait 高,通常说明系统与硬件设备的 I/O 交互时间比较长。 4.软中断和硬中断的 CPU 使用率,分别表示内核调用软中断处理程序、硬中断处理程序的时间百分比。它们的使用率高,通常说明系统发生了大量的中断。 5.在虚拟化环境中会用到的窃取 CPU 使用率(steal)和客户 CPU 使用率(guest),分别表示被其他虚拟机占用的 CPU 时间百分比,和运行客户虚拟机的 CPU 时间百分比。 --------------------------------------------------------------------------------------------------- 平均负载(Load Average) 是系统的平均活跃进程数。它反应了系统的整体负载情况,主要包括三个数值,分别指过去 1 分钟、过去 5 分钟和过去 15 分钟的平均负载。 理想情况下,平均负载等于逻辑 CPU 个数,这表示每个 CPU 都恰好被充分利用。如果平均负载大于逻辑 CPU 个数,就表示负载比较重了。 --------------------------------------------------------------------------------------------------- 进程上下文切换,包括: 1.无法获取资源而导致的自愿上下文切换; 2.被系统强制调度导致的非自愿上下文切换。 上下文切换,本身是保证 Linux 正常运行的一项核心功能。 但过多的上下文切换,会将原本运行进程的 CPU 时间,消耗在寄存器、内核栈以及虚拟内存等数据的保存和恢复上,缩短进程真正运行的时间,成为性能瓶颈。 --------------------------------------------------------------------------------------------------- CPU 缓存的命中率 CPU 缓存的速度介于 CPU 和内存之间,缓存的是热点的内存数据。根据不断增长的热点数据,这些缓存按照大小不同分为 L1、L2、L3 等三级缓存,其中 L1 和 L2 常用在单核中, L3 则用在多核中。 从 L1 到 L3,三级缓存的大小依次增大,相应的,性能依次降低(当然比内存还是好得多)。而它们的命中率,衡量的是 CPU 缓存的复用情况,命中率越高,则表示性能越好。

案例排查思路总结:平均负载的案例、上下文切换的案例、进程 CPU 使用率升高的案例、系统的 CPU 使用率升高的案例、不可中断进程和僵尸进程的案例、软中断的案例 ========================================================================================================= 平均负载的案例 我们先用 uptime, 查看了系统的平均负载; 而在平均负载升高后,又用 mpstat 和 pidstat ,分别观察了每个 CPU 和每个进程 CPU 的使用情况,进而找出了导致平均负载升高的进程,也就是我们的压测工具 stress。 1.双核CPU环境中,平均负载接近1;mpstat/top发现单核的CPU使用率一直很高,另一核一直空闲;某进程的CPU使用率很高; 说明某个高负荷进程一直跑在一颗CPU上;pidstat命令查看进程的用户CPU、系统CPU等数据 2.双核CPU环境中,top发现平均负载接近1;单核idle较低(7%),sys 20%+,iowait 70+; 说明某个高负荷进程一直跑在一颗CPU上;pidstat命令查看进程的用户CPU、系统CPU等数据,锁定进程 上述2个案例平均负载在1左右是因为某个进程一直处于running状态导致的;平均负载是单位时间内的活跃进程数,但它实际上是活跃进程数的指数衰减平均值。 3.双核CPU环境中,平均负载达到了7+,说明了多个任务在竞争CPU top命令的running任务数验证了这一点;通过top/pidstat的各个进程CPU数据,锁定了哪些进程正在竞争CPU ------------------------------------------------------------------------------------------------------------ 上下文切换的案例。 我们先用 vmstat ,查看了系统的上下文切换次数和中断次数; 然后通过 pidstat ,观察了进程的自愿上下文切换和非自愿上下文切换情况; 最后通过 pidstat ,观察了线程的上下文切换情况,找出了上下文切换次数增多的根源,也就是我们的基准测试工具 sysbench。 4.双核cpu环境中,top发现某个进程的cpu使用率达到194%,而平均负载却达到了7;系统CPU70%+,用户CPU20%+;running进程树一直也不多;所以猜测可能是多线程导致的CPU使用率高,平均负载高 vmstat命令的r一直在7左右浮动;top的running却一直是1;(说明vmstat是统计到线程,而top统计的是进程);同时vmstat可以看到硬中断和上下文切换的数据维持在高位 pidstat -wt验证了确实是多线程导致的高上下文切换 cat /proc/interrupts发现重调度中断(RES)变化最快,这个中断类型表示,唤醒空闲状态的 CPU 来调度新的任务运行。 top、pidstat默认显示的是进程的指标;vmstat则显示线程的指标 ------------------------------------------------------------------------------------------------------------ 进程 CPU 使用率升高的案例。 我们先用 top ,查看了系统和进程的 CPU 使用情况,发现 CPU 使用率升高的进程是 php-fpm; 再用 perf top ,观察 php-fpm 的调用链,最终找出 CPU 升高的根源,也就是库函数 sqrt() 。 5.单核CPU环境,在client使用ab命令对server端进行压测 top命令显示running数据6,用户CPU99%+,而5个同名进程的CPU综合使用率正好99%+ 使用perf分析该进程,找到资源消耗高的函数,查看源码进行优化 ------------------------------------------------------------------------------------------------------------ 系统的 CPU 使用率升高的案例。 我们先用 top 观察到了系统 CPU 升高,但通过 top 和 pidstat ,却找不出高 CPU 使用率的进程。 于是,我们重新审视 top 的输出,又从 CPU 使用率不高但处于 Running 状态的进程入手,找出了可疑之处,最终通过 perf record 和 perf report ,发现原来是短时进程在捣鬼。 另外,对于短时进程,我还介绍了一个专门的工具 execsnoop,它可以实时监控进程调用的外部命令。 5.双核CPU环境,在client使用ab命令对server端进行压测, top命令显示2颗CPU的用户CPU均60%+,系统CPU均23%+,idle很少;running的进程一直在8左右变化 但是几个进程的CPU使用率相加,却远远达不到90%+的使用率; 其实还是漏了running进程数量和CPU高的进程树对应不起来,根本原因在于短时进程造成的;通过排序,发现几个running进程,ps查看该进程却无该进程 多次使用pstree命令搜索该短时应用,发现了一些蛛丝马迹。。。 其实用execsnoop监视短时进程,效果很好。。 ------------------------------------------------------------------------------------------------------------ 不可中断进程和僵尸进程的案例。 我们先用 top 观察到了 iowait 升高的问题,并发现了大量的不可中断进程和僵尸进程; 接着我们用 dstat 发现是这是由磁盘读导致的,于是又通过 pidstat 找出了相关的进程。 但我们用 strace 查看进程系统调用却失败了,最终还是用 perf 分析进程调用链,才发现根源在于磁盘直接 I/O 。 6.双核CPU环境,top命令发现僵尸进程在不停增多;iowait持续维持在高位 僵尸进程问题相对比较简单,使用pstree -aps $pid确认父进程,然后去应用内查看源码 iowait维持在高位,使用dstat命令查看io数据,然后用pidstat -d锁定高io的应用;使用perf命令分析该应用 ------------------------------------------------------------------------------------------------------------ 软中断的案例。 我们通过 top 观察到,系统的软中断 CPU 使用率升高; 接着查看 /proc/softirqs, 找到了几种变化速率较快的软中断; 然后通过 sar 命令,发现是网络小包的问题, 最后再用 tcpdump ,找出网络帧的类型和来源,确定是一个 SYN FLOOD 攻击导致的。 7.单核CPU环境,top命令发现软中断很高,且cpu使用率最高的是ksoftirqd/0进程; /proc/softirqs查看软中断类型,发现是NET_RX(网络接收) 使用sar -n DEV查看网络流量的历史发送情况 最后用dumptcp命令锁定原因为sys攻击

tips: pidstat中的%wait跟 top中的iowait%对比 =================================================================== tips: pidstat 中的 %wait 跟 top 中的 iowait% (缩写为 wa)对比,其实这是没有意义的,因为它们是完全不相关的两个指标。 pidstat 中, %wait 表示进程等待 CPU 的时间百分比。 top 中 ,iowait% 则表示等待 I/O 的 CPU 时间百分比。 等待 CPU 的进程已经在 CPU 的就绪队列中,处于运行状态;R状态 而等待 I/O 的进程则处于不可中断状态。D状态

在执行 vmstat 时,第一行数据跟其他行相比较,数值相差特别大。 运行 man vmstat 命令,你可以在手册中发现下面这句话: The first report produced gives averages since the last reboot. Additional reports give information on a sam‐ pling period of length delay. The process and memory reports are instantaneous in either case. 也就是说,第一行数据是系统启动以来的平均值,其他行才是你在运行 vmstat 命令时,设置的间隔时间的平均值。另外,进程和内存的报告内容都是即时数值。
性能工具
第一个维度,从 CPU 的性能指标出发。也就是说,当你要查看某个性能指标时,要清楚知道哪些工具可以做到。
第二个维度,从工具出发。也就是当你已经安装了某个工具后,要知道这个工具能提供哪些指标。

如何迅速分析 CPU 的性能瓶颈;几个例子 ==================================================================== 如何迅速分析 CPU 的性能瓶颈 通常会先运行几个支持指标较多的工具,如 top、vmstat 和 pidstat ;这时为了缩小排查范围。 通过这张图你可以发现,这三个命令,几乎包含了所有重要的 CPU 性能指标,比如: 从 top 的输出可以得到各种 CPU 使用率以及僵尸进程和平均负载等信息。 从 vmstat 的输出可以得到上下文切换次数、中断次数、运行状态和不可中断状态的进程数。 从 pidstat 的输出可以得到进程的用户 CPU 使用率、系统 CPU 使用率、以及自愿上下文切换和非自愿上下文切换情况。 ---------------------------------------------------------------------------- 几个例子: 第一个例子,pidstat 输出的进程用户 CPU 使用率升高,会导致 top 输出的用户 CPU 使用率升高。 所以,当发现 top 输出的用户 CPU 使用率有问题时,可以跟 pidstat 的输出做对比,观察是否是某个进程导致的问题。 而找出导致性能问题的进程后,就要用进程分析工具来分析进程的行为,比如使用 strace 分析系统调用情况,以及使用 perf 分析调用链中各级函数的执行情况。 第二个例子,top 输出的平均负载升高,可以跟 vmstat 输出的运行状态和不可中断状态的进程数做对比,观察是哪种进程导致的负载升高。 如果是不可中断进程数增多了,那么就需要做 I/O 的分析,也就是用 dstat 或 sar 等工具,进一步分析 I/O 的情况。 如果是运行状态进程数增多了,那就需要回到 top 和 pidstat,找出这些处于运行状态的到底是什么进程,然后再用进程分析工具,做进一步分析。 最后一个例子,当发现 top 输出的软中断 CPU 使用率升高时,可以查看 /proc/softirqs 文件中各种类型软中断的变化情况,确定到底是哪种软中断出的问题。 比如,发现是网络接收中断导致的问题,那就可以继续用网络分析工具 sar 和 tcpdump 来分析。
CPU优化

优化问题:怎么评估性能优化的效果?多个性能问题同时存在,要怎么选择?有多种优化方法时,要如何选择? =========================================================================================================== 怎么评估性能优化的效果? 为了评估这个效果,我们需要对系统的性能指标进行量化,并且要分别测试出优化前、后的性能指标,用前后指标的变化来对比呈现效果。我把这个方法叫做性能评估“三步走”。 1.确定性能的量化指标。 性能的量化指标有很多,比如 CPU 使用率、应用程序的吞吐量、客户端请求的延迟等,都可以评估性能。 建议是不要局限在单一维度的指标上,你至少要从应用程序和系统资源这两个维度,分别选择不同的指标。比如,以 Web 应用为例: a.应用程序的维度,我们可以用吞吐量和请求延迟来评估应用程序的性能。 b.系统资源的维度,我们可以用 CPU 使用率来评估系统的 CPU 使用情况。 之所以从这两个不同维度选择指标,主要是因为应用程序和系统资源这两者间相辅相成的关系。 a.好的应用程序是性能优化的最终目的和结果,系统优化总是为应用程序服务的。所以,必须要使用应用程序的指标,来评估性能优化的整体效果。 b.系统资源的使用情况是影响应用程序性能的根源。所以,需要用系统资源的指标,来观察和分析瓶颈的来源。 2.测试优化前的性能指标。 3.测试优化后的性能指标。 这两个步骤,主要是为了对比优化前后的性能,更直观地呈现效果。 ------------------------------------------------------------------------------------------------------------ 多个性能问题同时存在,要怎么选择? “二八原则”,也就是说 80% 的问题都是由 20% 的代码导致的。只要找出这 20% 的位置,你就可以优化 80% 的性能。 所以,并不是所有的性能问题都值得优化。 建议动手优化之前先动脑,先把所有这些性能问题给分析一遍,找出最重要的、可以最大程度提升性能的问题,从它开始优化。 这样的好处是,不仅性能提升的收益最大,而且很可能其他问题都不用优化,就已经满足了性能要求。 推荐两个可以简化这个过程的方法。 第一,如果发现是系统资源达到了瓶颈, 比如 CPU 使用率达到了 100%,那么首先优化的一定是系统资源使用问题。完成系统资源瓶颈的优化后,我们才要考虑其他问题。 第二,针对不同类型的指标,首先去优化那些由瓶颈导致的,性能指标变化幅度最大的问题。 比如产生瓶颈后,用户 CPU 使用率升高了 10%,而系统 CPU 使用率却升高了 50%,这个时候就应该首先优化系统 CPU 的使用。 ------------------------------------------------------------------------------------------------------------ 有多种优化方法时,要如何选择? 一般情况下,我们当然想选能最大提升性能的方法,这其实也是性能优化的目标。 但要注意,现实情况要考虑的因素却没那么简单。最直观来说,性能优化并非没有成本。 性能优化通常会带来复杂度的提升,降低程序的可维护性,还可能在优化一个指标时,引发其他指标的异常。也就是说,很可能你优化了一个指标,另一个指标的性能却变差了。 所以,在考虑选哪个性能优化方法时,你要综合多方面的因素。 切记,不要想着“一步登天”,试图一次性解决所有问题;也不要只会“拿来主义”,把其他应用的优化方法原封不动拿来用,却不经过任何思考和分析。

应用程序优化;系统优化;避免过早优化 ====================================================================================================== 应用程序优化 应用程序的性能优化也包括很多种方法,我在这里列出了最常见的几种 1.编译器优化:很多编译器都会提供优化选项,适当开启它们,在编译阶段你就可以获得编译器的帮助,来提升性能。比如, gcc 就提供了优化选项 -O2,开启后会自动对应用程序的代码进行优化。 2.算法优化:使用复杂度更低的算法,可以显著加快处理速度。比如,在数据比较大的情况下,可以用 O(nlogn) 的排序算法(如快排、归并排序等),代替 O(n^2) 的排序算法(如冒泡、插入排序等)。 3.异步处理:使用异步处理,可以避免程序因为等待某个资源而一直阻塞,从而提升程序的并发处理能力。比如,把轮询替换为事件通知,就可以避免轮询耗费 CPU 的问题。 4.多线程代替多进程:前面讲过,相对于进程的上下文切换,线程的上下文切换并不切换进程地址空间,因此可以降低上下文切换的成本。 5.善用缓存:经常访问的数据或者计算过程中的步骤,可以放到内存中缓存起来,这样在下次用时就能直接从内存中获取,加快程序的处理速度。 ------------------------------------------------------------------------------------------------------ 系统优化 从系统的角度来说,优化 CPU 的运行, 一方面要充分利用 CPU 缓存的本地性,加速缓存访问; 另一方面,就是要控制进程的 CPU 使用情况,减少进程间的相互影响。 系统层面的 CPU 优化方法也有不少,这里我同样列举了最常见的一些方法,方便你记忆和使用。 1.CPU 绑定:把进程绑定到一个或者多个 CPU 上,可以提高 CPU 缓存的命中率,减少跨 CPU 调度带来的上下文切换问题。 2.CPU 独占:跟 CPU 绑定类似,进一步将 CPU 分组,并通过 CPU 亲和性机制为其分配进程。这样,这些 CPU 就由指定的进程独占,换句话说,不允许其他进程再来使用这些 CPU。 3.优先级调整:使用 nice 调整进程的优先级,正值调低优先级,负值调高优先级。优先级的数值含义前面我们提到过,忘了的话及时复习一下。在这里,适当降低非核心应用的优先级,增高核心应用的优先级,可以确保核心应用得到优先处理。 4.为进程设置资源限制:使用 Linux cgroups 来设置进程的 CPU 使用上限,可以防止由于某个应用自身的问题,而耗尽系统资源。 5.NUMA(Non-Uniform Memory Access)优化:支持 NUMA 的处理器会被划分为多个 node,每个 node 都有自己的本地内存空间。NUMA 优化,其实就是让 CPU 尽可能只访问本地内存。 6.中断负载均衡:无论是软中断还是硬中断,它们的中断处理程序都可能会耗费大量的 CPU。开启 irqbalance 服务或者配置 smp_affinity,就可以把中断处理过程自动负载均衡到多个 CPU 上。 ------------------------------------------------------------------------------------------------------ 避免过早优化 很多人即使没发现性能瓶颈,也会忍不住把各种各样的优化方法带到实际的开发中。 “过早优化是万恶之源” 因为,一方面,优化会带来复杂性的提升,降低可维护性; 另一方面,需求不是一成不变的。针对当前情况进行的优化,很可能并不适应快速变化的新需求。这样,在新需求出现时,这些复杂的优化,反而可能阻碍新功能的开发。
13 | 答疑(一):无法模拟出 RES 中断的问题,怎么办?
14 | 答疑(二):如何用perf工具分析Java程序?
这2章是针对前面课程的一些答疑,未总结!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!