|
|
在维护服务器的时候,发现有多个nova-novncproxy的僵尸进程。9 O6 k, z- [0 t4 v
# q, j# E* [+ Q. |5 W8 h26327 ? S 0:05 \_ /usr/bin/python /usr/bin/nova-novncproxy --config-file=/etc/nova/nova.conf
; o5 V8 ]; A, R6 g1 ?, L 4765 ? Z 0:00 \_ [nova-novncproxy] <defunct>( B4 O, Z* C" ^) M G% {' Y
4766 ? Z 0:00 \_ [nova-novncproxy] <defunct>3 Y& p6 S3 y5 b( ^4 m
4767 ? Z 0:00 \_ [nova-novncproxy] <defunct>7 [6 c0 P3 T1 b) a* j7 B
4768 ? Z 0:00 \_ [nova-novncproxy] <defunct>: ^4 b1 d7 ]. t, k7 ^
4769 ? Z 0:00 \_ [nova-novncproxy] <defunct>
- E7 ]$ N& B: N6 u9 o( G0 Z之前对于僵尸进程的了解并不深,该如何处理。
; m5 X. b% G) c( [4 S
; }2 C; r* ]1 {) G& |0 W定义; s9 {! p9 Q& {; |. ~% e
0 d+ o. J1 R2 ?0 C3 M/ JIn UNIX System terminology, a process that has terminated,but whose parent has not yet waited for it, is called a zombie./ q. \/ }) X# U4 ~! A
* l( m- s% _! w% C' r$ z
在UNIX 系统中,一个进程结束了,但是他的父进程没有等待(调用wait / waitpid)他, 那么他将变成一个僵尸进程. 在fork()/execve()过程中,假设子进程结束时父进程仍存在,而父进程fork()之前既没安装SIGCHLD信号处理函数调用 waitpid()等待子进程结束,又没有显式忽略该信号,则子进程成为僵尸进程。
8 [% M! e3 ~" P {+ L4 H! v1 F6 E; q+ a( F
如何查看linux系统上的僵尸进程,如何统计有多少僵尸进程?
C9 H( A8 n, p# ~4 i
# d1 _- @' Y2 i- ^) u j6 D! Z0 Q/ q#ps -ef | grep defunct
8 J, B5 N4 s! O1 a: [9 H. v8 X# y5 o: @' Z4 b$ V4 b7 Y) [
或者查找状态为Z的进程,Z就是代表zombie process,僵尸进程的意思。
7 ^8 a& \9 F' N$ K- ?, k/ |
1 e' }, Q6 W2 H) p, ~4 ^另外使用top命令查看时有一栏为S,如果状态为Z说明它就是僵尸进程。
. v3 H: v8 C1 A7 _& h# M; A& ~3 t% |" J) |; M
Tasks: 95 total, 1 running, 94 sleeping, 0 stopped, 0 zombie
6 G% b1 z. ^0 V/ g, s* J; K$ F' q# S6 v! U9 B! }- O3 T1 W
top命令中也统计了僵尸进程。或者使用下面的命令:
6 E* t) Q, a. M h' a) |8 k4 v1 H0 ]: I& c5 T
ps -ef | grep defunct | grep -v grep | wc -l; k; \! f' x/ z) l1 D
) J$ d1 b' `9 C `* O* {; s
如何杀死僵尸进程呢?# \6 m5 |5 n/ A
一般僵尸进程很难直接kill掉,不过您可以kill僵尸爸爸。父进程死后,僵尸进程成为”孤儿进程”,过继给1号进程init,init始终会负责清理僵尸进程.它产生的所有僵尸进程也跟着消失。9 N$ @ d4 |# g% t @
0 x# a+ G# I5 z9 Y% ~4 Gps -e -o ppid,stat | grep Z | cut -d” ” -f2 | xargs kill -9: m! v$ P4 c* j2 d6 h
% F$ S0 X4 D, W, V" M. Y' r2 C
或) e$ A& h* b5 T0 m8 }7 B1 }
$ Z4 X& R3 m* W: x4 [
kill -HUP `ps -A -ostat,ppid | grep -e ’^[Zz]‘ | awk ’{print $2}’`5 @0 L1 G& b" a) n3 @4 O: [& u1 i4 S
1 z1 |( U& A/ J. T) g* z$ }7 P
当然您可以自己编写更好的shell脚本,欢迎与大家分享。 R9 S. W2 W' T' e! |; A, Z+ k
3 Y- u& v( n- s5 W2 _6 `( H! p
我将nova-novncproxy stop后再start,僵尸进程即消失,问题解决。
4 I- @9 n2 g* o1 s5 T' l, k1 P! l: B( C2 L3 x; W
另外子进程死后,会发送SIGCHLD信号给父进程,父进程收到此信号后,执行waitpid()函数为子进程收尸。就是基于这样的原理:就算父进程没有调用wait,内核也会向它发送SIGCHLD消息,而此时,尽管对它的默认处理是忽略,如果想响应这个消息,可以设置一个处理函数。
6 ^+ p9 F( W5 z
) t$ T, R2 f) m6 y# r3 Z* [! I如何避免僵尸进程呢?
7 X, o$ f$ j2 U9 r& g处理SIGCHLD信号并不是必须的。但对于某些进程,特别是服务器进程往往在请求到来时生成子进程处理请求。如果父进程不等待子进程结束,子进程将成为僵尸进程(zombie)从而占用系统资源。如果父进程等待子进程结束,将增加父进程的负担,影响服务器进程的并发性能。在Linux下 可以简单地将 SIGCHLD信号的操作设为SIG_IGN。
: } y- j$ X7 c/ p6 D5 V# R. gsignal(SIGCHLD,SIG_IGN);
4 V8 K9 {! W2 j! V: |这样,内核在子进程结束时不会产生僵尸进程。这一点与BSD4不同,BSD4下必须显式等待子进程结束才能释放僵尸进程0 q' X/ E7 ], [
2 T! Z" J6 G( Y9 e4 z
或者: x% D1 V2 X5 l' I
& e; [" o3 J- y+ G用两次fork(),而且使紧跟的子进程直接退出,是的孙子进程成为孤儿进程,从而init进程将负责清除这个孤儿进程。 |
|