Linux系统优化之三:如何处理cpu占用100%

cpu使用率

linux通过proc这个虚拟文件系统,提供系统内部信息,/proc/stat提供的是系统cpu信息,可以使用以下命令查看:

# cat /proc/stat |grep ^cpu
cpu  241187 1658 242572 4371878 374 0 554 0 0 0
cpu0 134376 743 93967 2199565 172 0 286 0 0 0
cpu1 106810 914 148605 2172313 202 0 267 0 0 0

第一列表示cpu编号,没有编号的cpu表示所有cpu,其他列表示不同场景下cpu累加节拍数,它的单位是USER_HZ,也就是10ms(1/100s),每列具体含义,可以man proc

cpu相关指标

  • user: us, 代表用户态cpu时间,它不包括nice时间,但包括guest时间
  • nice: ni,代表低优先级用户态时间,就是进程nice值调整为1-19之间的cpu时间,nice值取值范围是-20~19,数值越大,优先级越低
  • system:sys,代表内核态cpu时间
  • idle:id,代表空闲时间,他不包括等待io时间(iowait)
  • iowait:wa,代表等待io的cpu时间
  • irq:hi,代表处理硬中断cpu时间
  • softirq:si,代表软中断cpu时间
  • steal:st,当系统运行在虚拟机中时,被其他虚拟机占用的cpu时间
  • guest:guest,代表通过虚拟化运行其他操作系统的时间,也就是运行虚拟机的cpu时间
  • guest_nice:gnice,代表低优先级运行虚拟机时间

cpu使用率=1-空闲时间/总cpu时间,一般计算cpu使用率,会取间隔一段时间的两次值,做差后,在计算出这段时间内平均cpu使用率,性能工具给出的都是间隔一段时间内的平均cpu使用率,所以要注意间隔时间设置

  • 查看cpu使用率工具
    • top工具
    • top工具默认显示的是所有cpu使用率平均值,要看单个cpu,可以按1,依次查看每个cpu使用率
    • pidstat工具
  pidstat 1 5

0:47:46 PM   UID       PID    %usr %system  %guest   %wait    %CPU   CPU  Command
10:47:47 PM     0       459    0.00    0.98    0.00    0.00    0.98     1  xfsaild/sda4
10:47:47 PM     0     28777    0.98    1.96    0.00    0.00    2.94     0  pidstat
%usr:用户态cpu使用率
%system:内核态cpu使用率
%guest:运行虚拟机cpu使用率
%wait:等待cpu使用率
%CPU:总的cpu使用率

cpu使用率过高分析

调试工具gdb,gdb调试程序过程会中断程序运行,故此,一般不允许在线上环境运行,通常是找出问题函数之后,线下借助gdb进一步分析函数内部问题
生产环境调试工具建议使用perf,第一种常见用法是 perf top,它能实时显示占用cpu时钟最多的函数或者指令,可以用来查找热点函数,使用如下:

perf top
Samples: 642  of event 'cpu-clock', Event count (approx.): 90431059
Overhead  Shared Object        Symbol
  18.63%  [kernel]             [k] _raw_spin_unlock_irqrestore
   5.58%  perf                 [.] __symbols__insert
   5.00%  [kernel]             [k] mpt_put_msg_frame
   3.66%  [kernel]             [k] vmw_cmdbuf_header_submit
   2.65%  [kernel]             [k] finish_task_switch
   2.42%  perf                 [.] rb_next
   1.85%  [kernel]             [k] kallsyms_expand_symbol.constprop.1
   1.74%  perf                 [.] map__process_kallsym_symbol
   1.73%  [kernel]             [k] __softirqentry_text_start
Samples: 采样数
event:事件类型
Event count:事件总数量
Overhead:该符号的性能事件在所有采样中占的比例,用百分比显示
Shared :该函数或指令所在的动态共享对象,如内核,进程名,动态连接库名,内核模块名等
Object:动态共享对象的类型,[.]表示用户空间可执行程序或者动态链接库,[k]表示内核空间
Symbol:符号名,就是函数名,若函数名未知,则使用16禁止的地址来表示

第二种常见用法

  • perf record:展示系统性能信息,并提供保存功能
  • perf report:解析展示perf record保存的数据
案例分析

环境说明:以nginx+php的web服务为例,需要安装perf,systat,docker,ab工具,web实例使用两个docker实例实现,一个提供web服务器,一个作为web服务器的客户端,使用ab工具,给web服务增加压力请求,开启两个终端,具体操作如下:

# docker run -it -d --name nginx -p 10000:80 feisky/nginx
# docker run -it -d --name php --network container:nginx feisky/php-fpm

# curl http://10.0.11.12:10000    访问宿主机地址的10000端口,显示It works!表示容器正常启动成功

开启ab测试:
# ab -c10 -n100 http://10.0.11.12:10000/

