Tomcatもビジーになってくると、スレッドが効率的に利用されているのかが気になってくる。それにはスレッド状態を見てやればよい。
Linux kernel 2.6.Xでは、procfsを覗いてやると、各プロセス中のスレッド状態を取得することが出来る。Tomcatのスレッド状態をコマンド一発で取得できればうれしいね。ということでシェルスクリプトを作ってみた。
#
# tomcatstat.sh : Obtain thread statuses of Tomcat
#
# Copyright(c) 2012 Ryuichi Kurishima
#
# This script is BSD licensed.
#
CNT_R=0
CNT_S=0
CNT_D=0
CNT_Z=0
CNT_T=0
CNT_W=0
CNT_ALL=0
CNT_UNKOWN=0
progName=`basename $0`
banner() {
echo "-------------------------"
echo " $progName : Check for thread statuses of Tomcat"
echo ""
echo " Copyright(c) 2012 Ryuichi Kurishima, all rights reserved."
echo ""
echo " This script is BSD licensed."
echo ""
echo "-------------------------"
}
#
# Main body.
#
banner
# Identify Tomcat's PID
pid=`ps -ef|grep java|grep Bootstrap|grep -v grep|gawk '{print $2}'`
if [ x"$pid" = x ]; then
echo "Tomcat is not found. Quitting."
exit 1
fi
echo "Tomcat PID : ${pid}"
echo "-*-*-*-*-*-*-"
threads=`ls /proc/${pid}/task`
for thread in $threads
do
path=/proc/${pid}/task/${thread}/stat
state=`cat $path|gawk '{print $3}'`
# Refer to procfs man page.
if [ x"$state" = x"R" ]; then
desc="Running"
CNT_R=`expr ${CNT_R} + 1`
elif [ x"$state" = x"S" ]; then
desc="Interruptibe Sleep"
CNT_S=`expr ${CNT_S} + 1`
elif [ x"$state" = x"D" ]; then
desc="Uninterruptible Disk Sleep"
CNT_D=`expr ${CNT_D} + 1`
elif [ x"$state" = x"Z" ]; then
desc="Zombie"
CNT_Z=`expr ${CNT_Z} + 1`
elif [ x"$state" = x"T" ]; then
desc="Traced or Stopped (on a signal)"
CNT_T=`expr ${CNT_T} + 1`
elif [ x"$state" = x"W" ]; then
desc="Paging"
CNT_W=`expr ${CNT_W} + 1`
else
desc="Unkown Status"
CNT_UNKOWN=`expr ${CNT_UNKOWN} + 1`
fi
CNT_ALL=`expr ${CNT_ALL} + 1`
echo "Thraed ID : ${thread}, state = '${state}', description = '${desc}'"
done
echo "-*-*-*-*-*-*-"
echo "State 'R' (Running) count : ${CNT_R}"
echo "State 'S' (Interruptible Sleep) count : ${CNT_S}"
echo "State 'D' (Uninterruptible Disk Sleep) count : ${CNT_D}"
echo "State 'Z' (Zombie) count : ${CNT_Z}"
echo "State 'T' (Traced or Stopped) count : ${CNT_T}"
echo "State 'W' (Paging) count : ${CNT_W}"
echo "Unkown State : ${CNT_UNKOWN}"
echo ""
echo "Threads count (ALL) : ${CNT_ALL}"
実施例は以下の通り。
-------------------------
tomcatstat.sh : Check for thread statuses of Tomcat
Copyright(c) 2012 Ryuichi Kurishima, all rights reserved.
This script is BSD licensed.
-------------------------
Tomcat PID : 2275
-*-*-*-*-*-*-
Thraed ID : 2275, state = 'S', description = 'Interruptibe Sleep'
Thraed ID : 2316, state = 'S', description = 'Interruptibe Sleep'
Thraed ID : 2317, state = 'S', description = 'Interruptibe Sleep'
Thraed ID : 2318, state = 'S', description = 'Interruptibe Sleep'
Thraed ID : 2319, state = 'S', description = 'Interruptibe Sleep'
Thraed ID : 2320, state = 'S', description = 'Interruptibe Sleep'
Thraed ID : 2321, state = 'S', description = 'Interruptibe Sleep'
Thraed ID : 2322, state = 'S', description = 'Interruptibe Sleep'
Thraed ID : 2323, state = 'S', description = 'Interruptibe Sleep'
Thraed ID : 2416, state = 'S', description = 'Interruptibe Sleep'
Thraed ID : 2474, state = 'S', description = 'Interruptibe Sleep'
Thraed ID : 2475, state = 'S', description = 'Interruptibe Sleep'
Thraed ID : 2547, state = 'S', description = 'Interruptibe Sleep'
Thraed ID : 2550, state = 'S', description = 'Interruptibe Sleep'
Thraed ID : 2551, state = 'S', description = 'Interruptibe Sleep'
Thraed ID : 2552, state = 'S', description = 'Interruptibe Sleep'
Thraed ID : 2553, state = 'S', description = 'Interruptibe Sleep'
Thraed ID : 2554, state = 'S', description = 'Interruptibe Sleep'
-*-*-*-*-*-*-
State 'R' (Running) count : 0
State 'S' (Interruptible Sleep) count : 18
State 'D' (Uninterruptible Disk Sleep) count : 0
State 'Z' (Zombie) count : 0
State 'T' (Traced or Stopped) count : 0
State 'W' (Paging) count : 0
Unkown State : 0
Threads count (ALL) : 18
user@server$
ウチのサーバーのTomcatはヒマだから、全部スリープ中なのだ。
スレッド状態には、procfsのmanページによると、以下の状態がある。
R (Running) : 実行状態。この状態のスレッドばかりならば、フル稼働中というわけだ。働き者ぉ~!
S (Interruptible Sleep) : 割り込み可能なスリープ状態。割り込み可能とは、つまり、いつでも処理を担当することが出来るということ。手持ち無沙汰なんだね。
D (Uninterrutible Disk Sleep) : 割り込み不可能なディスクアクセス状態のスリープ。この状態が長く続くならば、何かディスクI/Oパフォーマンス上の問題があるのかも。
Z (Zombie) : スレッドのゾンビ状態。スレッド実行終了後、他の任意の「仲間スレッド」がpthread_join()してやらないと、ずっとこの状態で残ってしまうよ。プロセスのゾンビと違って、確かスレッドゾンビの場合はリソースをつかんだままだったような。。。
T (Traced or Stopped) : スレッドがトレース状態かストップ状態となっている。デバッガがプロセスにアタッチしていることがなければ、普通はこういうことはない。
W (Paging) : 物理ページへ"W"riteしているのだろう。Linuxはオン・デマンド・ページング(またはコピー・オン・ライトともいうね)なので、仮想メモリの書き換えが起こる時点で実際に物理ページを新しく割り当てる。一時的にこの状態ならば問題はないだろうが、ずっとこの状態であるならば、カーネルによるページのリクレーム処理が長引いているのかもしれない。Linuxはページが足りなくなると一気にガツンとリクレームするからね。
たとえば、Tomcatのスレッドがスリープ状態なのにリクエストの滞留(処理待ち)が発生しているならば、KeepAlive等によってコネクションを握ってしまっているクライアントがいるということだ。Tomcatコネクタのコネクションタイムアウト値(既定で60000ミリ秒=60秒)を2000ミリ秒=2秒程度に設定してやるとずっと具合がよくなる。これはちょっとしたTipsだよ。