05 | CPU使用率100%

246 阅读4分钟

1. 概述

在进行资源分析时,通常我们优先关注资源的使用率,而不是负载的具体数值。对于上下文切换,其中有一种称为非自愿上下文切换的情况,通常发生在进程或线程的时间片耗尽时,操作系统会强制其释放 CPU。需要注意的是,时间片的长度与节拍率(HZ)有关,它是衡量时间片的单位。节拍率 HZ 是内核的可配选项,可以设置为 100、250、1000 等。不同的系统可能设置不同数值,你可以通过查询 /boot/config 内核选项来查看它的配置值。查看节拍率命令如下:

$ grep 'CONFIG_HZ=' /boot/config-$(uname -r)
CONFIG_HZ=250

Linux 通过 /proc 虚拟文件系统,向用户空间提供了系统内部状态的信息,而 /proc/stat 提供的就是系统的 CPU 和任务统计信息。比方说,如果你只关注 CPU 的话,可以执行下面的命令:

# 只保留各个CPU的数据
$ cat /proc/stat | grep ^cpu
cpu  280580 7407 286084 172900810 83602 0 583 0 0 0
cpu0 144745 4181 176701 86423902 52076 0 301 0 0 0
cpu1 135834 3226 109383 86476907 31525 0 282 0 0 0

常见的CPU指标:

  • user(通常缩写为 us),代表用户态 CPU 时间。注意,它不包括下面的 nice 时间,但包括了 guest 时间。
  • nice(通常缩写为 ni),代表低优先级用户态 CPU 时间,也就是进程的 nice 值被调整为 1-19 之间时的 CPU 时间。这里注意,nice 可取值范围是 -20 到 19,数值越大,优先级反而越低。
  • system(通常缩写为 sys),代表内核态 CPU 时间。
  • idle(通常缩写为 id),代表空闲时间。注意,它不包括等待 I/O 的时间(iowait)。
  • iowait(通常缩写为 wa),代表等待 I/O 的 CPU 时间。irq(通常缩写为 hi),代表处理硬中断的 CPU 时间。
  • softirq(通常缩写为 si),代表处理软中断的 CPU 时间。
  • steal(通常缩写为 st),代表当系统运行在虚拟机中的时候,被其他虚拟机占用的 CPU 时间。
  • guest(通常缩写为 guest),代表通过虚拟化运行其他操作系统的时间,也就是运行虚拟机的 CPU 时间。
  • guest_nice(通常缩写为 gnice),代表以低优先级运行虚拟机的时间。

CPU 使用率,就是除了空闲时间外的其他时间占总 CPU 时间的百分比

查看CPU使用率

  • top 显示了系统总体的 CPU 和内存使用情况,以及各个进程的资源使用情况。
  • ps 则只显示了每个进程的资源使用情况。

使用top命令

# 默认每3秒刷新一次
$ top
top - 11:58:59 up 9 days, 22:47,  1 user,  load average: 0.03, 0.02, 0.00
Tasks: 123 total,   1 running,  72 sleeping,   0 stopped,   0 zombie
%Cpu(s):  0.3 us,  0.3 sy,  0.0 ni, 99.3 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
KiB Mem :  8169348 total,  5606884 free,   334640 used,  2227824 buff/cache
KiB Swap:        0 total,        0 free,        0 used.  7497908 avail Mem

  PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND
    1 root      20   0   78088   9288   6696 S   0.0  0.1   0:16.83 systemd
    2 root      20   0       0      0      0 S   0.0  0.0   0:00.05 kthreadd
    4 root       0 -20       0      0      0 I   0.0  0.0   0:00.00 kworker/0:0H
...

使用pidstat命令

# 每隔1秒输出一组数据,共输出5组
$ pidstat 1 5
15:56:02      UID       PID    %usr %system  %guest   %wait    %CPU   CPU  Command
15:56:03        0     15006    0.00    0.99    0.00    0.00    0.99     1  dockerd

...

Average:      UID       PID    %usr %system  %guest   %wait    %CPU   CPU  Command
Average:        0     15006    0.00    0.99    0.00    0.00    0.99     -  dockerd

