这篇文章上次修改于 899 天前,可能其部分内容已经发生变化,如有疑问可询问作者。

1 CPU 性能指标

  • CPU 利用率

    • 用户 CPU 利用率高,说明用户程序比较繁忙。
    • 系统 CPU 利用率高,说明内核比较繁忙。
    • 等待 I/O 的 CPU 使用率,即 iowait 高,说明系统与硬件的 I/O 交互时间较长。
    • 软中断和硬中断的 CPU 使用率高,说明中断较多,比如 SYN 泛洪攻击导致软中断中的网络中断较多。
  • 平均负载

    • 如果平均负载大于逻辑 CPU 个数,说明负载较重。
  • 进程上下文切换

    • 包括无法获取资源的自愿上下文切换和被系统强制调度的非自愿上下文切换。

      • 自愿上下文切换较多,可能发生了 I/O 等问题。
      • 非自愿上下文切换较多,可能 CPU 成为了瓶颈。
    • 过多的上下文切换会导致 CPU 时间过多地消耗在寄存器、内核堆栈、虚拟内存等数据的保存和恢复上。
  • CPU 缓存命中率

2 性能工具

2.1 根据指标查工具

2.1.1 平均负载

  • uptime:最简单

    $ uptime
    02:34:03 up 2 days, 20:14,  1 user,  load average: 0.63, 0.83, 0.88
  • 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
    ...

2.1.2 系统整体 CPU 使用率

  • mpstat

    # -P ALL 表示监控所有CPU,后面数字5表示间隔5秒后输出一组数据
    $ mpstat -P ALL 5
    Linux 4.15.0 (ubuntu) 09/22/18 _x86_64_ (2 CPU)
    13:30:06     CPU    %usr   %nice    %sys %iowait    %irq   %soft  %steal  %guest  %gnice   %idle
    13:30:11     all   50.05    0.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00   49.95
    13:30:11       0    0.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00  100.00
    13:30:11       1  100.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00
  • vmstat

    # 每隔5秒输出1组数据
    $ vmstat 5
    procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
     r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st
     0  0      0 7005360  91564 818900    0    0     0     0   25   33  0  0 100  0  0
  • top:第 3 行
  • sar:可以记录历史数据
  • /proc/stat:是性能工具的数据来源

2.1.3 进程 CPU 使用率

  • pidstat:比 top 提供的指标更详细。

    # 间隔5秒后输出一组数据,-u表示CPU指标
    $ pidstat -u 5 1
    Linux 4.15.0 (ubuntu)     09/22/18     _x86_64_    (2 CPU)
    13:42:08      UID       PID    %usr %system  %guest   %wait    %CPU   CPU  Command
    13:42:13        0       104    0.00    3.39    0.00    0.00    3.39     1  kworker/1:1H
    13:42:13        0       109    0.00    0.40    0.00    0.00    0.40     0  kworker/0:1H
    13:42:13        0      2997    2.00   35.53    0.00    3.99   37.52     1  stress
    13:42:13        0      3057    0.00    0.40    0.00    0.00    0.40     0  pidstat
  • ps, top, atop, htop:top 还提供进程的状态。

2.1.4 系统上下文切换

  • vmstat:提供上下文切换次数(cs),运行状态和不可中断状态进程的数量(r,b)。

2.1.5 进程上下文切换

  • pidstat

    # 每隔5秒输出1组数据
    $ pidstat -w 5
    Linux 4.15.0 (ubuntu)  09/23/18  _x86_64_  (2 CPU)
    
    08:18:26      UID       PID   cswch/s nvcswch/s  Command
    08:18:31        0         1      0.20      0.00  systemd
    08:18:31        0         8      5.40      0.00  rcu_sched
    ...
    # 每隔1秒输出一组数据(需要 Ctrl+C 才结束)
    # -wt 参数表示输出线程的上下文切换指标
    $ pidstat -wt 1
    08:14:05      UID      TGID       TID   cswch/s nvcswch/s  Command
    ...
    08:14:05        0     10551         -      6.00      0.00  sysbench
    08:14:05        0         -     10551      6.00      0.00  |__sysbench
    08:14:05        0         -     10552  18911.00 103740.00  |__sysbench
    08:14:05        0         -     10553  18915.00 100955.00  |__sysbench
    08:14:05        0         -     10554  18827.00 103954.00  |__sysbench
    ...

