案例:某个应用的 CPU 使用率居然达到 100%,我该怎么办?

记录《Linux性能优化》课程实践过程。

环境准备

  • 两台虚拟机(Ubuntu 18.04)
  • 机器配置:2 CPU,8GB 内存
  • 预先安装 docker、sysstat、perf、ab 等工具,如 apt install docker.io sysstat linux-tools-common apache2-utils

操作和分析

其中一台用作 Web 服务器,来模拟性能问题;另一台用作 Web 服务器的客户端,来给 Web 服务增加压力请求。

打开两个终端,分别 SSH 登录到两台机器上,并安装上面提到的工具。

默认以 root 用户运行所有命令,先运行 sudo su root 命令切换到 root 用户。

由于 Nginx 和 PHP 的配置比较麻烦, 课程提供了两个Docker 镜像,这样只需要运行两个容器,就可以得到模拟环境。

运行docker容器应用

首先,在第一个终端执行下面的命令来运行 Nginx 和 PHP 应用:

$ docker run --name nginx -p 10000:80 -itd feisky/nginx
$ docker run --name phpfpm -itd --network container:nginx feisky/php-fpm

下载过程可能比较缓慢…下载完成后,执行 docker ps -a ,如图:

案例练习:某个应用的CPU使用率居然达到100%,我该怎么办?

第二个终端使用 curl 访问 http://[VM1 的 IP]:10000,确认 Nginx 已正常启动。

# 192.168.139.139是第一台虚拟机的IP地址
$ curl http://192.168.139.139:10000/

如图:

案例练习:某个应用的 CPU 使用率居然达到 100%,我该怎么办?

压力测试一

在第二个终端运行下面的 ab 命令:

# 并发10个请求测试Nginx性能,总共测试100个请求
$ ab -c 10 -n 100 http://192.168.139.139:10000/

如图:

案例练习:某个应用的 CPU 使用率居然达到 100%,我该怎么办?
从 ab 的输出结果我们可以看到,Nginx 能承受的每秒平均请求数只有 11.47。这个数据实际是很差的,如果暂时感觉不到什么,那尝试用 toppidstat 再做观察。

压力测试二

继续在第二个终端,运行 ab 命令:

# 这次将测试的请求总数增加到10000
$ ab -c 10 -n 10000  http://192.168.139.139:10000/

回到第一个终端运行 top 命令,并按下数字 1 ,切换到每个 CPU 的使用率:

案例练习:某个应用的 CPU 使用率居然达到 100%,我该怎么办?

这里可以看到,系统中有几个 php-fpm 进程的 CPU 使用率加起来接近 100%;而 CPU 的用户使用率(us)也已经超过了 99%,接近饱和。这里猜测是用户空间的 php-fpm 进程,导致 CPU 使用率骤升。

perf 分析 php-fpm 进程

那怎么知道是 php-fpm 的哪个函数导致了 CPU 使用率升高呢?我们来用 perf 分析一下。

在第一个终端运行下面的 perf 命令(如果提示命令not found,按提示安装即可):

# -g开启调用关系分析,-p指定php-fpm的进程号2250
$ perf top -g -p 2250

如图:

案例练习:某个应用的 CPU 使用率居然达到 100%,我该怎么办?

通过方向键移动到 php-fpm 进程,通过 enter 键展开 + 号位置的内容,如图:

案例练习:某个应用的 CPU 使用率居然达到 100%,我该怎么办?

可以看到,调用关系最终到了 sqrt 和 add_function。

grep 查找具体函数

尝试将PHP源码拷贝出来,然后查看是不是调用了这两个函数,

# 从容器phpfpm中将PHP源码拷贝出来
$ docker cp phpfpm:/app .

# 使用grep查找函数调用
$ grep sqrt -r app/ #找到了sqrt调用
$ grep add_function -r app/ #没找到add_function调用,这其实是PHP内置函数

如图:

案例练习:某个应用的 CPU 使用率居然达到 100%,我该怎么办?

到这里可知,只有 sqrt 函数在 app/index.php 被调用。最后我们来看下这个文件源代码,

案例练习:某个应用的 CPU 使用率居然达到 100%,我该怎么办?

其实,这里的本意,//test only 下的代码是不应该存在的,因为它造成多余地消耗CPU。代码虽然简单,但我们还是尝试把测试代码删除,再看看执行效果吧。

优化应用代码

课程提供了一个优化后的镜像,可以如下操作:

# 停止原来的应用
$ 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

不过,我想直接在现有容器上修改,修改已经拷贝出来的 index.php

案例练习:某个应用的 CPU 使用率居然达到 100%,我该怎么办?

然后覆盖到php-fpm容器里面,并验证是否更新了代码,

案例练习:某个应用的 CPU 使用率居然达到 100%,我该怎么办?

压力测试三

确保终端一正常运行 Nginx 和 PHP 应用,切换到终端二,首先 Ctrl+C 停止之前的 ab 命令后,再运行下面的命令:

ab -c 10 -n 10000  http://192.168.139.139:10000/

如图:

案例练习:某个应用的 CPU 使用率居然达到 100%,我该怎么办?

可以看到,现在每秒的平均请求数,已经从原来的 11 变成了 1222。

结语

本案例代码设计较为简单,工作中可能遇到更加复杂的问题,这里只是分享下,一种查找发现问题的方法。

同时,我会把更多实践案例归纳在 Linux 性能优化笔记 文章底部,欢迎阅读。:smile:

本作品采用《CC 协议》,转载必须注明作者和本文链接
本帖由系统于 4年前 自动加精
《L01 基础入门》
我们将带你从零开发一个项目并部署到线上,本课程教授 Web 开发中专业、实用的技能,如 Git 工作流、Laravel Mix 前端工作流等。
《L02 从零构建论坛系统》
以构建论坛项目 LaraBBS 为线索,展开对 Laravel 框架的全面学习。应用程序架构思路贴近 Laravel 框架的设计哲学。
讨论数量: 9

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!