あるプログラムがソケットを使用してほかのプログラムと通信している場合、netstatコマンドを使用してソケットの状態を確認するといろいろなことが分かる。
編集部注:netstatコマンドについて詳しく知りたい読者は、@IT Master of IP Networkの「ホストのネット接続は正しく行われているか?〜netstatによるネットワーク設定の確認〜」をご参照ください。
早速、netstatでDBコネクションの状態を見てみると、確立済み(ESTABLISHED)状態のコネクションが、DBCPに設定している最大コネクション数と同じ数だけ存在した。Tomcatの設定を確認してみると、DBCPの最大コネクション数はTomcatの最大スレッド数と同じ値に設定してあった。つまり、スレッドが同時に複数のコネクションを使用しない限りコネクションが不足することはない。
アプリケーション開発のリーダーに確認したところ、「アプリケーションは同時に1つのコネクションしか使わないようコーディングされているはず」とのことだった。
足りるはずのコネクションが不足した。ここから想定される原因は、おそらくコネクションのクローズ漏れだろう。
コネクションのクローズ漏れがTomcatの無応答につながる理由について、もう少し詳しく見ておこう。
DBCPのようにコネクションプールを実装するライブラリは、実際のConnectionオブジェクトをラップしたクラスを用意する。そのラップしたクラスのオブジェクトのclose()メソッドを呼ぶと、コネクションは実際にはクローズされず、プールに返却される。
そして、クローズ漏れが発生すると、プールに戻らないコネクションが生まれてしまう。
プールのコネクション数が上限に達し、不足した場合、後続のコネクション取得処理はプールから取り出すところで待ちとなる。そのため、無応答になってしまうのだ。
クローズ漏れを起こしたコネクションはどうなるのか?
実コネクションに関しては、GCされたタイミングでfinalizeメソッドにより物理的なコネクションをクローズするように実装されている。しかし、DBCPのラッパーオブジェクトはfinalizeを実装しておらず、GCによってプールに戻ってくることもない。
さて、スレッドダンプとnetstatコマンドによりコネクションのクローズ漏れが原因であると目安を付けたものの、解決するにはもうひと手間が必要だ。なぜなら、スレッドダンプは「コネクションを獲得しようとしている」スレッドを検出することはできるが、「コネクションをクローズし忘れた」処理についての情報は何も教えてくれないからだ。
アプリケーションのコードを修正するためには、すべてのソースコードを見直してクローズ漏れがないかどうかチェックしなくてはならない。アプリケーション開発のリーダーに相談したところ、「試験工程のスケジュールがすでに遅れており、すべてのソースコードチェックを行うような人手は掛けられない」とのことだった。
そこで、DBCPの持つremoveAbandoned機能を試してみることにした。DBCPには、クローズ漏れ(見捨てられた:abandoned)となったコネクションを回収する仕組みが存在する。
removeAbandonedを有効にすると、コネクションをプールから取り出す際に、“trace”リストにコネクションへの参照が格納される。コネクションには、そのときの呼び出しのstackTrace情報が保存される。
そして、プールから取り出されたコネクションの数がプールの最大値(maxActive)に近づくと、コネクションの取得を要求したスレッドは、“trace”リストを基に、取り出しから一定時間たったコネクションを追跡、closeを呼ぶことでプールにコネクションを返却する。
removeAbandonedを有効にするには、DataSourceの設定で、リスト4のようにパラメータを追加する。
リスト4 DataSource設定 |
<Resource name="jdbc/postgres" auth="Container" |
パラメータの内容の詳細については、後述する。
removeAbandonedパラメータを設定し、再度負荷試験を行うと、Tomcatのログにリスト5のようなstackTraceが出力された。
リスト5 removeAbandonedによるstackTrace (拡大したものはこちら) |
DBCP object created 2007-xx-xx 14:53:32 by the following code was never closed: |
stackTraceはどれも同じメソッド、LogoutBean.doExecメソッドを示している。
どうやら、このメソッドの後続の処理でクローズ漏れがありそうだ。
Copyright © ITmedia, Inc. All Rights Reserved.