2.1.6 软中断

  • top:第 3 行的 si 列。
  • mpstat:soft 列。
  • /proc/softirqs

    $ watch -d cat /proc/softirqs
                        CPU0       CPU1
              HI:          0          0
           TIMER:    1083906    2368646
          NET_TX:         53          9
          NET_RX:    1550643    1916776
           BLOCK:          0          0
        IRQ_POLL:          0          0
         TASKLET:     333637       3930
           SCHED:     963675    2293171
         HRTIMER:          0          0
             RCU:    1542111    1590625

2.1.7 硬中断

  • top:第 3 行的 hi 列。
  • vmstat:提供总的中断次数(in)。
  • /proc/interrupts:提供各种中断在每个 CPU 上的累积次数。

    # -d 参数表示高亮显示变化的区域
    $ watch -d cat /proc/interrupts
               CPU0       CPU1
    ...
    RES:    2450431    5279697   Rescheduling interrupts
    ...

2.1.8 网络

  • dstat

    # 间隔1秒输出10组数据
    $ dstat 1 10
    You did not select any stats, using -cdngy by default.
    --total-cpu-usage-- -dsk/total- -net/total- ---paging-- ---system--
    usr sys idl wai stl| read  writ| recv  send|  in   out | int   csw
      0   0  96   4   0|1219k  408k|   0     0 |   0     0 |  42   885
      0   0   2  98   0|  34M    0 | 198B  790B|   0     0 |  42   138
      0   0   0 100   0|  34M    0 |  66B  342B|   0     0 |  42   135
      0   0  84  16   0|5633k    0 |  66B  342B|   0     0 |  52   177
      0   3  39  58   0|  22M    0 |  66B  342B|   0     0 |  43   144
      0   0   0 100   0|  34M    0 | 200B  450B|   0     0 |  46   147
      0   0   2  98   0|  34M    0 |  66B  342B|   0     0 |  45   134
      0   0   0 100   0|  34M    0 |  66B  342B|   0     0 |  39   131
      0   0  83  17   0|5633k    0 |  66B  342B|   0     0 |  46   168
      0   3  39  59   0|  22M    0 |  66B  342B|   0     0 |  37   134
  • sar

    # -n DEV 表示显示网络收发的报告,间隔1秒输出一组数据
    $ sar -n DEV 1
    15:03:46        IFACE   rxpck/s   txpck/s    rxkB/s    txkB/s   rxcmp/s   txcmp/s  rxmcst/s   %ifutil
    15:03:47         eth0  12607.00   6304.00    664.86    358.11      0.00      0.00      0.00      0.01
    15:03:47      docker0   6302.00  12604.00    270.79    664.66      0.00      0.00      0.00      0.00
    15:03:47           lo      0.00      0.00      0.00      0.00      0.00      0.00      0.00      0.00
    15:03:47    veth9f6bbcd   6302.00  12604.00    356.95    664.66      0.00      0.00      0.00      0.05
  • tcpdump

    # -i eth0 只抓取eth0网卡,-n不解析协议名和主机名
    # tcp port 80表示只抓取tcp协议并且端口号为80的网络帧
    $ tcpdump -i eth0 -n tcp port 80
    15:11:32.678966 IP 192.168.0.2.18238 > 192.168.0.30.80: Flags [S], seq 458303614, win 512, length 0
    ...

2.1.9 I/O

  • dstat
  • sar

