はじめに
Linuxで特定のプロセスの問題調査によく使用するコマンドや方法を紹介します。
また、それぞれのコマンドの詳細な説明は他に譲り、ここではあくまで紹介にとどめます。
・ps
/ pstree
コマンド
非常に有名なコマンドですが、現在動いているプロセスを調べるにはps
コマンドを使用します。
また、ps
コマンドには色々なオプションがあり、特に問題点が見つけやすいaux
オプションをよく使用します。
aux
オプションはそれぞれ下記の意味を持ちます。
- a:端末操作のプロセスを表示
- u:CPUやメモリの情報を表示
- x:端末操作ではないプロセスを表示(デーモン/サービスなども表示されます)
$ ps aux
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.0 0.1 41688 5424 ? Ss 11月30 0:16 /usr/lib/systemd/systemd
root 2 0.0 0.0 0 0 ? S 11月30 0:00 [kthreadd]
root 3 0.0 0.0 0 0 ? I< 11月30 0:00 [rcu_gp]
・・・
また、プロセスの親子関係を見たい場合はf
オプションを追加したり、pstree
コマンドを使用するとツリー構造で表示されて便利です。
$ ps auxf
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 2 0.0 0.0 0 0 ? S 11月30 0:00 [kthreadd]
root 3 0.0 0.0 0 0 ? I< 11月30 0:00 \_ [rcu_gp]
・・・
root 2294 0.0 0.1 110840 7320 ? Ss 11月30 0:00 /usr/sbin/sshd -D
root 29659 0.0 0.2 148512 8672 ? Ss 11:29 0:00 \_ sshd: user [priv]
user 29676 0.0 0.1 148512 4432 ? S 11:29 0:00 \_ sshd: user@pts/0
user 29677 0.0 0.1 124872 4132 pts/0 Ss 11:29 0:00 \_ -bash
user 29727 0.0 0.1 162464 4020 pts/0 R+ 11:39 0:00 \_ ps auxf
・・・
$ pstree -aup 2294
sshd,2294 -D
└─sshd,29659
└─sshd,29676,user
└─bash,29677
└─pstree,29841 -aup 2294
ps
コマンドではコマンドなどの文字列が長い場合に途中で文字列が切れてしまう場合がありますが、そういう場合はww
オプションを追加してあげると切れてしまった部分も表示されます。
また、ps
コマンドはプロセスを探すためにgrep
コマンドと組み合わせる場合も多いと思いますが、その際はgrep -e ^U -e [先頭文字]残り文字列
を使用すると、ヘッダーを表示しつつps
コマンドのプロセスを表示せずにキレイに表示できます。
$ ps aux | grep -e ^U -e [s]shd
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 2294 0.0 0.1 110840 7320 ? Ss 11月30 0:00 /usr/sbin/sshd -D
root 29659 0.0 0.2 148512 8672 ? Ss 11:29 0:00 sshd: user [priv]
user 29676 0.0 0.1 148512 4432 ? S 11:29 0:00 sshd: user@pts/0
$
grep
コマンドと同様に、特定の複数のプロセスのメモリ使用量の合計を調べたい時などにawk
コマンドと組み合わせる場合もあると思いますが、こちらも[先頭文字]残り文字列
で該当プロセスを絞ってあげるとps
コマンドのプロセスを含まない正確な合計値が集計できます。
$ ps aux | awk '/[s]shd/{sum+=$6}END{print sum}'
20424
$
・top
/ htop
コマンド
ps
コマンドは他のコマンドと組み合わせる際によく使用するコマンドですが、全体的にザックリ現在プロセスがどんな状況なのか確認するにはtop
やhtop
をよく使用します。
$ top
top - 11:38:19 up 1 days, 8:01, 1 user, load average: 0.00, 0.00, 0.00
Tasks: 41 total, 1 running, 22 sleeping, 0 stopped, 0 zombie
%Cpu(s): 0.0 us, 0.0 sy, 0.0 ni,100.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
KiB Mem : 3956464 total, 3259792 free, 109392 used, 587280 buff/cache
KiB Swap: 0 total, 0 free, 0 used. 3621688 avail Mem
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 30000 user 20 0 168840 4412 3884 R 0.3 0.1 0:00.05 top
1 root 20 0 41688 5424 3816 S 0.0 0.1 0:16.30 systemd
2 root 20 0 0 0 0 S 0.0 0.0 0:00.17 kthreadd
3 root 0 -20 0 0 0 I 0.0 0.0 0:00.00 rcu_gp
$
top
コマンド実行中は入力を受け付けており、その中でもL
(文字列検索)、P
(CPU使用順でソート)、M
(メモリ使用順にソート)をよく使用します。h
を入力するとヘルプが出てくるので、興味のある方はそちらを参照してください。
また、top
コマンドを拡張したhtop
というコマンドがあります。見た目もグラフィカルで見やすく、マウスや十字キーで画面スクロールやプロセスの選択(!)ができ、top
コマンドでできることは大抵できる優れモノです。
ただ、top
コマンドのようにデフォルトで入っていない事が多いため追加インストールが必要、メモリやCPUリソースを多く取るなどの欠点もあります。
・lsof
コマンド
ps
コマンドやtop
コマンドなどで調査対象のプロセスが分かった後に、該当プロセスが掴んでいるファイルやポートを調べる場合にlsof
コマンドをよく使用します。
$ sudo lsof -p 29659
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
sshd 29659 root cwd DIR 259,1 302 96 /
sshd 29659 root rtd DIR 259,1 302 96 /
sshd 29659 root txt REG 259,1 832328 13021527 /usr/sbin/sshd
sshd 29659 root mem REG 259,1 15408 12864569 /usr/xxx/xxx/xxx.so
・・・
sshd 29659 root 3u IPv4 658172 0t0 TCP ip-xxx-xxx-xxx-xxx:ssh->ip-xxx-xxx-xxx-xxx:48183 (ESTABLISHED)
sshd 29659 root 4u unix 0xffffa0d25215d800 0t0 658603 socket
sshd 29659 root 6w FIFO 0,23 0t0 72119 /run/systemd/sessions/2604.ref
sshd 29659 root 7u unix 0xffffa0d25207dc00 0t0 658237 socket
また、ロックファイルなどのファイルを現在どのプロセスが掴んでいるか調べる事もできるので、比較的使用頻度の高いコマンドになります。
$ sudo lsof /usr/sbin/sshd
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
sshd 2294 root txt REG 259,1 832328 13021527 /usr/sbin/sshd
sshd 29659 root txt REG 259,1 832328 13021527 /usr/sbin/sshd
sshd 29676 user txt REG 259,1 832328 13021527 /usr/sbin/sshd
sshd 30036 root txt REG 259,1 832328 13021527 /usr/sbin/sshd
sshd 30053 user txt REG 259,1 832328 13021527 /usr/sbin/sshd
$
ps
コマンドなどでプロセスを特定した後にタイムラグなくlsof
コマンドで確認したい場合は、プロセスIDを特定する事に特化したpidof
コマンドやpgrep
コマンドなどを使用するとスッキリ記述する事ができます。
$ sudo lsof -p $(pidof rpcbind)
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
rpcbind 1809 rpc cwd DIR 259,1 302 96 /
rpcbind 1809 rpc rtd DIR 259,1 302 96 /
rpcbind 1809 rpc txt REG 259,1 61432 12997494 /usr/sbin/rpcbind
・・・
$ pgrep sshd | sed 's/^/echo "---";sudo lsof -p/e'
---
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
sshd 2294 root cwd DIR 259,1 302 96 /
sshd 2294 root rtd DIR 259,1 302 96 /
sshd 2294 root txt REG 259,1 832328 13021527 /usr/sbin/sshd
・・・
---
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
sshd 29659 root cwd DIR 259,1 302 96 /
sshd 29659 root rtd DIR 259,1 302 96 /
sshd 29659 root txt REG 259,1 832328 13021527 /usr/sbin/sshd
・・・
---
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
sshd 29676 user cwd DIR 259,1 302 96 /
sshd 29676 user rtd DIR 259,1 302 96 /
sshd 29676 user txt REG 259,1 832328 13021527 /usr/sbin/sshd
・・・
---
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
sshd 30036 root cwd DIR 259,1 302 96 /
sshd 30036 root rtd DIR 259,1 302 96 /
sshd 30036 root txt REG 259,1 832328 13021527 /usr/sbin/sshd
・・・
---
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
sshd 30053 user cwd DIR 259,1 302 96 /
sshd 30053 user rtd DIR 259,1 302 96 /
sshd 30053 user txt REG 259,1 832328 13021527 /usr/sbin/sshd
・・・
$
・/proc/(プロセスID)/
ディレクトリ
lsof
コマンドでファイルやポートを調べる事もできますが、ザックリこのプロセス何やっているのか調べる場合は/proc/(プロセスID)/
ディレクトリを確認する方が手っ取り早い場合があります。
/proc/(プロセスID)/
ディレクトリにはプロセスに関する多くの情報が格納されていますが、その中でも使用頻度が高い確認方法を紹介します。
$ sudo ls -l /proc/2294/exe
lrwxrwxrwx 1 root root 0 11月 30 03:27 /proc/2294/exe -> /usr/sbin/sshd
$ sudo cat /proc/2294/cmdline
/usr/sbin/sshd-D$
$ sudo cat /proc/2294/environ
LANG=en_US.UTF-8PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/binNOTIFY_SOCKET=/run/systemd/notifySSH_USE_STRONG_RNG=0$
$ sudo cat /proc/2294/status
Name: sshd
Umask: 0022
State: S (sleeping)
Tgid: 2294
Ngid: 0
Pid: 2294
PPid: 1
TracerPid: 0
Uid: 0 0 0 0
Gid: 0 0 0 0
FDSize: 64
Groups:
NStgid: 2294
NSpid: 2294
NSpgid: 2294
NSsid: 2294
VmPeak: 110868 kB
VmSize: 110840 kB
VmLck: 0 kB
・・・
$ sudo ls -l /proc/2294/fd
合計 0
lr-x------ 1 root root 64 11月 30 03:27 0 -> /dev/null
lrwx------ 1 root root 64 11月 30 03:27 1 -> socket:[17744]
lrwx------ 1 root root 64 11月 30 03:27 2 -> socket:[17744]
lrwx------ 1 root root 64 11月 30 03:27 3 -> socket:[19174]
lrwx------ 1 root root 64 11月 30 03:27 4 -> socket:[19183]
$ sudo cat /proc/2294/io
rchar: 1438914
wchar: 748992
syscr: 20279
syscw: 19141
read_bytes: 1880064
write_bytes: 24576
cancelled_write_bytes: 0
$
他にも様々な情報が格納されているので、興味のある方はman proc
コマンドなどでprocを調べてみてください。
・strace
コマンド
さらに踏み込んだ調査方法として、現在プロセスが内部的にどのような処理を行なっているのかstrace
コマンドで見る事ができます。
また、strace
コマンドはプロセスが処理しているシステムコールを表示する事ができるので非常に詳細な情報を確認する事ができますが、このプロセス止まっているように見えるけど何やっているんだろう...というような場合に確認するには細かすぎてよくわからなくなってしまうので、出力する内容を限定する-e read,write,open,execve
オプションをよく使用します。
$ strace -e read,write,open,execve echo test
execve("/bin/echo", ["echo", "test"], [/* 36 vars */]) = 0
open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
open("/lib64/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\340\30\2\0\0\0\0\0"..., 832) = 832
open("/usr/lib/locale/locale-archive", O_RDONLY|O_CLOEXEC) = 3
write(1, "test\n", 5test
) = 5
+++ exited with 0 +++
$
strace
コマンドはプロセスが現在実行している詳細な内容をリアルタイムに確認する事ができる非常に強力なコマンドなので、是非活用して頂ければと思います。
・gcore
/ gdb
コマンド
さらにさらに踏み込んだ調査方法として、プロセスが使用しているメモリや処理に必要な情報を断面的にまるごと出力できるgcore
というコマンドがあります。
strace
コマンドではプロセスが実行しているシステムコールをリアルタイムで確認する事ができましたが、gcore
コマンドでは現時点でプロセスが使用しているメモリの内容や処理内容(コアダンプ)を出力し、gdb
コマンドというデバッガでメモリや処理内容を確認していく事ができます。
gcore
コマンドは一貫性のあるメモリ情報を出力するために一時的にプロセスを中断します。コアダンプ取得後に処理は再開されますが、止める事ができないプロセスなどには使用しないでください。
プロセスが異常終了した場合に異常終了直前のコアダンプが出力され(coreが吐かれ)、gdb
コマンドなどのデバッガを使用して原因調査を行う流れが一般的かと思いますが、gcore
コマンドを使用する事で異常状態にならずともコアダンプが出力できる、gdb
コマンドで本命プロセスにアタッチせずに解析できる、などのメリットがあります。