如何找到使用CPU高的函数?GDB可以分析,不过这个工具一般不会再生产上使用,因为会影响程序运行。生产环境一般使用perf命令

$ perf top
Samples: 833  of event 'cpu-clock', Event count (approx.): 97742399
Overhead  Shared Object       Symbol
   7.28%  perf                [.] 0x00000000001f78a4
   4.72%  [kernel]            [k] vsnprintf
   4.32%  [kernel]            [k] module_get_kallsym
   3.65%  [kernel]            [k] _raw_spin_unlock_irqrestore
...

指标解释

列名含义
Overhead性能事件在所有采样中的比例,以百分比表示。
Shared动态共享对象(Dynamic Shared Object),包括内核、进程名、动态链接库名、内核模块名等。
Object动态共享对象的类型:- [.]表示用户空间的可执行程序或动态链接库。- [k]表示内核空间。
Symbol符号名(函数名)。若函数名未知,则显示十六进制地址。

perf top像top一样,只实时展示数据,并不保存数据,下面可以使用perf record收集数据

$ perf record # 按Ctrl+C终止采样
[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 0.452 MB perf.data (6093 samples) ]

$ perf report # 展示类似于perf top的报告

-g 显示调用关系

2. 案例

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

准备两台虚拟机

配置docker镜像配置文件

tee /etc/docker/daemon.json <<-'EOF'
{
    "registry-mirrors": [
       "https://docker.1ms.run",
       "https://docker.1panel.live/"
    ]
}
EOF

systemctl daemon-reload

systemctl restart docker

VM1 终端 1:

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

VM 2终端 1:

# 172.23.28.83是第一台虚拟机的IP地址
$ curl http://172.23.28.83:10000/
It works!

VM2 终端:

# 并发10个请求测试Nginx性能,总共测试100个请求
$ ab -c 10 -n 100 http://172.23.28.83:10000/
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 -c 10 -n 10000 http://172.23.28.83:10000/

回到VM1执行top,并输入1

通过perf继续查看是php-fpm的哪个函数导致的

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

清理环境

docker rm -f nginx phpfpm

3. 小结

3.1. CPU 使用率:性能问题排查的第一关注点

CPU 使用率是系统性能的最直观和常用的指标,也是性能排查的首要关注点。理解各类 CPU 使用率的含义,对定位问题至关重要。以下是常见的 CPU 使用率类型及其意义:

  1. 用户 CPU(%user)和 Nice CPU(%nice)
    • 用户态进程占用较多的 CPU。
    • 排查重点:进程性能问题,例如高计算量的程序或异常负载的应用。
  1. 系统 CPU(%system)
    • 内核态占用较多的 CPU。
    • 排查重点:内核线程或系统调用的性能问题。
  1. 等待 I/O(%iowait)
    • CPU 空闲,但等待 I/O 操作完成。
    • 排查重点:存储性能问题,例如磁盘 I/O 的瓶颈。
  1. 中断(%irq)和软中断(%softirq)
    • CPU 被硬中断或软中断的处理程序占用。
    • 排查重点:中断服务程序,如网络、存储驱动等内核模块。

3.2. 性能问题排查思路

  1. 确认 CPU 使用率来源
    使用 toppidstat 等工具查看各进程或线程的 CPU 占用情况:
    • top:实时显示系统资源使用情况。
    • pidstat:按进程或线程统计 CPU 使用率,定位高 CPU 使用的具体进程或线程。
  1. 深入分析问题根因
    使用 perf 等性能分析工具,进一步排查具体函数或系统调用:
    • 检测高 CPU 消耗的热点函数。
    • 确认系统调用或内核线程的异常行为。
  1. 针对性优化
    • 用户态问题:优化代码逻辑、降低计算复杂度。
    • 内核态问题:调整系统参数或升级相关驱动。
    • I/O 问题:优化存储性能或调整 I/O 调度策略。
    • 中断问题:优化设备配置或减少中断处理开销。

通过以上方法,可以快速定位并解决 CPU 使用率升高导致的性能问题。

附录

blog.csdn.net/wufaqidong1…