安徽公司招聘网站,连云港做网站制作首选公司,哪个网站可以学做包包,娱乐网站设计SEO文章目录 一、评价 CPU 的指标1.1 CPU 使用率1.2 平均负载#xff08;Load Average#xff09;1.3 上下文切换1.4 CPU 缓存命中率 二、性能工具2.1 维度#xff1a;从 CPU 性能指标出发#xff0c;即当你查看某性能指标时#xff0c;要清除知道哪些工具可以做到2.2 维度Load Average1.3 上下文切换1.4 CPU 缓存命中率 二、性能工具2.1 维度从 CPU 性能指标出发即当你查看某性能指标时要清除知道哪些工具可以做到2.2 维度从工具出发即当你已经安装了某个工具后要知道这个工具能提供哪些指标 三、如何迅速分析 CPU 的性能瓶颈四、性能优化方法论4.1 评估性能优化效果4.2 多个性能问题同时存在要怎么选择4.3 有多种优化方法时要如何选择? 五、CPU 优化5.1 应用程序优化5.2 系统优化5.3 千万避免过早优化 一、评价 CPU 的指标
1.1 CPU 使用率
CPU 使用率描述了非空闲时间占总 CPU 时间的百分比根据 CPU 上运行任务的不同又被分为用户 CPU、系统 CPU、等待 I/O CPU、软中断和硬中断等。
用户 CPU 使用率包括用户态 CPU 使用率user和低优先级用户态 CPU 使用率nice表示 CPU 在用户态运行的时间百分比。用户 CPU 使用率高通常说明有应用程序比较繁忙。系统 CPU 使用率表示 CPU 在内核态运行的时间百分比不包括中断。系统 CPU 使用率高说明内核比较繁忙。等待 I/O 的 CPU 使用率通常也称为 iowait表示等待 I/O 的时间百分比。iowait 高通常说明系统与硬件设备的 I/O 交互时间比较长。软中断和硬中断的 CPU 使用率分别表示内核调用软中断处理程序、硬中断处理程序的时间百分比。它们的使用率高通常说明系统发生了大量的中断。除了上面这些还有在虚拟化环境中会用到的窃取 CPU 使用率steal和客户 CPU 使用率guest分别表示被其他虚拟机占用的 CPU 时间百分比和运行客户虚拟机的 CPU 时间百分比。
1.2 平均负载Load Average
即系统的平均活跃进程数。它反应了系统的整体负载情况主要包括三个数值分别指过去 1 分钟、过去 5 分钟和过去 15 分钟的平均负载。
理想情况下平均负载等于逻辑 CPU 个数这表示每个 CPU 都恰好被充分利用。如果平均负载大于逻辑 CPU 个数就表示负载比较重了。
1.3 上下文切换
进程上下文切换包括
无法获取资源而导致的自愿上下文切换被系统强制调度导致的非自愿上下文切换。
上下文切换本身是保证 Linux 正常运行的一项核心功能。但过多的上下文切换会将原本运行进程的 CPU 时间消耗在寄存器、内核栈以及虚拟内存等数据的保存和恢复上缩短进程真正运行的时间成为性能瓶颈。
1.4 CPU 缓存命中率
由于 CPU 发展的速度远快于内存的发展CPU 的处理速度就比内存的访问速度快得多。这样CPU 在访问内存的时候免不了要等待内存的响应。为了协调这两者巨大的性能差距CPU 缓存通常是多级缓存就出现了。 就像上面这张图显示的CPU 缓存的速度介于 CPU 和内存之间缓存的是热点的内存数据。根据不断增长的热点数据这些缓存按照大小不同分为 L1、L2、L3 等三级缓存其中 L1 和 L2 常用在单核中 L3 则用在多核中。
从 L1 到 L3三级缓存的大小依次增大相应的性能依次降低当然比内存还是好得多。而它们的命中率衡量的是 CPU 缓存的复用情况命中率越高则表示性能越好。
总结如下图
二、性能工具
掌握了 CPU 的性能指标我们还需要知道怎样去获取这些指标也就是工具的使用。
你还记得前面案例都用了哪些工具吗这里我们也一起回顾一下 CPU 性能工具。
首先平均负载的案例。我们先用 uptime 查看了系统的平均负载而在平均负载升高后又用 mpstat 和 pidstat 分别观察了每个 CPU 和每个进程 CPU 的使用情况进而找出了导致平均负载升高的进程也就是我们的压测工具 stress。
第二个上下文切换的案例。我们先用 vmstat 查看了系统的上下文切换次数和中断次数然后通过 pidstat 观察了进程的自愿上下文切换和非自愿上下文切换情况最后通过 pidstat 观察了线程的上下文切换情况找出了上下文切换次数增多的根源也就是我们的基准测试工具 sysbench。
第三个进程 CPU 使用率升高的案例。我们先用 top 查看了系统和进程的 CPU 使用情况发现 CPU 使用率升高的进程是 php-fpm再用 perf top 观察 php-fpm 的调用链最终找出 CPU 升高的根源也就是库函数 sqrt() 。
第四个系统的 CPU 使用率升高的案例。我们先用 top 观察到了系统 CPU 升高但通过 top 和 pidstat 却找不出高 CPU 使用率的进程。于是我们重新审视 top 的输出又从 CPU 使用率不高但处于 Running 状态的进程入手找出了可疑之处最终通过 perf record 和 perf report 发现原来是短时进程在捣鬼。
另外对于短时进程我还介绍了一个专门的工具 execsnoop它可以实时监控进程调用的外部命令。
第五个不可中断进程和僵尸进程的案例。我们先用 top 观察到了 iowait 升高的问题并发现了大量的不可中断进程和僵尸进程接着我们用 dstat 发现是这是由磁盘读导致的于是又通过 pidstat 找出了相关的进程。但我们用 strace 查看进程系统调用却失败了最终还是用 perf 分析进程调用链才发现根源在于磁盘直接 I/O 。
最后一个软中断的案例。我们通过 top 观察到系统的软中断 CPU 使用率升高接着查看 /proc/softirqs 找到了几种变化速率较快的软中断然后通过 sar 命令发现是网络小包的问题最后再用 tcpdump 找出网络帧的类型和来源确定是一个 SYN FLOOD 攻击导致的。
到这里估计你已经晕了吧原来短短几个案例我们已经用过十几种 CPU 性能工具了而且每种工具的适用场景还不同呢这么多的工具要怎么区分呢在实际的性能分析中又该怎么选择呢
我的经验是从两个不同的维度来理解它们做到活学活用。
2.1 维度从 CPU 性能指标出发即当你查看某性能指标时要清除知道哪些工具可以做到
根据不同的性能指标对提供指标的性能工具进行分类和理解。这样在实际排查性能问题时你就可以清楚知道什么工具可以提供你想要的指标而不是毫无根据地挨个尝试撞运气。
其实我在前面的案例中已经多次用到了这个思路。比如用 top 发现了软中断 CPU 使用率高后下一步自然就想知道具体的软中断类型。那在哪里可以观察各类软中断的运行情况呢当然是 proc 文件系统中的 /proc/softirqs 这个文件。
紧接着比如说我们找到的软中断类型是网络接收那就要继续往网络接收方向思考。系统的网络接收情况是什么样的什么工具可以查到网络接收情况呢在我们案例中用的正是 dstat。
虽然你不需要把所有工具背下来但如果能理解每个指标对应的工具的特性一定更高效、更灵活地使用。这里我把提供 CPU 性能指标的工具做成了一个表格方便你梳理关系和理解记忆当然你也可以当成一个“指标工具”指南来使用。 2.2 维度从工具出发即当你已经安装了某个工具后要知道这个工具能提供哪些指标
这在实际环境特别是生产环境中也是非常重要的因为很多情况下你并没有权限安装新的工具包只能最大化地利用好系统中已经安装好的工具这就需要你对它们有足够的了解。
具体到每个工具的使用方法一般都支持丰富的配置选项。不过不用担心这些配置选项并不用背下来。你只要知道有哪些工具、以及这些工具的基本功能是什么就够了。真正要用到的时候 通过 man 命令查它们的使用手册就可以了。
同样的我也将这些常用工具汇总成了一个表格方便你区分和理解自然你也可以当成一个“工具指标”指南使用需要时查表即可。 三、如何迅速分析 CPU 的性能瓶颈
我相信到这一步你对 CPU 的性能指标已经非常熟悉也清楚每种性能指标分别能用什么工具来获取。
那是不是说每次碰到 CPU 的性能问题你都要把上面这些工具全跑一遍然后再把所有的 CPU 性能指标全分析一遍呢
你估计觉得这种简单查找的方式就像是在傻找。不过别笑话因为最早的时候我就是这么做的。把所有的指标都查出来再统一分析当然是可以的也很可能找到系统的潜在瓶颈。
但是这种方法的效率真的太低了耗时耗力不说在庞大的指标体系面前你一不小心可能就忽略了某个细节导致白干一场。我就吃过好多次这样的苦。
所以在实际生产环境中我们通常都希望尽可能快地定位系统的瓶颈然后尽可能快地优化性能也就是要又快又准地解决性能问题。
那有没有什么方法可以又快又准找出系统瓶颈呢答案是肯定的。
虽然 CPU 的性能指标比较多但要知道既然都是描述系统的 CPU 性能它们就不会是完全孤立的很多指标间都有一定的关联。想弄清楚性能指标的关联性就要通晓每种性能指标的工作原理。这也是为什么我在介绍每个性能指标时都要穿插讲解相关的系统原理希望你能记住这一点。
举个例子用户 CPU 使用率高我们应该去排查进程的用户态而不是内核态。因为用户 CPU 使用率反映的就是用户态的 CPU 使用情况而内核态的 CPU 使用情况只会反映到系统 CPU 使用率上。
你看有这样的基本认识我们就可以缩小排查的范围省时省力。
所以为了缩小排查范围我通常会先运行几个支持指标较多的工具如 top、vmstat 和 pidstat 。为什么是这三个工具呢仔细看看下面这张图你就清楚了。 这张图里我列出了 top、vmstat 和 pidstat 分别提供的重要的 CPU 指标并用虚线表示关联关系对应出了性能分析下一步的方向。
通过这张图你可以发现这三个命令几乎包含了所有重要的 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 来分析。
四、性能优化方法论
在我们历经千辛万苦通过各种性能分析方法终于找到引发性能问题的瓶颈后是不是立刻就要开始优化了呢别急动手之前你可以先看看下面这三个问题。
首先既然要做性能优化那要怎么判断它是不是有效呢特别是优化后到底能提升多少性能呢第二性能问题通常不是独立的如果有多个性能问题同时发生你应该先优化哪一个呢第三提升性能的方法并不是唯一的当有多种方法可以选择时你会选用哪一种呢是不是总选那个最大程度提升性能的方法就行了呢
如果你可以轻松回答这三个问题那么二话不说就可以开始优化。
比如在前面的不可中断进程案例中通过性能分析我们发现是因为一个进程的直接 I/O 导致了 iowait 高达 90%。那是不是用“直接 I/O 换成缓存 I/O”的方法就可以立即优化了呢
按照上面讲的你可以先自己思考下那三点。如果不能确定我们一起来看看。
第一个问题直接 I/O 换成缓存 I/O可以把 iowait 从 90% 降到接近 0性能提升很明显。第二个问题我们没有发现其他性能问题直接 I/O 是唯一的性能瓶颈所以不用挑选优化对象。第三个问题缓存 I/O 是我们目前用到的最简单的优化方法而且这样优化并不会影响应用的功能。
好的这三个问题很容易就能回答所以立即优化没有任何问题。
但是很多现实情况并不像我举的例子那么简单。性能评估可能有多重指标性能问题可能会多个同时发生而且优化某一个指标的性能可能又导致其他指标性能的下降。
那么面对这种复杂的情况我们该怎么办呢
接下来我们就来深入分析这三个问题。
4.1 评估性能优化效果
首先来看第一个问题怎么评估性能优化的效果。
我们解决性能问题的目的自然是想得到一个性能提升的效果。为了评估这个效果我们需要对系统的性能指标进行量化并且要分别测试出优化前、后的性能指标用前后指标的变化来对比呈现效果。我把这个方法叫做性能评估“三步走”。
确定性能的量化指标。测试优化前的性能指标。测试优化后的性能指标。 先看第一步性能的量化指标有很多比如 CPU 使用率、应用程序的吞吐量、客户端请求的延迟等都可以评估性能。那我们应该选择什么指标来评估呢
我的建议是不要局限在单一维度的指标上你至少要从应用程序和系统资源这两个维度分别选择不同的指标。比如以 Web 应用为例
应用程序的维度我们可以用吞吐量和请求延迟来评估应用程序的性能。系统资源的维度我们可以用 CPU 使用率来评估系统的 CPU 使用情况。
之所以从这两个不同维度选择指标主要是因为应用程序和系统资源这两者间相辅相成的关系。
好的应用程序是性能优化的最终目的和结果系统优化总是为应用程序服务的。所以必须要使用应用程序的指标来评估性能优化的整体效果。系统资源的使用情况是影响应用程序性能的根源。所以需要用系统资源的指标来观察和分析瓶颈的来源。
至于接下来的两个步骤主要是为了对比优化前后的性能更直观地呈现效果。如果你的第一步是从两个不同维度选择了多个指标那么在性能测试时你就需要获得这些指标的具体数值。
还是以刚刚的 Web 应用为例对应上面提到的几个指标我们可以选择 ab 等工具测试 Web 应用的并发请求数和响应延迟。而测试的同时还可以用 vmstat、pidstat 等性能工具观察系统和进程的 CPU 使用率。这样我们就同时获得了应用程序和系统资源这两个维度的指标数值。
不过在进行性能测试时有两个特别重要的地方你需要注意下。
第一要避免性能测试工具干扰应用程序的性能。通常对 Web 应用来说性能测试工具跟目标应用程序要在不同的机器上运行。 比如在之前的 Nginx 案例中我每次都会强调要用两台虚拟机其中一台运行 Nginx 服务而另一台运行模拟客户端的工具就是为了避免这个影响。 第二避免外部环境的变化影响性能指标的评估。这要求优化前、后的应用程序都运行在相同配置的机器上并且它们的外部依赖也要完全一致。
比如还是拿 Nginx 来说就可以运行在同一台机器上并用相同参数的客户端工具来进行性能测试。
4.2 多个性能问题同时存在要怎么选择
再来看第二个问题开篇词里我们就说过系统性能总是牵一发而动全身所以性能问题通常也不是独立存在的。那当多个性能问题同时发生的时候应该先去优化哪一个呢
在性能测试的领域流传很广的一个说法是“二八原则”也就是说 80% 的问题都是由 20% 的代码导致的。只要找出这 20% 的位置你就可以优化 80% 的性能。所以我想表达的是并不是所有的性能问题都值得优化。
我的建议是动手优化之前先动脑先把所有这些性能问题给分析一遍找出最重要的、可以最大程度提升性能的问题从它开始优化。这样的好处是不仅性能提升的收益最大而且很可能其他问题都不用优化就已经满足了性能要求。
那关键就在于怎么判断出哪个性能问题最重要。这其实还是我们性能分析要解决的核心问题只不过这里要分析的对象从原来的一个问题变成了多个问题思路其实还是一样的。
所以你依然可以用我前面讲过的方法挨个分析分别找出它们的瓶颈。分析完所有问题后再按照因果等关系排除掉有因果关联的性能问题。最后再对剩下的性能问题进行优化。
如果剩下的问题还是好几个你就得分别进行性能测试了。比较不同的优化效果后选择能明显提升性能的那个问题进行修复。这个过程通常会花费较多的时间这里我推荐两个可以简化这个过程的方法。
第一如果发现是系统资源达到了瓶颈比如 CPU 使用率达到了 100%那么首先优化的一定是系统资源使用问题。完成系统资源瓶颈的优化后我们才要考虑其他问题。
第二针对不同类型的指标首先去优化那些由瓶颈导致的性能指标变化幅度最大的问题。比如产生瓶颈后用户 CPU 使用率升高了 10%而系统 CPU 使用率却升高了 50%这个时候就应该首先优化系统 CPU 的使用。
4.3 有多种优化方法时要如何选择?
接着来看第三个问题当多种方法都可用时应该选择哪一种呢是不是最大提升性能的方法一定最好呢
一般情况下我们当然想选能最大提升性能的方法这其实也是性能优化的目标。
但要注意现实情况要考虑的因素却没那么简单。最直观来说性能优化并非没有成本。性能优化通常会带来复杂度的提升降低程序的可维护性还可能在优化一个指标时引发其他指标的异常。也就是说很可能你优化了一个指标另一个指标的性能却变差了。
一个很典型的例子是我将在网络部分讲到的 DPDKData Plane Development Kit。DPDK 是一种优化网络处理速度的方法它通过绕开内核网络协议栈的方法提升网络的处理能力。
不过它有一个很典型的要求就是要独占一个 CPU 以及一定数量的内存大页并且总是以 100% 的 CPU 使用率运行。所以如果你的 CPU 核数很少就有点得不偿失了。
所以在考虑选哪个性能优化方法时你要综合多方面的因素。切记不要想着“一步登天”试图一次性解决所有问题也不要只会“拿来主义”把其他应用的优化方法原封不动拿来用却不经过任何思考和分析。
五、CPU 优化
清楚了性能优化最基本的三个问题后我们接下来从应用程序和系统的角度分别来看看如何才能降低 CPU 使用率提高 CPU 的并行处理能力。
5.1 应用程序优化
首先从应用程序的角度来说降低 CPU 使用率的最好方法当然是排除所有不必要的工作只保留最核心的逻辑。比如减少循环的层次、减少递归、减少动态内存分配等等。
除此之外应用程序的性能优化也包括很多种方法我在这里列出了最常见的几种你可以记下来。
编译器优化很多编译器都会提供优化选项适当开启它们在编译阶段你就可以获得编译器的帮助来提升性能。比如 gcc 就提供了优化选项 -O2开启后会自动对应用程序的代码进行优化。算法优化使用复杂度更低的算法可以显著加快处理速度。比如在数据比较大的情况下可以用 O(nlogn) 的排序算法如快排、归并排序等代替 O(n^2) 的排序算法如冒泡、插入排序等。异步处理使用异步处理可以避免程序因为等待某个资源而一直阻塞从而提升程序的并发处理能力。比如把轮询替换为事件通知就可以避免轮询耗费 CPU 的问题。多线程代替多进程前面讲过相对于进程的上下文切换线程的上下文切换并不切换进程地址空间因此可以降低上下文切换的成本。善用缓存经常访问的数据或者计算过程中的步骤可以放到内存中缓存起来这样在下次用时就能直接从内存中获取加快程序的处理速度。
5.2 系统优化
从系统的角度来说优化 CPU 的运行一方面要充分利用 CPU 缓存的本地性加速缓存访问另一方面就是要控制进程的 CPU 使用情况减少进程间的相互影响。
具体来说系统层面的 CPU 优化方法也有不少这里我同样列举了最常见的一些方法方便你记忆和使用。
CPU 绑定把进程绑定到一个或者多个 CPU 上可以提高 CPU 缓存的命中率减少跨 CPU 调度带来的上下文切换问题。CPU 独占跟 CPU 绑定类似进一步将 CPU 分组并通过 CPU 亲和性机制为其分配进程。这样这些 CPU 就由指定的进程独占换句话说不允许其他进程再来使用这些 CPU。优先级调整使用 nice 调整进程的优先级正值调低优先级负值调高优先级。适当降低非核心应用的优先级增高核心应用的优先级可以确保核心应用得到优先处理。为进程设置资源限制使用 Linux cgroups 来设置进程的 CPU 使用上限可以防止由于某个应用自身的问题而耗尽系统资源。NUMANon-Uniform Memory Access优化支持 NUMA 的处理器会被划分为多个 node每个 node 都有自己的本地内存空间。NUMA 优化其实就是让 CPU 尽可能只访问本地内存。中断负载均衡无论是软中断还是硬中断它们的中断处理程序都可能会耗费大量的 CPU。开启 irqbalance 服务或者配置 smp_affinity就可以把中断处理过程自动负载均衡到多个 CPU 上。
5.3 千万避免过早优化
掌握上面这些优化方法后我估计很多人即使没发现性能瓶颈也会忍不住把各种各样的优化方法带到实际的开发中。
不过我想你一定听说过高德纳的这句名言 “过早优化是万恶之源”我也非常赞同这一点过早优化不可取。
因为一方面优化会带来复杂性的提升降低可维护性另一方面需求不是一成不变的。针对当前情况进行的优化很可能并不适应快速变化的新需求。这样在新需求出现时这些复杂的优化反而可能阻碍新功能的开发。
所以性能优化最好是逐步完善动态进行不追求一步到位而要首先保证能满足当前的性能要求。当发现性能不满足要求或者出现性能瓶颈时再根据性能评估的结果选择最重要的性能问题进行优化。
一定要忍住“把 CPU 性能优化到极致”的冲动因为 CPU 并不是唯一的性能因素。还有更多的性能问题比如内存、网络、I/O 甚至是架构设计的问题。
如果不做全方位的分析和测试只是单纯地把某个指标提升到极致并不一定能带来整体的收益。