转载一同事的博文。
总结1 :尽量避免使用 killall、pgrep 、ps | xargs kill 的方式
总计2 :尽量使用 pidof 或者 pidof | xargs kill 的组合来代替上面的几个命令
平常大家 kill 进程,可能习惯使用如下的方式
1
|
killall bt_uinfo_memcached
|
1
|
pkill bt_uinfo_memcached
|
1
|
ps
-C bt_uinfo_memcached --
format
=\'pid\' --noheaders |
xargs
kill
|
大部分情况下这个都是可以正常工作的,但我们来看一下下面的这个命令
1
2
3
4
5
6
|
root@ubuntu:~
# ps -ef |grep bt_uinfo_memcached
root 8765 23103 0 14:13 pts
/2
00:00:00
grep
--color=auto bt_uinfo_memcached
root 26195 1 0 12:43 ? 00:00:32 .
/bt_uinfo_memcached
-p 20211 -u root -l 0.0.0.0 -m 3072 -d
root 26236 1 0 12:43 ? 00:00:30 .
/bt_uinfo_memcached
-p 20311 -u root -l 0.0.0.0 -m 3072 -d
root 26586 1 1 12:43 ? 00:01:15 .
/bt_uinfo_memcached
-p 20411 -u root -l 0.0.0.0 -m 3072 -d
root@ubuntu:~
#
|
1
2
3
|
root@ubuntu:~
# killall bt_uinfo_memcached
bt_uinfo_memcached: no process found
root@ubuntu:~
#
|
killall 命令竟然找不到 bt_uinfo_memcached 进程? 上面 ps 命令是列出来了的 。换 pkill 试试,还是不行
1
2
3
4
5
6
7
8
|
root@ubuntu:~
# pkill bt_uinfo_memcached
root@ubuntu:~
#
root@ubuntu:~
# ps -ef |grep bt_uinfo_memcached
root 17723 23103 0 14:19 pts
/2
00:00:00
grep
--color=auto bt_uinfo_memcached
root 26195 1 0 12:43 ? 00:00:36 .
/bt_uinfo_memcached
-p 20211 -u root -l 0.0.0.0 -m 3072 -d
root 26236 1 0 12:43 ? 00:00:34 .
/bt_uinfo_memcached
-p 20311 -u root -l 0.0.0.0 -m 3072 -d
root 26586 1 1 12:43 ? 00:01:22 .
/bt_uinfo_memcached
-p 20411 -u root -l 0.0.0.0 -m 3072 -d
root@ubuntu:~
#
|
甚至连 ps 也有问题,当 -C(command) 选项的参数值超过15个字符时,实际上是会匹配到其他的进程
1
2
3
4
5
6
7
8
9
10
11
|
linbobo@ubuntu:~$
ps
-C bt_uinfo_memcachecd
PID TTY TIME CMD
26195 ? 00:01:44 bt_uinfo_memcac
26236 ? 00:01:41 bt_uinfo_memcac
26586 ? 00:03:23 bt_uinfo_memcac
linbobo@ubuntu:~$
ps
-C bt_uinfo_memcachecd123456
PID TTY TIME CMD
26195 ? 00:01:44 bt_uinfo_memcac
26236 ? 00:01:41 bt_uinfo_memcac
26586 ? 00:03:23 bt_uinfo_memcac
linbobo@ubuntu:~$
|
为什么会这样呢? 通过 strace 命令可以找到原因
1
2
3
4
5
6
7
8
9
10
11
12
|
root@ubuntu:~
# strace -e trace=file pkill bt_uinfo_memcached 2>&1 | grep open | tail
open
(
"/proc/31713/status"
, O_RDONLY) = 4
open
(
"/proc/31713/cmdline"
, O_RDONLY) = 4
open
(
"/proc/31716/status"
, O_RDONLY) = 4
open
(
"/proc/31716/cmdline"
, O_RDONLY) = 4
open
(
"/proc/31717/status"
, O_RDONLY) = 4
open
(
"/proc/31717/cmdline"
, O_RDONLY) = 4
open
(
"/proc/31720/status"
, O_RDONLY) = 4
open
(
"/proc/31720/cmdline"
, O_RDONLY) = 4
open
(
"/proc/31721/status"
, O_RDONLY) = 4
open
(
"/proc/31721/cmdline"
, O_RDONLY) = 4
root@ubuntu:~
#
|
pkill 命令检查的是 /proc/ 下面的 pid 目录的 cmdline 文件和 status 文件。我们找其中一个 bt_uinfo_memcached 进程 ( 26195 ) 看一下,
1
2
3
4
5
6
7
|
root@ubuntu:~
# cat /proc/26195/cmdline | tr \'\0\' \' \'
.
/bt_uinfo_memcached
-p 20211 -u root -l 0.0.0.0 -m 3072 -d root@ubuntu:~
#
root@ubuntu:~
#
root@ubuntu:~
# cat /proc/26195/status | tr \'\0\' \' \'
Name: bt_uinfo_memcac
State: S (sleeping)
.....
|
可以看到 cmdline 是记录完整命令行的 (pgrep 默认是部分匹配),而 status 这个文件里面的 Name 字段的值是 bt_uinfo_memcac 而不是 bt_uinfo_memcached ,也就是被截断了(15个字符,OS 的限制) !!!
虽然 cmdline 文件里面记录的命令是正确的,但我估计 pgrep 会对比 cmdline 第一个字段和 status 文件的 Name 字段的值是否相同,如果不同则跳过,所以虽然 cmdline 是对的,但 pkill 并不杀死该进程
下面再来看 killall 命令的
1
2
3
4
5
6
7
8
9
10
11
12
|
linbobo@ubuntu:~$
strace
-e trace=
file
killall bt_uinfo_memcached 2>&1 |
grep
open
|
tail
open
(
"/proc/31705/stat"
, O_RDONLY) = 3
open
(
"/proc/31708/stat"
, O_RDONLY) = 3
open
(
"/proc/31709/stat"
, O_RDONLY) = 3
open
(
"/proc/31712/stat"
, O_RDONLY) = 3
open
(
"/proc/31713/stat"
, O_RDONLY) = 3
open
(
"/proc/31716/stat"
, O_RDONLY) = 3
open
(
"/proc/31717/stat"
, O_RDONLY) = 3
open
(
"/proc/31720/stat"
, O_RDONLY) = 3
open
(
"/proc/31721/stat"
, O_RDONLY) = 3
open
(
"/proc/32553/stat"
, O_RDONLY) = 3
linbobo@ubuntu:~$
|
killall 命令跟 pkill(pgrep) 不同,它查看的不是 /proc/pid/{cmdline,status} 文件,而是另外一个文件 /proc/pid/stat ,这个文件的内容
1
2
3
4
|
linbobo@ubuntu:~$
cat
/proc/26195/stat
26195 (bt_uinfo_memcac) S 1 26195 26195 0 -1 4202560 42735 0 0 0 3517 5339 0 0 20 0 6 0 293270594 475316224
36956 18446744073709551615 1 1 0 0 0 0 0 4097 2 18446744073709551615 0 0 17 9 0 0 0 0 0
linbobo@ubuntu:~$
|
可以看到也是一样被截断了,所以 killall 没杀死进程就是这个导致的。
把 killall 和 pkill 命令改为下面就可以了
1
2
3
4
5
|
linbobo@ubuntu:~$ pgrep bt_uinfo_memcac
26195
26236
26586
linbobo@ubuntu:~$
|
既然如此,那么有没有 可靠一点的命令呢? 有,那就是 pidof 命令 。pidof 命令除了查找 cmdline 和 stat 文件外,还查找了 /proc/pid/exe 这个symbol link
所以对于那些二进制名超过 15 个字符,甚至启动后改名的都可以找到, 最常见就是 myshard 的东东
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
open
(
"26195/stat"
, O_RDONLY) = 4
fstat(4, {st_mode=S_IFREG|0444, st_size=0, ...}) = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f1c95e9d000
read
(4,
"26195 (bt_uinfo_memcac) S 1 2619"
..., 1024) = 251
close(4) = 0
munmap(0x7f1c95e9d000, 4096) = 0
open
(
"26195/cmdline"
, O_RDONLY) = 4
fstat(4, {st_mode=S_IFREG|0444, st_size=0, ...}) = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f1c95e9d000
read
(4,
"./bt_uinfo_memcached\0-p\00020211\0-u"
..., 1024) = 60
close(4) = 0
munmap(0x7f1c95e9d000, 4096) = 0
stat(
"/proc/26195/exe"
, {st_mode=S_IFREG|0755, st_size=325966, ...}) = 0
open
(
"26236/stat"
, O_RDONLY) = 4
fstat(4, {st_mode=S_IFREG|0444, st_size=0, ...}) = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f1c95e9d000
read
(4,
"26236 (bt_uinfo_memcac) S 1 2623"
..., 1024) = 250
close(4)
|
1
2
3
4
5
6
7
8
9
|
linbobo@ubuntu:~$
ps
-ef |
grep
shard
linbobo 9741 9722 0 14:59 pts
/0
00:00:00
grep
--color=auto shard
root 27628 1 0 May02 ? 00:27:09 .
/shard_2013_115_d
root 27732 1 0 May02 ? 00:16:17 .
/shard_2013_116_d
linbobo@ubuntu:~$ pidof shard_2013_115_d
27628
linbobo@ubuntu:~$
sudo
ls
-l
/proc/27628/exe
lrwxrwxrwx 1 root root 0 2013-05-29 16:00
/proc/27628/exe
->
/home/dspeak/myshard/2013/room_1_0/bin/shard_d
linbobo@ubuntu:~$
|