Linux系统优化之四:如何处理大量不可中断进程和僵尸进程

之前的专栏讨论了cpu使用率高的问题,根据之前专栏的相关介绍,其实等待I/O的cpu使用率(简称iowait)升高,也是常见的性能问题,本文就讨论下这个问题

进程状态

top工具显示结果说明

  • top输出结果R列相关状态说明
  • R:running的缩写,表示进程在cpu就绪队列中,正在运行或者正在等待运行
  • D:disk sleep缩写,也就是不可中断睡眠,表示进程在与硬件交互,且在交互过程中不允许被其他进程或中断打断
  • Z:zombie缩写,僵尸进程,,就是进程结束了,但是其父进程还没有回收他的资源,比如进程描述符,pid等
  • S:interruptible sleep缩写,就是可中断睡眠,表示进程因为某个事件被系统挂起,当进程的事件发生时,它会被唤醒并进入R状态
  • I:idle的缩写,就是空闲状态,用在不可中断睡眠的内核线程上,硬件交互导致的不可中断进程用D表示,对于某些内核线程来说,他们可能实际并没有任何负载,用idle就是为了区分这种情况。D状态的进程会导致平均负载升高,I状态的进程不会

除了以上5个状态之外,还有下面两个状态

  • T:t,stopped或者traced缩写,表示进程处于暂停或跟踪状态。向一个进程发送SIGSTOP信号,该进程会变成暂停状态(stopped),再发送SIGCONT信号,进程恢复运行,如果进程是终端里直接启动,则需要你用fg命令恢复到前台运行;当你用gdb调试一个进程时,再使用断点中断进程后,进程就变成跟踪状态(traced),这也是一种特殊的暂停状态
  • X:dead缩写,表示进程已经消亡,不会在top或ps中看到此进程

不可中断状态,是为保证进程数据与硬件状态一致,正常情况下,不可中断状态会在短时间内结束,所以,短时的不可中断状态,算正常现象,但如果系统或硬件发送故障,进程会长时间在不可中断睡眠状态,甚至导致出现大量不可中断睡眠进程,这时就要引起注意

僵尸进程,是多进程应用很容易碰到的问题,正常情况,当一个进程创建了子进程,它应该通过系统调用wait()或waitpid()等待子进程结束,回收子进程资源;子进程结束,会向它的父进程发送SIGCHLD信号,所以,父进程还可以注册SIGCHLD信号处理函数,异步回收资源,如果父进程没这么做,或者子进程执行太快,父进程没来得及处理子进程状态,子进程就已经提前退出,那此时子进程就变成僵尸进程。通常僵尸进程持续时间较短,在父进程回收他的资源后就会消失,或者父进程退出后,由init进程回收后也会消亡,一旦父进程没有处理子进程的终止,还一直处于运行状态,那子进程就会一直处于僵尸状态,大量僵尸进程会用尽pid,导致新进程不能被创建,所以一定要避免

案例分析

环境说明

  • 使用docker运行应用,另外需要使用dstat工具

操作分析

# docker run -it -d --privileged --name=app feisky/app:iowait
# ps aux |grep /app
root       4030  0.0  0.0   4512  1620 pts/0    Ss+  17:18   0:00 /app

Ss+ : S表示可中断睡眠状态,s表示此进程是一个会话领导进程,+表示前台进程组

进程组:表示一组相互关联的进程,比如每个子进程都是父进程所在组成员
会话:共享同一个控制终端的一个或多个进程组,ssh登陆服务器,就会打开一个控制终端,这个终端就对应一个会话,在终端运行的命令及其它们的子进程,就构成一个个进程组,后台运行的命令,构成后台进程组,在前台运行的命令,构成前台进程组

运行top命令,按1,切换显示所以cpu使用情况