2.1.10 CPU 个数

  • lscpu
  • /proc/cpuinfo

    $ grep 'model name' /proc/cpuinfo | wc -l
    2

2.1.11 事件剖析

  • 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
    ...
    # -g开启调用关系分析,-p指定php-fpm的进程号21515
    $ perf top -g -p 21515
    # 记录性能事件,等待大约15秒后按 Ctrl+C 退出
    $ perf record -g
    
    # 查看报告
    $ perf report
  • execsnoop:查看短时进程。

    # 按 Ctrl+C 结束
    $ execsnoop
    PCOMM            PID    PPID   RET ARGS
    sh               30394  30393    0
    stress           30396  30394    0 /usr/local/bin/stress -t 1 -d 1
    sh               30398  30393    0
    stress           30399  30398    0 /usr/local/bin/stress -t 1 -d 1
    sh               30402  30400    0
    stress           30403  30402    0 /usr/local/bin/stress -t 1 -d 1
    sh               30405  30393    0
    stress           30407  30405    0 /usr/local/bin/stress -t 1 -d 1
    ...
  • strace:跟踪进程的系统调用。

    # strace -p $(pgrep app)
    strace: Process 4988 attached
    restart_syscall(<\.\.\. resuming interrupted nanosleep \.\.\.>) = 0
    openat(AT_FDCWD, "/dev/sdb1", O_RDONLY|O_DIRECT) = 4
    mmap(NULL, 33558528, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f448d240000
    read(4, "8vq\213\314\264u\373\4\336K\224\25@\371\1\252\2\262\252q\221\n0\30\225bD\252\266@J"\.\.\., 33554432) = 33554432
    write(1, "Time used: 0.948897 s to read 33"\.\.\., 45) = 45
    close(4)                                = 0

2.1.12 进程的父子关系

  • pstree

    $ pstree | grep stress
            |-docker-containe-+-php-fpm-+-php-fpm---sh---stress
            |         |-3*[php-fpm---sh---stress---stress]
    # -a 表示输出命令行选项
    # p表PID
    # s表示指定进程的父进程
    $ pstree -aps 3084
    systemd,1
      └─dockerd,15006 -H fd://
          └─docker-containe,15024 --config /var/run/docker/containerd/containerd.toml
              └─docker-containe,3991 -namespace moby -workdir...
                  └─app,4009
                      └─(app,3084)

2.2 根据工具查指标

  • uptime:平均负载。
  • top:平均负载,运行队列长度,整体 CPU 使用率,每个进程的 CPU 使用率和状态。
  • vmstat: 系统整体 CPU 使用率,上下文切换次数,中断次数,处于运行和不可中断状态的进程数量。
  • mpstat:每个 CPU 的使用率和软中断次数。
  • pidstat:进程的 CPU 使用率,中断上下文切换次数。
  • ps:每个进程的状态和 CPU 使用率。
  • pstree:进程间的父子关系。
  • dstat:系统整体的 CPU 使用率,网络。
  • sar:网络。
  • strace:进程的系统调用。
  • perf:CPU 性能事件剖析,如调用链分析、CPU 缓存、CPU 调度等。
  • execsnoop:监控短时进程。

3 如何快速 CPU 的性能瓶颈

例如:

  • 当通过 top 分析到 CPU 使用率高,可通过 pidstat 查看哪个进程 CPU 使用率高,进而通过 strace 分析系统调用情况以及用 perf 分析调用链中各级函数调用情况。
  • 当通过 top 分析到平均负载高,可通过 vmstat 分析运行状态和不可中断状态的进程哪种导致的,如果是运行状态进程导致的,需要通过 top 和 pidstat 分析进程;否则,需要通过 dstat 或 sar 进一步分析 I/O。
  • 当发现软中断导致 CPU 使用率高,可通过查看 /proc/softirqs 查看哪种软中断导致的,如果是网络中断导致的,可通过 sar 和 tcpdump 进一步分析。

参考

倪朋飞. Linux 性能优化实战.