07.应对系统中出现大量不可中断进程和僵尸进程

上一篇,用一个 Nginx+PHP 的案例,给你讲了服务器 CPU 使用率高的分析和应对方法。这里一定要记得,当碰到无法解释的 CPU 使用率问题时,先要检查一下是不是短时应用在捣 鬼。 短时应用的运行时间比较短,很难在 top 或者 ps 这类展示系统概要和进程快照的工具中发现, 你需要使用记录事件的工具来配合诊断,比如 execsnoop 或者 perf top

这些思路你不用刻意去背,多练习几次,多在操作中思考,你便能灵活运用。

另外,我们还讲到 CPU 使用率的类型。除了上一节提到的用户 CPU 之外,它还包括系统 CPU(比如上下文切换)、等待 I/O 的 CPU(比如等待磁盘的响应)以及中断 CPU(包括软中 断和硬中断)等。

我们已经在上下文切换的文章中,一起分析了系统 CPU 使用率高的问题,剩下的等待 I/O 的 CPU 使用率(以下简称为 iowait)升高,也是最常见的一个服务器性能问题。

我们来看 一个多进程 I/O 的案例,并分析这种情况。

进程状态

当 iowait 升高时,进程很可能因为得不到硬件的响应,而长时间处于不可中断状态。从 ps 或 者 top 命令的输出中,你可以发现它们都处于 D 状态,也就是不可中断状态(Uninterruptible Sleep)。既然说到了进程的状态,进程有哪些状态你还记得吗?我们先来回顾一下。

top 和 ps 是最常用的查看进程状态的工具,我们就从 top 的输出开始。下面是一个 top 命令 输出的示例,S 列(也就是 Status 列)表示进程的状态。从这个示例里,你可以看到 R、D、 Z、S、I 等几个状态,它们分别是什么意思呢?

$ top
 PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
28961 root 20 0 43816 3148 4040 R 3.2 0.0 0:00.01 top
 620 root 20 0 37280 33676 908 D 0.3 0.4 0:00.01 app
 1 root 20 0 160072 9416 6752 S 0.0 0.1 0:37.64 systemd
 1896 root 20 0 0 0 0 Z 0.0 0.0 0:00.00 devapp
 2 root 20 0 0 0 0 S 0.0 0.0 0:00.10 kthreadd
 4 root 0 -20 0 0 0 I 0.0 0.0 0:00.00 kworker/0:0H
 6 root 0 -20 0 0 0 I 0.0 0.0 0:00.00 mm_percpu_wq
 7 root 20 0 0 0 0 S 0.0 0.0 0:06.37 ksoftirqd/0

我们挨个来看一下:

  • R 是 Running 或 Runnable 的缩写,表示进程在 CPU 的就绪队列中,正在运行或者正在等 待运行。
  • D 是 Disk Sleep 的缩写,也就是不可中断状态睡眠(Uninterruptible Sleep),一般表示 进程正在跟硬件交互,并且交互过程不允许被其他进程或中断打断。
  • Z 是 Zombie 的缩写,如果你玩过“植物大战僵尸”这款游戏,应该知道它的意思。它表示 僵尸进程,也就是进程实际上已经结束了,但是父进程还没有回收它的资源(比如进 程的描 述符、PID 等)。
  • S 是 Interruptible Sleep 的缩写,也就是可中断状态睡眠,表示进程因为等待某个事件而被 系统挂起。当进程等待的事件发生时,它会被唤醒并进入 R 状态。
  • I 是 Idle 的缩写,也就是空闲状态,用在不可中断睡眠的内核线程上。前面说了,硬件交互 导致的不可中断进程用 D 表示,但对某些内核线程来说,它们有可能实际上并没有任何负载,用 Idle 正是为了区分这种情况。要注意,D 状态的进程会导致平均负载升高, I 状态的 进程却不会。

当然了,上面的示例并没有包括进程的所有状态。除了以上 5 个状态,进程还包括下面这 2 个 状态。

第一个是 T 或者 t,也就是 Stopped 或 Traced 的缩写,表示进程处于暂停或者跟踪状态。

向一个进程发送 SIGSTOP 信号,它就会因响应这个信号变成暂停状态(Stopped);再向它发 送 SIGCONT 信号,进程又会恢复运行(如果进程是终端里直接启动的,则需要你用 fg 命令, 恢复到前台运行)。

而当你用调试器(如 gdb)调试一个进程时,在使用断点中断进程后,进程就会变成跟踪状 态,这其实也是一种特殊的暂停状态,只不过你可以用调试器来跟踪并按需要控制进程的运行。

另一个是 X,也就是 Dead 的缩写,表示进程已经消亡,所以你不会在 top 或者 ps 命令中看到 它。