top - 17:32:57 up 12:39,  3 users,  load average: 2.65, 2.45, 1.63
Tasks: 537 total,   1 running,  96 sleeping,   0 stopped, 348 zombie
%Cpu0  :  0.3 us, 23.4 sy,  0.0 ni, 34.4 id, 41.8 wa,  0.0 hi,  0.0 si,  0.0 st
%Cpu1  :  0.3 us, 18.3 sy,  0.0 ni, 42.2 id,  3.8 wa,  0.0 hi, 35.3 si,  0.0 st
KiB Mem :  2017512 total,   503812 free,   496220 used,  1017480 buff/cache
KiB Swap:  2047996 total,  2047472 free,      524 used.  1354576 avail Mem

   PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND
    16 root      20   0       0      0      0 S  28.9  0.0   2:08.95 ksoftirqd/1
  4452 root      20   0       0      0      0 Z  22.4  0.0   0:00.68 app
  4453 root      20   0       0      0      0 Z  21.4  0.0   0:00.65 app
  4330 root      20   0   43192   4264   3232 R   1.0  0.2   0:02.76 top
   983 root      20   0  191840  11500  10020 S   0.7  0.6   1:01.13 vmtoolsd
 32400 root      20   0       0      0      0 I   0.7  0.0   0:10.08 kworker/0:0
     8 root      20   0       0      0      0 I   0.3  0.0   0:18.87 rcu_sched

仔细观察top命令的输出结果,有以下几个特点:

  • load average 这个参数,1分钟,5分钟,15分钟的数据依次减小,说明平均负载正在升高,并且,1分钟内负载超过cpu个数2,说明系统可能出现了性能瓶颈

  • Tasks这一行,一个在运行,但僵尸进程很多,并且在不断增加,说明子进程退出时,资源没被清理,产生大量僵尸进程

  • cpu使用率,不高,但是iowait稍高,好像有点不正常

  • 观察是否有处于D状态进程,由于本实验主机采用了ssd硬盘,出现iowait可能性不大,如果用机械硬盘,会有处于D状态进程,这一般是在等待io

  • 问题汇总一下:
    1.iowait高,导致平均负载高,甚至超过了cpu个数
    2.僵尸进程不断增多,说明没有正确清理子进程资源

问题处理

因为机器配置原因,可能iowait没达到理想效果,故在此仅说一下处理思路问题
1.使用dstat观察cpu和io情况,一般wai高,磁盘read会很大,说明wai高跟磁盘读请求有关
2.使用top观察处于D状态的进程,并找出这些进程的pid
3.使用pidstat -d 1 3 命令查看输出结果,观察一会,一般会找到问题进程

进程要访问磁盘,就要使用系统调用,为找到问题根源,就需要使用strace这种跟踪系统调用的工具

strace -p pid  

运行此命令可能会报错,因为问题进程app已经处于Z状态,表示已经退出了,只不过处于僵尸态,故此会报错,但问题追踪还得继续,可以使用perf top ,perf record, perf report命令进行下一步操作,一般会找到问题根源

僵尸进程处理

  • 此处说一下处理思路,出现僵尸进程,一般是要找出其父进程,然后在父进程中解决
    • 找到父进程,一般使用pstree命令
      pstree -a -p -s <pid>
      
  - 查看父进程程序代码里面,对子进程结束的处理是否正确,如有问题,进行更正极客解决

**总结**

- iowait高不代表io有性能瓶颈
- 系统中只有io类型的进程运行时,iowait也会很高,但实际上,磁盘的读写远远没有达到性能瓶颈的程度
- 碰到iowait高,先用dstat,pidstat确认是不是磁盘io问题,,然后找出导致问题出现的进程
- 等待io进程一般是不可中断状态,可以用ps命令找到D状态的进程,此进程为可疑进程,在本案例中,io操作后,进程变成了僵尸进程,所以不能用strace直接分析,这种情况,我们用了perf工具,逐步发现了问题所在
- 僵尸进程的排查,使用pstree找出父进程,去看父进程代码,去寻找问题所在






文章作者: BY 木易杨
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 BY 木易杨 !
评论
 上一篇
mysql技术内幕之文件 mysql技术内幕之文件
文件1.1 日志文件 错误日志 位置查看:show variables like ‘log_error’ 默认文件名是当前服务器主机名.err 二进制日志 记录了对数据库进行更改的所有操作,若操作本身没导致数据变化,也会写入二进制日志
2020-05-26 BY 木易杨
下一篇 
Linux系统优化之四:cpu使用率高,为啥找不到元凶? Linux系统优化之四:cpu使用率高,为啥找不到元凶?
当你发现系统cpu使用率很高的时候,不一定能找到相对应的高cpu使用率进程,本文就是讨论这样问题的,以一个实例逐步分析,给出解决思路 案例实验环境说明 以nginx+php服务为例,使用docker跑对应的服务 案例操作及分析过程#
2020-04-26 BY 木易杨