Requests per second:    20.51 [#/sec] (mean)
Time per request:       487.579 [ms] (mean)
Time per request:       48.758 [ms] (mean, across all concurrent requests)
Transfer rate:          3.44 [Kbytes/sec] received


从结果可以看出,nginx每秒平均请求数只有20.51,这有点差,到底哪里出了问题,我们继续追查,

一个终端上运行:
# ab -c10 -n10000 http://10.0.11.12:10000/

另一个终端运行:
top
按1,结果如下:

top - 09:50:23 up  8:00,  5 users,  load average: 4.31, 1.51, 0.54
Tasks: 204 total,   7 running, 105 sleeping,   0 stopped,   0 zombie
%Cpu0  : 98.3 us,  1.0 sy,  0.0 ni,  0.0 id,  0.0 wa,  0.0 hi,  0.7 si,  0.0 st
%Cpu1  : 97.3 us,  2.0 sy,  0.0 ni,  0.0 id,  0.0 wa,  0.0 hi,  0.7 si,  0.0 st
KiB Mem :  2017512 total,   288396 free,   534180 used,  1194936 buff/cache
KiB Swap:  2047996 total,  2047472 free,      524 used.  1293320 avail Mem
   PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND
 30877 daemon    20   0  336696  16548   8868 R  39.7  0.8   0:08.92 php-fpm
 30879 daemon    20   0  336696  16484   8804 R  39.7  0.8   0:09.23 php-fpm
 30876 daemon    20   0  336696  16548   8868 R  39.4  0.8   0:09.21 php-fpm
 30880 daemon    20   0  336696  16484   8804 R  39.4  0.8   0:08.88 php-fpm
 30878 daemon    20   0  336696  16484   8804 R  38.7  0.8   0:09.06 php-fpm
 30225 root      20   0  109104   6168   4388 S   0.7  0.3   0:00.61 containerd-shim
  1407 root      20   0 1055344  43452  23408 S   0.3  2.2   0:43.45 containerd
  1408 Debian-+  20   0   64376  11564   7020 S   0.3  0.6   0:20.01 snmpd
 29885 root      20   0 1277672 100664  47664 S   0.3  5.0   0:20.95 dockerd
 30298 systemd+  20   0   33172   4276   2972 S   0.3  0.2   0:00.15 nginx
 30299 systemd+  20   0   33136   3748   2392 S   0.3  0.2   0:00.06 nginx

可以看出,php-fpm进程使用率加起来将近200%,并且每个cpu的us达到98.3%,可以看出,正式由于php进程导致cpu使用率飙升

下面使用perf工具进一步分析:

# perf top -g -p 30880   30880是php-fpm进程号
按方向键切换到php-fpm,在按下回车键展开php-fpm调用关系,最终发现sqrt和add_function函数
Samples: 205K of event 'cpu-clock', Event count (approx.): 3490439906
  Children      Self  Shared Object       Symbol                                                               
-   99.58%     0.00%  php-fpm             [.] zend_execute
 -   96.77%     4.19%  php-fpm             [.] execute_ex                                                       
   - 54.13% execute_ex                                                                                         
      - 20.41% 0x8c4a7c                                                                                        
           5.20% sqrt                                                                                          
      - 16.71% 0x98dea3                                                                                        
         - 4.73% 0x98dd97                                                                                      
              4.68% add_function


下面查看源码内容:
拷贝代码到当前目录
# docker cp php:/app .

# grep sqrt -r app/
app/index.php:  $x += sqrt($x);
查看代码,进行修复,然后重新运行,会发现这次nginx每秒平均请求数大幅上升了,基本算正常了

总结

  • 用户cpu和nice cpu高,说明用户进程占用了较多的cpu,所以应该着重排查用户进程的性能问题
  • 系统cpu高,说明内核占用较多cpu,应着重排查内核线程或者系统调用的性能问题
  • io wait cpu高,说明等待io时间长,着重排查磁盘存储是否出现io问题
  • 软中断和硬中断高,说明中断程序占用过多的cpu,应该着重排查内核中的中断处理程序
  • 碰到cpu占用率高的问题,要借助top,pidstat工具,确认引起性能问题原因,再使用perf工具排查引起性能问题的具体函数*

可能会出现的问题

  • 在centos系统上运行perf top -g -p pid,会看到16进制的东西,可能会报xxx.so错误,这一般是perf无法找到依赖的库,在分析容器应用问题经常会碰到,一般可以在容器外面把分析记录保存下来,到容器里去看结果,具体操作如下:
  • 在宿主机运行perf record -g -p pid 执行一会,退出命令
  • 把生成的perf.data拷贝到容器
docker cp perf.data php:/tmp
docker exec -it php /bin/bash
安装perf等工具
perf report 分析perf.data数据

centos系统一般会出现上面问题,ubuntu一般不会出现,perf找不到sqr函数,只看到地址,一般是因为依赖在容器内,故而perf无法找到php符号表,解决办法就是把perf.data拷贝到容器内用perf report进行分析


文章作者: BY 木易杨
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 BY 木易杨 !
评论
 上一篇
Linux系统优化之二:cpu上下文切换 Linux系统优化之二:cpu上下文切换
linux是一个多任务操作系统,它支持远大于cpu核心数的任务同时运行,当然,这些任务实际上并不是真正同时运行,操作系统在很短时间内,将cpu资源轮流分配给这些任务,造成多任务同时运行的错觉。每个任务运行前,cpu需要知道从哪里加载,从哪
2020-04-25 BY 木易杨
下一篇 
Linux优化实战之一:平均负载 Linux优化实战之一:平均负载
平均负载 平均负载:是指单位时间内,系统处于可运行状态和不可中断状态的平均进程数,也就是平均活跃进程数,它和cpu使用率没直接关系 可运行状态进程: 正在使用cpu或者正在等待使用cpu的进程,就是ps命令看到的处于R状态的进程 不可中
2020-04-25 BY 木易杨