一、CPU 使用率
为了维护 CPU 时间,Linux 通过事先定义的节拍率(内核中表示为 HZ),触发时间中断,并使用全局变量 Jiffies 记录了开机以来的节拍数。每发生一次时间中断,Jiffies 的值就加 1。节拍率 HZ 是内核的可配选项,可以设置为 100、250、1000 等。不同的系统可能设置不同数值,你可以通过查询 /boot/config 内核选项来查看它的配置值。比如在我的系统中,节拍率设置成了 250,也就是每秒钟触发 250 次时间中断
二、CPU 使用率过高怎么办?
1、perf top
第一种常见用法是 perf top,类似于 top,它能够实时显示占用 CPU 时钟最多的函数或者指令,因此可以用来查找热点函数,使用界面如下所示:
比如上图CPU时钟事件总数为3203009455个,而perf工具采集了14K个时钟事件。们可以看到,占用 CPU 时钟最多的是 perf 工具自身,不过它的比例也只有 4.15%,说明系统并没有 CPU 性能问题。
2、perf record 和 perf report
perf top 虽然实时展示了系统的性能信息,但它的缺点是并不保存数据,也就无法用于离线或者后续的分析。而 perf record 则提供了保存数据的功能,保存后的数据,需要你用 perf report 解析展示。
三、案例分析
预先安装 docker、sysstat、perf、ab 等工具,如 apt install docker.io sysstat linux-tools-common apache2-utils
首先,在第一个终端执行下面的命令来运行 Nginx 和 PHP 应用:
$ docker run --name nginx -p 10000:80 -itd feisky/nginx $ docker run --name phpfpm -itd --network container:nginx This is ApacheBench, Version 2.3 <$Revision: 1706008 $> Copyright 1996 Adam Twiss, Zeus Technology Ltd .Requests per second: 11.63[#/sec] (mean) Time per request: 859.942 [ms] (mean)...
从 ab 的输出结果我们可以看到,Nginx 能承受的每秒平均请求数只有 11.63。你一定在吐槽,这也太差了吧。那到底是哪里出了问题呢?我们用 top 和 pidstat 再来观察下。
这次,我们在第二个终端,将测试的请求总数增加到 10000。这样当你在第一个终端使用性能分析工具时, Nginx 的压力还是继续。继续在第二个终端,运行 ab 命令:
ab -c 10 -n 10000 http://10.240.0.5:10000/
接着,回到第一个终端运行 top 命令,并按下数字 1 ,切换到每个 CPU 的使用率:
top
这里可以看到,系统中有几个 php-fpm 进程的 CPU 使用率加起来接近 200%;而每个 CPU 的用户使用率(us)也已经超过了 98%,接近饱和。这样,我们就可以确认,正是用户空间的 php-fpm 进程,导致 CPU 使用率骤升。那再往下走,怎么知道是 php-fpm 的哪个函数导致了 CPU 使用率升高呢?我们来用 perf 分析一下。在第一个终端运行下面的 perf 命令:
# -g开启调用关系分析,-p指定php-fpm的进程号21515 $ perf top -g -p 21515
方向键切换到 php-fpm,再按下回车键展开 php-fpm 的调用关系,你会发现,调用关系最终到了 sqrt 和 add_function。看来,我们需要从这两个函数入手了。
# 停止原来的应用 $ docker rm -f nginx phpfpm # 运行优化后的应用 $ docker run --name nginx -p 10000:80 -itd feisky/nginx:cpu-fix $ docker run --name phpfpm -itd --network container:nginx feisky/php-fpm:cpu-fix
接着,到第二个终端来验证一下修复后的效果。首先 Ctrl+C 停止之前的 ab 命令后,再运行下面的命令:
ab -c 10 -n 10000 http://10.240.0.5:10000/
在每秒的平均请求数,已经从原来的 11 变成了 223