了解了这些,我们再回到今天的主题。先看不可中断状态,这其实是为了保证进程数据与硬件状 态一致,并且正常情况下,不可中断状态在很短时间内就会结束。所以,短时的不可中断状态进 程,我们一般可以忽略。

但如果系统或硬件发生了故障,进程可能会在不可中断状态保持很久,甚至导致系统中出现大量 不可中断进程。这时,你就得注意下,系统是不是出现了 I/O 等性能问题。

再看僵尸进程,这是多进程应用很容易碰到的问题。正常情况下,当一个进程创建了子进程后, 它应该通过系统调用 wait() 或者 waitpid() 等待子进程结束,回收子进程的资源;而子进程在结 束时,会向它的父进程发送 SIGCHLD 信号,所以,父进程还可以注册 SIGCHLD 信号的处理函 数,异步回收资源。

如果父进程没这么做,或是子进程执行太快,父进程还没来得及处理子进程状态,子进程就已经 提前退出,那这时的子进程就会变成僵尸进程。换句话说,父亲应该一直对儿子负责,善始善 终,如果不作为或者跟不上,都会导致“问题少年”的出现。

通常,僵尸进程持续的时间都比较短,在父进程回收它的资源后就会消亡;或者在父进程退出 后,由 init 进程回收后也会消亡。

一旦父进程没有处理子进程的终止,还一直保持运行状态,那么子进程就会一直处于僵尸状态。 大量的僵尸进程会用尽 PID 进程号,导致新进程不能创建,所以这种情况一定要避免。

案例分析

接下来,将用一个多进程应用的案例,分析大量不可中断状态和僵尸状态进程的问题。这 个应用基于 C 开发,由于它的编译和运行步骤比较麻烦,把它打包成了一个 Docker 镜像。 这样,你只需要运行一个 Docker 容器就可以得到模拟环境。

你的准备

下面的案例仍然基于 Ubuntu 18.04,同样适用于其他的 Linux 系统。我使用的案例环境如下所 示:

  • 机器配置:2 CPU,8GB 内存
  • 预先安装 docker、sysstat、dstat 等工具,如 apt install docker.io dstat sysstat

这里,dstat 是一个新的性能工具,它吸收了 vmstat、iostat、ifstat 等几种工具的优点,可以同时观察系统的 CPU、磁盘 I/O、网络以及内存使用情况。

接下来,我们打开一个终端,SSH 登录到机器上,并安装上述工具。

注意,以下所有命令都默认以 root 用户运行,如果你用普通用户身份登陆系统,请运行 sudo su root 命令切换到 root 用户。 如果安装过程有问题,你可以先上网搜索解决,实在解决不了的,记得在留言区向我提问。

温馨提示:案例应用的核心代码逻辑比较简单,你可能一眼就能看出问题,但实际 生产环境中的源码就复杂多了。所以,我依旧建议,操作之前别看源码,避免先入 为主,而           要把它当成一个黑盒来分析,这样你可以更好地根据现象分析问题。你姑 且当成你工作中的一次演练,这样效果更佳。

操作和分析

安装完成后,我们首先执行下面的命令运行案例应用:

$ docker run --privileged --name=app -itd feisky/app:iowait

然后,输入 ps 命令,确认案例应用已正常启动。如果一切正常,你应该可以看到如下所示的输 出:

$ ps aux | grep /approot 4009 0.0 0.0 4376 1008 pts/0 Ss+ 05:51 0:00 /app
root 4287 0.6 0.4 37280 33660 pts/0 D+ 05:54 0:00 /app
root 4288 0.6 0.4 37280 33668 pts/0 D+ 05:54 0:00 /app

从这个界面,我们可以发现多个 app 进程已经启动,并且它们的状态分别是 Ss+ 和 D+。其 中,S 表示可中断睡眠状态,D 表示不可中断睡眠状态,我们在前面刚学过,那后面的 s 和 + 是什么意思呢?不知道也没关系,查一下 man ps 就可以。现在记住,s 表示这个进程是一个会 话的领导进程,而 + 表示前台进程组。

这里又出现了两个新概念,进程组会话。它们用来管理一组相互关联的进程,意思其实很好理 解。

  • 进程组表示一组相互关联的进程,比如每个子进程都是父进程所在组的成员;
  • 而会话是指共享同一个控制终端的一个或多个进程组。

比如,我们通过 SSH 登录服务器,就会打开一个控制终端(TTY),这个控制终端就对应一个 会话。而我们在终端中运行的命令以及它们的子进程,就构成了一个个的进程组,其中,在后台 运行的命令,构成后台进程组;在前台运行的命令,构成前台进程组。

明白了这些,我们再用 top 看一下系统的资源使用情况:

