其中一台 ubuntu 服务器有 82 个僵尸进程。所有进程都将“[sh] defunct”显示为进程命令。有没有办法找出哪个进程正在变成僵尸进程?
我尝试检查/proc/PID/
目录以获取有关僵尸进程的一些线索,但所有文件都是空的。如何找到谁让这个进程成为僵尸进程...还有其他方法可以查到吗?
更新/解决:使问题更清晰,并按照 andcoz 的建议回答了我自己的问题。
答案1
Linux 内核的审计子系统对于找出哪些进程正在变成僵尸进程非常有用。我刚刚遇到了以下情况:
server ~ # ps -ef --forest
[...]
root 16385 1 0 17:04 ? 00:00:00 /usr/sbin/apache2 -k start
root 16388 16385 0 17:04 ? 00:00:00 \_ /usr/bin/perl -T -CSDAL /usr/lib/iserv/apache_user
root 16389 16385 0 17:04 ? 00:00:00 \_ /usr/bin/perl -T -CSDAL /usr/lib/iserv/apache_user
www-data 16415 16385 0 17:04 ? 00:00:00 \_ /usr/sbin/apache2 -k start
www-data 18254 16415 0 17:23 ? 00:00:00 | \_ [sh] <defunct>
www-data 18347 16415 0 17:23 ? 00:00:00 | \_ [sh] <defunct>
www-data 22966 16415 0 18:18 ? 00:00:00 | \_ [sh] <defunct>
www-data 16583 16385 0 17:05 ? 00:00:01 \_ /usr/sbin/apache2 -k start
www-data 18306 16583 0 17:23 ? 00:00:00 | \_ [sh] <defunct>
www-data 18344 16583 0 17:23 ? 00:00:00 | \_ [sh] <defunct>
www-data 17561 16385 0 17:12 ? 00:00:00 \_ /usr/sbin/apache2 -k start
www-data 22983 17561 0 18:18 ? 00:00:00 | \_ [sh] <defunct>
www-data 18318 16385 0 17:23 ? 00:00:00 \_ /usr/sbin/apache2 -k start
www-data 19725 16385 0 17:43 ? 00:00:01 \_ /usr/sbin/apache2 -k start
www-data 22638 16385 0 18:13 ? 00:00:00 \_ /usr/sbin/apache2 -k start
www-data 22659 16385 0 18:14 ? 00:00:00 \_ /usr/sbin/apache2 -k start
www-data 25102 16385 0 18:41 ? 00:00:00 \_ /usr/sbin/apache2 -k start
www-data 25175 16385 0 18:42 ? 00:00:00 \_ /usr/sbin/apache2 -k start
www-data 25272 16385 0 18:44 ? 00:00:00 \_ /usr/sbin/apache2 -k start
这些僵尸进程的原因很可能是 PHP 脚本,但由于这些 Apache 子进程正在处理大量 HTTP 请求和大量不同的 PHP 脚本,因此很难找出哪个进程负责。 Linux 也已经释放了这些僵尸进程的重要信息,因此我们甚至不必/proc/<pid>/cmdline
弄清楚可能正在运行哪个脚本或-c
命令:/bin/sh
server ~ # cat /proc/18254/cmdline
server ~ #
为了弄清楚这一点,我安装了auditd
:https://linux-audit.com/configuring-and-auditing-linux-systems-with-audit-daemon/
我设置了以下审核规则:
auditctl -a always,exit -F arch=b32 -S execve -F path=/bin/dash
auditctl -a always,exit -F arch=b64 -S execve -F path=/bin/dash
这些规则审核/bin/dash
二进制文件的所有进程创建。/bin/sh
在这里不起作用,因为它是一个符号链接,并且审核显然只能看到目标文件名:
server ~ # ls -l /bin/sh
lrwxrwxrwx 1 root root 4 Nov 8 2014 /bin/sh -> dash*
一个简单的测试现在应该会生成审核日志/var/log/audit/audit.log
(我冒昧地添加了很多换行符以提高可读性):
server ~ # sh -c 'echo test'
test
server ~ # tail -f /var/log/audit/audit.log
[...]
type=SYSCALL msg=audit(1488219335.976:43871): arch=40000003 syscall=11 \
success=yes exit=0 a0=ffdca3ec a1=f7760e58 a2=ffdd399c a3=ffdca068 items=2 \
ppid=27771 pid=27800 auid=0 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 \
fsgid=0 tty=pts7 ses=7532 comm="sh" exe="/bin/dash" key=(null)
type=EXECVE msg=audit(1488219335.976:43871): argc=3 a0="sh" a1="-c" \
a2=6563686F2074657374
type=CWD msg=audit(1488219335.976:43871): \
cwd="/var/lib/iserv/remote-support/iserv-martin.von.wittich"
type=PATH msg=audit(1488219335.976:43871): item=0 name="/bin/sh" inode=10403900 \
dev=08:01 mode=0100755 ouid=0 ogid=0 rdev=00:00 nametype=NORMAL
type=PATH msg=audit(1488219335.976:43871): item=1 name=(null) inode=5345368 \
dev=08:01 mode=0100755 ouid=0 ogid=0 rdev=00:00 nametype=NORMAL
type=PROCTITLE msg=audit(1488219335.976:43871): \
proctitle=7368002D63006563686F2074657374
许多信息都经过编码,但ausearch
可以使用以下命令进行翻译-i
:
server ~ # ausearch -i -x /bin/dash | tail
[...]
----
type=PROCTITLE msg=audit(27.02.2017 19:15:35.976:43871) : proctitle=sh
type=PATH msg=audit(27.02.2017 19:15:35.976:43871) : item=1 name=(null) \
inode=5345368 dev=08:01 mode=file,755 ouid=root ogid=root rdev=00:00 \
nametype=NORMAL
type=PATH msg=audit(27.02.2017 19:15:35.976:43871) : item=0 name=/bin/sh \
inode=10403900 dev=08:01 mode=file,755 ouid=root ogid=root rdev=00:00 \
nametype=NORMAL
type=CWD msg=audit(27.02.2017 19:15:35.976:43871) : \
cwd=/var/lib/iserv/remote-support/iserv-martin.von.wittich
type=EXECVE msg=audit(27.02.2017 19:15:35.976:43871) : argc=3 a0=sh a1=-c \
a2=echo test
type=SYSCALL msg=audit(27.02.2017 19:15:35.976:43871) : arch=i386 \
syscall=execve success=yes exit=0 a0=0xffdca3ec a1=0xf7760e58 a2=0xffdd399c \
a3=0xffdca068 items=2 ppid=27771 pid=27800 auid=root uid=root gid=root \
euid=root suid=root fsuid=root egid=root sgid=root fsgid=root tty=pts7 \
ses=7532 comm=sh exe=/bin/dash key=(null)
----
如果您不想将ausearch
过滤限制为/bin/dash
,也可以使用ausearch -i -m ALL
翻译完整的日志。ausearch -i -p <PID of a zombie process>
在这种情况下,另一个好的过滤器是ausearch -i -p 27800
。
只需保留这些规则,直到出现新的僵尸进程,然后搜索僵尸 PID 的进程创建:
ausearch -i -p <PID>
这对于识别僵尸进程的根本原因应该非常有帮助。就我而言,它是一个 PHP 脚本,用于proc_open
生成 Perl 脚本,而无需使用proc_close
.
答案2
答案3
简短的回答是你不在乎。僵尸进程已死亡。对于进程表中的该条目,它所消耗的只是一小部分内核内存。
由于进程剩下的只是进程表条目,因此您几乎没有什么可继续的。僵尸进程是指其父进程尚未回收的死亡进程;查看进程的 PPID 以了解其父进程是谁。
答案4
ps auxf | grep --color -5 ' Z '
显示进程层次结构,包括僵尸及其父级识别僵尸脚本名称很困难,因为只有您看到“sh defunct”