Lework Study hard, improve every day.

[Linux性能优化]3.CPU使用率100%,怎么办?

2019-06-16
lework
本文 5120 字,阅读全文约需 15 分钟

CPU使用率是单位时间内CPU使用情况的统计,以百分比的方式展示。

CPU时间是Linux通过事先定义的节拍率(内核中表示为 HZ),触发时间中断,并使用全局变量Jiffies记录了开机以来的节拍数。每发生一次时间中断,Jiffies的值就加 1。 节拍率 HZ 是内核的可配选项,可以设置为100、250、1000等。不同的系统可能设置不同数值,你可以通过查询 /boot/config 内核选项来查看它的配置值。比如在我的系统中,节拍率设置成了1000,也就是每秒钟触发1000次时间中断。

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

同时,正因为节拍率HZ是内核选项,所以用户空间程序并不能直接访问。为了方便用户空间程序,内核还提供了一个用户空间节拍率 USER_HZ,它总是固定为100,也就是1/100 秒。这样,用户空间程序并不需要关心内核中HZ被设置成了多少,因为它看到的总是固定值USER_HZ。

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和Nice CPU高,说明用户态进程占用了较多的CPU,所以应该着重排查进程的性能问题。
  • 系统CPU高,说明内核态占用了较多的CPU,所以应该着重排查内核线程或者系统调用的性能问题。
  • I/O等待CPU高,说明等待I/O的时间比较长,所以应该着重排查系统存储是不是出现了I/O问题。
  • 软中断和硬中断高,说明软中断或硬中断的处理程序占用了较多的CPU,所以应该着重排查内核中的中断服务程序。

cpu使用率

CPU使用率,就是除了空闲时间外的其他时间占总CPU时间的百分比,用公式来表示就是:

                                空闲时间
            CPU使用率 =  1 - --------------
                                总cpu时间

通过查看/proc/stat,我们根据公式可以计算出系统cpu使用率。但是这里面的数值是开机以来的累积数据,计算出来的cpu使用率是开机到现在的cpu使用率。

我们计算cpu使用率,一般是选择一段时间内的cpu使用率,比如top使用的是3秒内的数据,而ps则用的是进程的生命周期数据。

计算一段时间内的cpu使用率的公式:

                                 空闲时间new - 空闲时间old 
            CPU使用率 =  1 - ------------------------------
                                总cpu时间new - 总cpu时间old

进程的cpu使用率是通过/proc/[pid]/stat文件内的数据来计算的。

怎么查看cpu使用率?

使用一些性能工具就能看到。

  • top 显示了系统总体的 CPU 和内存使用情况,以及各个进程的资源使用情况。
  • ps 则只显示了每个进程的资源使用情况。
  • pidstat 显示了用户态和内核态的cpu使用率
# 默认每3秒刷新一次
# top
top - 19:33:00 up  6:11,  5 users,  load average: 0.00, 0.01, 0.05
Tasks: 100 total,   1 running,  99 sleeping,   0 stopped,   0 zombie
%Cpu(s):  0.0 us,  0.0 sy,  0.0 ni,100.0 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
KiB Mem :   999720 total,   671020 free,   102360 used,   226340 buff/cache
KiB Swap: 10485756 total, 10485756 free,        0 used.   722092 avail Mem 

   PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND

     1 root      20   0   43668   4124   2488 S   0.0  0.4   0:01.18 systemd 

     2 root      20   0       0      0      0 S   0.0  0.0   0:00.01 kthreadd 

     3 root      20   0       0      0      0 S   0.0  0.0   0:15.86 ksoftirqd/0  

     5 root       0 -20       0      0      0 S   0.0  0.0   0:00.00 kworker/0:0H   

     7 root      rt   0       0      0      0 S   0.0  0.0   0:02.79 migration/0  

     8 root      20   0       0      0      0 S   0.0  0.0   0:00.00 rcu_bh    

     9 root      20   0       0      0      0 S   0.0  0.0   0:01.40 rcu_sched    
...

这个输出结果中,第三行%Cpu就是系统的CPU使用率,具体每一列的含义上一节都讲过,只是把CPU时间变换成了CPU使用率,我就不再重复讲了。不过需要注意,top默认显示的是所有CPU的平均值,这个时候你只需要按下数字1 ,就可以切换到每个CPU的使用率了。

继续往下看,空白行之后是进程的实时信息,每个进程都有一个%CPU列,表示进程的CPU 使用率。它是用户态和内核态CPU使用率的总和,包括进程用户空间使用的CPU、通过系统调用执行的内核空间CPU 、以及在就绪队列等待运行的CPU。在虚拟化环境中,它还包括了运行虚拟机占用的CPU。

# 每隔1秒输出一组数据,共输出2组
# pidstat 1 2
Linux 3.10.0-693.el7.x86_64 (node74-1) 	2019年06月16日 	_x86_64_	(2 CPU)

19时36分16秒   UID       PID    %usr %system  %guest   %wait    %CPU   CPU  Command
19时36分17秒     0     13528    0.00    0.99    0.00    0.00    0.99     0  kworker/0:0
19时36分17秒     0     13745    0.00    0.99    0.00    0.00    0.99     1  pidstat