# 按下数字 1 切换到所有 CPU 的使用情况,观察一会儿按 Ctrl+C 结束
$ top
top - 05:56:23 up 17 days, 16:45, 2 users, load average: 2.00, 1.68, 1.39
Tasks: 247 total, 1 running, 79 sleeping, 0 stopped, 115 zombie
%Cpu0 : 0.0 us, 0.7 sy, 0.0 ni, 38.9 id, 60.5 wa, 0.0 hi, 0.0 si, 0.0 st
%Cpu1 : 0.0 us, 0.7 sy, 0.0 ni, 4.7 id, 94.6 wa, 0.0 hi, 0.0 si, 0.0 st
...
 PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
 4340 root 20 0 44676 4048 3432 R 0.3 0.0 0:00.05 top
 4345 root 20 0 37280 33624 860 D 0.3 0.0 0:00.01 app
 4344 root 20 0 37280 33624 860 D 0.3 0.4 0:00.01 app
 1 root 20 0 160072 9416 6752 S 0.0 0.1 0:38.59 systemd
...

从这里你能看出什么问题吗?细心一点,逐行观察,别放过任何一个地方。忘了哪行参数意思的 话,也要及时返回去复习。

好的,如果你已经有了答案,那就继续往下走,看看跟我找的问题是否一样。这里,我发现了四 个可疑的地方。

  • 先看第一行的平均负载( Load Average),过去 1 分钟、5 分钟和 15 分钟内的平均负载在 依次减小,说明平均负载正在升高;而 1 分钟内的平均负载已经达到系统的 CPU 个数,说 明系统很可能已经有了性能瓶颈。
  • 再看第二行的 Tasks,有 1 个正在运行的进程,但僵尸进程比较多,而且还在不停增加,说 明有子进程在退出时没被清理。
  • 接下来看两个 CPU 的使用率情况,用户 CPU 和系统 CPU 都不高,但 iowait 分别是 60.5% 和 94.6%,好像有点儿不正常。
  • 最后再看每个进程的情况, CPU 使用率最高的进程只有 0.3%,看起来并不高;但有两个进 程处于 D 状态,它们可能在等待 I/O,但光凭这里并不能确定是它们导致了 iowait 升高。

我们把这四个问题再汇总一下,就可以得到很明确的两点:

第一点,iowait 太高了,导致系统的平均负载升高,甚至达到了系统 CPU 的个数。

第二点,僵尸进程在不断增多,说明有程序没能正确清理子进程的资源。

那么,碰到这两个问题该怎么办呢?结合我们前面分析问题的思路,你先自己想想,动手试试, 下节课我来继续“分解”。

小结

今天我们主要通过简单的操作,熟悉了几个必备的进程状态。用我们最熟悉的 ps 或者 top ,可 以查看进程的状态,这些状态包括运行(R)、空闲(I)、不可中断睡眠(D)、可中断睡眠 (S)、僵尸(Z)以及暂停(T)等。

其中,不可中断状态和僵尸状态,是我们今天学习的重点。

  • 不可中断状态,表示进程正在跟硬件交互,为了保护进程数据和硬件的一致性,系统不允许 其他进程或中断打断这个进程。进程长时间处于不可中断状态,通常表示系统有 I/O 性能问 题。
  • 僵尸进程表示进程已经退出,但它的父进程还没有回收子进程占用的资源。短暂的僵尸状态 我们通常不必理会,但进程长时间处于僵尸状态,就应该注意了,可能有应用程序没有正常 处理子进程的退出。

思考

最后,思考课题,案例中发现的这两个问题,会怎么分析呢?又应该怎么解决呢?

原文地址:https://www.cnblogs.com/LHXW/p/10084388.html

时间: 12-07

07.应对系统中出现大量不可中断进程和僵尸进程的相关文章

Linux系统编程——特殊进程之僵尸进程

僵尸进程(Zombie Process) 进程已执行结束,但进程的占用的资源未被回收.这种进程称为僵尸进程. 在每一个进程退出的时候,内核释放该进程全部的资源.包含打开的文件.占用的内存等. 可是仍然为其保留一定的信息,这些信息主要主要指进程控制块的信息(包含进程号.退出状态.执行时间等).直到父进程通过 wait() 或 waitpid() 来获取其状态并释放(详细使用方法,请看<等待进程结束>). 这样就会导致一个问题,假设进程不调用wait() 或 waitpid() 的话, 那么保留的

一起聊聊 Linux 系统中的僵尸进程

