0. 今回お話しすること
- TomcatのThread dumpを取得してみたよ
- 'kill -3' だとcatarina.outに埋もれるから、別ファイルに書き出したよ
- tomcatの実行ユーザがno-login指定だったからちょっと困ったけど解決したよ
- AWS EC2 + Java + Tomcatという環境でお話しするよ
アプリケーションエンジニアが本業で、ミドルウェア〜インフラはまだまだヒヨッコです。
「当たり前だろ!」というところも優しい目で見守ってください。
1. 前説
1.1 'kill -3' の問題点
「Thread dumpといえば、'kill -3'でしょ!」
そういう環境で育ってきました。
もちろん'kill -3'でもThread dumpは取得できます。
できますが、問答無用でcatarina.outへと吐き出されます。
筆者はJava-Tomcatで環境構築しているのですが、
catarina.outといえば、各種ログが詰め込まれた"雑草地"です。
解析するためにThread dumpの結果部分だけを切り出すのがとてもしんどいのです。。。
1.2 'no-login' ユーザの難点
仮想マシンを複数ユーザが共有する場合、利用する人ごとにユーザを発行するのが定石です。
また、Tomcatなどのミドルウェアを常時起動しておく場合、通常のユーザとは分けてそれ専用のユーザを発行し、そのユーザで起動することが多いかと思います。
私はこれまで「ミドルウェア実行用ユーザ」のアクセス制御をあまり考えてきませんでした。
しかし、実際にはこれらのユーザでログインする必要がないため、no-login指定をしてアクセスさせないようにしました。
するとどうでしょう。
この後お話しする'jstack'によるThread dumpは実行ユーザ自身でないと取得できないのに、'sudo su' でもログインできないではありませんか。
セキュリティを高くしたばっかりに、自分が締め出されてしまいました。。。
2. 解決方法
2.1 Thread dumpの結果をcatarina.out以外のファイルに
'kill -3'の代わりに、以下のように記述します。
jstack PID >> /PATH/FILE_NAME.log
※PID: TomcatのプロセスID。psコマンドでわかる。
※/PATH/FILE_NAME.log: 結果を吐き出すパスとファイル名。
※「>>」は追記の意味なので、必要に応じて「>」に変えてください。
2.2 no-login指定のユーザでログインするには
no-loginユーザは、ログイン時に"nologinシェル"が実行されることで、ログインできなくしています。
なのでログイン時に実行されるシェルを強制的に指定することでログインできるようになります。
su -s /bin/bash USERNAME
2.3 自動的にスレッドダンプの結果を吐き出すためにcronに仕込んでみた(かなり強引)
jstackコマンドは、tomcatを実行しているユーザで実行しないと結果を出せません。(rootユーザでも不可)
そのため、tomcat実行ユーザでログインし、以下をcronに仕込んでみました。
もっときちんとつくることが望ましいですが、なるべく時間をかけず、ざっくり90%OKなラインで作ってみました。
より良い方法があれば是非教えてください。
jstack `ps aux | fgrep TOMCAT_USER | head -n 1 | cut -c 10-15` >> /PATH/FILE_NAME.log
※TOMCAT_USER: tomcatを実行しているユーザ名
※head -n 1: fgrepで絞り込んだ結果、複数ヒットするもののtomcatのプロセスが必ず先頭になるので先頭1行を抽出(なぜかはわからない・・・なお経験則なので確実でもない。よって強引。)
※cut -c 10-15: 先頭行のPIDがうまいこと引っかかるように文字列カット(ここもちょっと強引。)
このcronを仕込んだおかげで、これまでcatarina.outから頑張って見つけていたスレッドダンプがかなり楽にとれるようになりました。