19时36分17秒   UID       PID    %usr %system  %guest   %wait    %CPU   CPU  Command
19时36分18秒     0       950    0.99    0.00    0.00    0.00    0.99     1  tuned
19时36分18秒     0     13745    0.00    0.99    0.00    0.00    0.99     1  pidstat

平均时间:   UID       PID    %usr %system  %guest   %wait    %CPU   CPU  Command
平均时间:     0       950    0.50    0.00    0.00    0.00    0.50     -  tuned
平均时间:     0     13528    0.00    0.50    0.00    0.00    0.50     -  kworker/0:0
平均时间:     0     13745    0.00    0.99    0.00    0.00    0.99     -  pidstat

部分指标含义:

  • 用户态 CPU 使用率 (%usr)
  • 内核态 CPU 使用率(%system)
  • 运行虚拟机 CPU 使用率(%guest)
  • 等待 CPU 使用率(%wait)
  • 总的 CPU 使用率(%CPU)

CPU 使用率过高怎么办?

通过toppspidstat我们可以很容易的找到使用cpu高的进程,找到进程后,下一步该做什么呢?

  • 使用GDB(The GNU Project Debugger)来调试程序,找出问题点。但是GDB会在程序中打上断点,影响业务正常工作。
  • 使用perf分析CPU性能问题,它以性能事件采样为基础,不仅可以分析系统的各种事件和内核性能,还可以用来分析指定应用程序的性能问题。
# yum -y install perf
Samples: 106  of event 'cpu-clock', Event count (approx.): 26160156 

Overhead  Shared Object            Symbol
 
  56.38%  [kernel]                 [k] mpt_put_msg_frame
   8.97%  [kernel]                 [k] _raw_spin_unlock_irqrestore
   3.82%  [kernel]                 [k] _raw_qspin_lock
   3.82%  [kernel]                 [k] xfs_iflush_int
   3.82%  [kernel]                 [k] xfs_inode_buf
...

输出结果中,第一行包含三个数据,分别是采样数(Samples)、事件类型(event)和事件总数量(Event count)。比如这个例子中,perf总共采集了106个CPU时钟事件,而总事件数则为26160156

  • 第一列 Overhead ,是该符号的性能事件在所有采样中的比例,用百分比来表示。
  • 第二列 Shared ,是该函数或指令所在的动态共享对象(Dynamic Shared Object),如内核、进程名、动态链接库名、内核模块名等。
  • 第三列 Object ,是动态共享对象的类型。比如 [.] 表示用户空间的可执行程序、或者动态链接库,而 [k] 则表示内核空间。
  • 最后一列 Symbol 是符号名,也就是函数名。当函数名未知时,用十六进制的地址来表示。
# perf record # 先进行采样
^C[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 0.232 MB perf.data (1762 samples) ]

# perf report # 对采样的数据生成报告,跟perf top一样

案例

还是之前模拟多进程的例子

使用stress模拟多进程

# -c 指定几个进程,-t指定时间
# stress -c 2 -t 600
stress: info: [13786] dispatching hogs: 2 cpu, 0 io, 0 vm, 0 hdd

使用top查看cpu使用率

# top
top - 19:53:34 up  6:31,  6 users,  load average: 1.67, 0.62, 0.26
Tasks: 105 total,   3 running, 102 sleeping,   0 stopped,   0 zombie
%Cpu0  :100.0 us,  0.0 sy,  0.0 ni,  0.0 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
%Cpu1  :100.0 us,  0.0 sy,  0.0 ni,  0.0 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
KiB Mem :   999720 total,   631232 free,   107600 used,   260888 buff/cache
KiB Swap: 10485756 total, 10485756 free,        0 used.   710932 avail Mem 

   PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND   

 13788 root      20   0    7264     96      0 R  99.7  0.0   1:42.94 stress 

 13787 root      20   0    7264     96      0 R  99.3  0.0   1:43.02 stress
 ...

从上面可以看到是stress进程导致cpu使用率比较高。

使用perf查看进程的哪个函数导致cpu上升的

# -g 开启调用关系分析,-p 指定进程id
# perf record -g -p 13788
^C[ perf record: Woken up 4 times to write data ]
[ perf record: Captured and wrote 0.966 MB perf.data (15691 samples) ]

# perf report

Samples: 15K of event 'cpu-clock', Event count (approx.): 3922750000  

  Children      Self  Command  Shared Object      Symbol             

+   36.33%    36.32%  stress   libc-2.17.so       [.] __random_r      

+   30.27%    30.20%  stress   libc-2.17.so       [.] __random         

+   12.40%    12.40%  stress   libc-2.17.so       [.] rand            

+    9.80%     9.78%  stress   stress             [.] 0x0000000000002dc1    

+    4.31%     4.31%  stress   stress             [.] 0x0000000000001000 

从输出结果可以看到是stress的__random随机数生成函数导致cpu上升的。 使用回车键可以看到引用内容。

原文地址 https://lework.github.io/2019/06/16/cpu-usage-100/

Similar Posts

Comments