Linux 系统中僵尸进程和现实中僵尸(虽然我也没见过)类似,虽然已经死了,但是由于没人给它们收尸,还能四处走动.僵尸进程指的是那些虽然已经终止的进程,但仍然保留一些信息,等待其父进程为其收尸.僵尸进程如何产生的?如果一个进程在其终止的时候,自己就回收所有分配给它的资源,系统就不会产生所谓的僵尸进程了.那么我们说一个进程终止之后,还保留哪些信息?为什么终止之后还需要保留这些信息呢?一个进程终止的方法很多,进程终止后有些信息对于父进程和内核还是很有用的,例如进程的ID号.进程的退出状态.进程运行的

Linux中的僵尸进程和孤儿进程

在UNIX里,除了进程0(即PID=0的交换进程,Swapper Process)以外的所有进程都是由其他进程使用系统调用fork创建的,这里调用fork创建新进程的进程即为父进程,而相对应的为其创建出的进程则为子进程,因而除了进程0以外的进程都只有一个父进程,但一个进程可以有多个子进程.        操作系统内核以进程标识符(Process Identifier,即PID)来识别进程.进程0是系统引导时创建的一个特殊进程,在其调用fork创建出一个子进程(即PID=1的进程1,又称init)

理解Linux系统中的load average

理解Linux系统中的load average(图文版) 博客分类: Linux linux load nagios 一.什么是load average? linux系统中的Load对当前CPU工作量的度量 (WikiPedia: the system load is a measure of the amount of work that a computer system is doing).也有简单的说是进程队列的长度. Load Average 就是一段时间 (1 分钟.5分钟.15分钟

CentOS系统中与时间相关的几个命令

时间在任何系统里都是最基本的部分,必不可少.本文介绍CentOS系统中与时间的相关命令. 基本概念 硬件时钟(Hardware Clock) 硬件时钟,也叫实时时钟(RealTimeClock),或者BIOS时钟,或者CMOS时钟.它是位于机器主板上的实际硬件设备,一般靠电池维持运行.所以,即使机器关机,它也会一直保持记录当前时间,一般不是十分精确. 系统时间(System Time) 系统时间指的是操作系统中的时间.它是由系统加电后的硬件定时器驱动,Linux系统根据定时器信号来递增时间计数.

Mac OS X: 删除系统中的Grow!软件

系统版本和系统配置:  OS X Yosemite 10.10.4 故障现象:可能是由于安装过盗版软件,所以系统被安装了Grow!软件. 解决方法: 1.可能是由于安装过盗版软件,所以在"系统偏好设置"中发现,被安装了Grow!软件. 2.Grow!简介: 3.打开"Grow!"配置界面. 4.Grow!的通知栏效果预览 5.在"系统偏好设置"中,右击"Grow!",选择卸载,会弹出一个确认卸载的对话框. 6.确认卸载之后,G

rabbitmq在艺龙业务系统中的实践

rabbitmq作为成熟的企业消息中间件,实现了应用程序间接口调用的解耦,提高系统的吞吐量. 下面介绍下rabbitmq的一些基本概念: message acknowledgment: 消息确认,解决消息确认问题,只有收到ack之后才能从消息系统中删除. message durability: 消 息持久化,当rabbitmq退出或崩溃后,会把queue中的消息持久化.但注意,RabbitMQ并不能百分之百保证消息一定不会丢失,因为为了提 升性能,RabbitMQ会把消息暂存在内存缓存中,直到达

Linux系统中数据库启动和关闭&Basic SQL

第一步:使用oracle用户登录 第二步:在oracle用户下输入sqlplus /nolog 第三步:如需使用管理员权限,则输入connect /as sysdba 第四步:启动和关闭 startup startup nomount #只启动实例 startup mount   #打开控制文件 startup open    #打开数据文件和重做日志 shutdown shutdown normal        #不接受新的连接,需要等待所有的用户断开连接 shutdown immediat

(转载)windows8系统中使用hyper-v的时候配置网络方法

启用了虚拟机角色,您的物理设备就需要共享给所有的虚拟机(您的Windows 8也变成了虚拟机,因为它使用物理设备时也要通过虚拟化层,当然,只要能开启Hyper-v,就说明您的硬件支持虚拟化,换句话说,性能损失很低,所以,没必要为开启虚拟化而担心Windows 8性能受损.) 因为CPU.内存的分配都在虚拟机的设置里来调整的,所以,开始使用Hyper-v之前呢,需要考虑就是虚拟交换机啦,也就是将物理网卡变成一个虚拟交换机,然后虚拟一块网卡给物理机(刚刚都说过啦,您的Windows 8已经是一台虚拟

CentOS-6.4-DVD系统中安装Oracle-11.2.0.4

完整版见https://jadyer.github.io/2014/05/18/centos-install-oracle/ /** * CentOS-6.4-DVD系统中安装Oracle-11.2.0.4 * ---------------------------------------------------------------------------------------------------------------------- * [前言] * 本来是在CentOS-6.4-m