【トラブル大捜査線】失われたコネクションを追え!:現場から学ぶWebアプリ開発のトラブルハック(7)(3/3 ページ)
本連載は、現場でのエンジニアの経験から得られた、APサーバをベースとしたWebアプリ開発における注意点やノウハウについて解説するハック集である。現在起きているトラブルの解決や、今後の開発の参考として大いに活用していただきたい。(編集部)
【最終話】それが、トラブルシューティング屋の務め
クローズ漏れの個所も大体の見当が付いたので、アプリケーション開発チームに確認・修正を依頼した。
アプリケーションが直るまでの間、removeAbandonedを付けたままで負荷試験を継続することにした。目的はremoveAbandonedのオーバヘッドを測定することである。logAbandonedを指定しなければstackTraceは生成されない。そのため、ある程度の性能は出るように思われた。
■removeAbandonedの同期化
しかし、実際に測定してみたところ、思ったように性能は出なかった。CPUがほとんど使い切れなかったのだ。
ここまできたら、ついでに解析してしまうのが、トラブルシューティング屋の務めだろう。負荷を掛けている最中にスレッドダンプを取得すると、多数のスレッドが以下の2つの処理の直前でtraceリストのロック取得待ちとなっていた。
- コネクションを取得する際のtraceリスト内の走査処理
- コネクションを返却する際のtraceリストからのremove処理
該当するAbandonedObjectPoolのソースコードをチェックすると、リスト6のようになっている。
*** 一部省略されたコンテンツがあります。PC版でご覧ください。 ***
synchronizedブロックで囲われた中で、それぞれIteratorによるリストの走査処理と、ArrayList#remove(obj)を呼び出している。
どちらも十分速い処理ではあるが、リスト内の要素数が増えるにつれ、どうしてもある程度の時間を要してしまう。この2つの処理は、コネクションの使用に伴い毎回呼ばれる処理のため、無視できない同期待ち時間になってしまったのだ。
■「このような基本的なミスをして申しわけない」
removeAbandonedのオーバヘッドは予想以上に大きかった。やはり、コネクションのクローズ漏れに関しては、アプリケーションを修正せざるを得ない。
「このような基本的なミスをして申しわけない」。アプリケーション開発のリーダーから修正版のアプリケーションを受け取ると、今度こそ性能が出ることを確認できた。
【Tips】DBCPのパラメータを理解し、武器にする
今回の事例からは、Tomcatを使用するうえではDBCPについての知識も必要となることが分かる。そこでコネクションプールの性能に影響を与えるパラメータについて解説しておこう。
■コネクション数を管理する
パラメータ | 内容 | デフォルト値 | |
---|---|---|---|
maxActive | プールから貸し出すコネクションの最大数 | 8 | |
minIdle | プール内のコネクション数をminIdle以上に保つ | 0 | |
maxIdle | プール内のコネクション数をmaxIdle以下に保つ | 8 | |
initialSize | プールの初期状態に確保するコネクション数 | 0 | |
maxWait | プール内のコネクションが不足したときの最大待ち時間(ミリ秒) | −1(無限大) |
コネクション数の管理において、一番注意が必要となるのが、「maxActive」だ。DBサーバ側にも最大プロセス数等の制限があるため、その値以下にしなくてはならない。
また、アプリケーションサーバが複数台あるときには、その分も考慮しなくてはならないだろう。0以下の値を指定した場合、最大値の制限はなくなる。
「maxWait」はプール内のコネクションが不足したとき、最大何ミリ秒待つかを指定する。指定した時間内にコネクションが確保できなかった場合、SQLExceptionが投げられる。エラーとして応答を返せば、アプリケーションが無応答になることを防ぐことができる。
コネクション数はTomcatのスレッド数よりも少ない値を指定することも可能だ。しかし、Object#wait()で待っている複数のスレッドはObject#notifyAll()によってすべて起動させられる。
コネクションを取得できるのは、OSのスケジューリングにより最初にコネクションの再取得にたどり着いたスレッドのみだ。そのため、運が悪いスレッドはいつまでもコネクションが取得できないこともあり得る。コネクション数を絞り込む場合、適切な「maxWait」の値を設定しタイムアウトさせた方がよいだろう。
■コネクションを検証する
パラメータ | 内容 | デフォルト値 | |
---|---|---|---|
validationQuery | コネクションが有効かどうかを検証するためのSQL | なし | |
testOnBorrow | コネクションをプールから取り出すときに検証するかどうか | true | |
testOnReturn | コネクションをプールに返すときに検証するかどうか | false | |
testWhileIdle | プール内でアイドル状態のコネクションを検証するかどうか | false | |
timeBetweenEvictionRunsMillis | アイドル状態のコネクションの検証間隔 | −1 | |
numTestsPerEvictionRun | 1回の検証当たり何個のコネクションを対象とするか | 3 | |
minEvictableIdleTimeMillis | 何ミリ秒アイドルだったら検証するか | 1000 * 60 * 30 |
validationQueryパラメータでは、コネクションが有効かどうかを検証するためのSQLを指定する。通常は、負荷の軽いSQLを指定する。
testWhileIdle以降はプール内でアイドル状態のコネクションを検証するかどうかのパラメータだ。この機能を使用するときには、validationQueryパラメータが設定されている必要がある。
■PreparedStatementをキャッシュする
パラメータ | 内容 | デフォルト値 | |
---|---|---|---|
poolPreparedStatements | PreparedStatementをキャッシュするかどうか | false | |
maxOpenPreparedStatements | 1コネクション当たりキャッシュするPreparedStatementの最大数 | 0(無限大) |
PreparedStatementキャッシュは、作成したPreparedStatementをDBコネクションごとにキャッシュする機能だ。SQLのパース、実行計画の作成などのDBサーバの処理を減らし、負荷を下げる効果がある。
■コネクションを追跡する
パラメータ | 内容 | デフォルト値 | |
---|---|---|---|
removeAbandoned | クローズ漏れとなったコネクションを回収するかどうか | false | |
removeAbandonedTimeout | コネクションが最後に使用されてから回収対象となるまでの時間(秒) | 300 | |
logAbandoned | コネクションがプールから取り出されたときの時間とスタックトレースを回収時に出力するかどうか | false |
removeAbandonedはクローズ漏れとなったコネクションを回収する機能だ。しかし、本文中でも触れたとおり、非効率な処理が多く含まれている。本番環境で使用することは避けた方がよいだろう。
【最後に】閉め忘れにご用心
本稿では、試験環境におけるDBCPに関するトラブル事例を紹介した。DBCPにはクローズ漏れを実行時に回収する手段や呼び出しのstackTraceを表示する機能が存在する。
しかし、フレームワークにコネクションの処理を委譲したり、コーディング規約やチェックツールにより確実にクローズしていることを確認したりするなど、クローズ漏れに関してはそのほかの手段を用いる方がよいだろう。
あくまで緊急の手段であることをお忘れなく。
プロフィール
金子 崇之(かねこ たかゆき)
NTTデータ先端技術株式会社 オープンソース事業部所属。
入社よりJavaを用いたWebシステムの開発支援にかかわる。最近では、主にオープンソースのアプリケーションサーバに関する検証や技術支援、トラブルシューティングに明け暮れている
Copyright © ITmedia, Inc. All Rights Reserved.
関連記事
- JNDI活用でデータソース管理を一元化する
- Tomcatの環境を構築する
やり直し「JSPとTomcat」(2) JSPの実行環境となる「Webコンテナ」の1つ、「Tomcat」を実行するための環境を構築し、次回以降の実習環境を作ります - サーブレット/JSPの開発環境を作る
[連載]基礎から学ぶサーブレット/JSP(3) サーブレット/JSPの開発/実行環境を整えるためにJ2SE、Tomcat、Apacheのインストールを行います - DBのコネクションプーリングを簡単に実現
[連載]現場に活かすJakarta Project(6) CommonsのDBCPは、PoolよりもDBのコネクションプーリングを容易に実現できるコンポーネントだ - JSPでのエラーとパフォーマンス対策
[連載]JSPコーディング・テクニック(4) JSPでエラー処理を行う方法と、データベースアクセスでパフォーマンスを発揮するためのコネクションプーリングについて解説 - 事例に学ぶWebシステム開発のワンポイント
現場のエンジニアの経験から得られた、アプリケーション・サーバをベースとしたWebシステム開発におけるノウハウ、注意点について解説 - 第1回 クラスタ化すると遅くなる?(2002/3/9)
- 第2回 キャッシュが性能劣化をもたらす謎を解く(2002/3/23)
- 第3回 クラスタは何台までOK?(2002/4/19)
- 第4回 マルチスレッドのいたずらに注意(2002/5/14)
- 第5回 クラスタによるアプリケーションの動的アップデート(2002/6/4)
- 第6回 APサーバからの応答がなくなった、なぜ?(2002/11/30)
- 第7回 低負荷なのにCPU使用率が100%?(2002/12/11)
- 第8回 文字化け“???”の法則とその防止策(2003/1/28)
- 第9回 メモリは足りているのに“OutOfMemory”のなぞ(2003/2/15)
- 第10回 レスポンスキャッシュでパフォーマンス向上(2003/3/29)
- 第11回 JDBC接続を高速化―PreparedCacheの活用(2003/4/18)
- 第12回 ブラウザキャッシュでパフォーマンス向上(2003/5/10)
- 第13回 ファイルアップロード/ダウンロードに潜むわな(2003/6/12)