数百キロのコードでブルー - ドクターTomcat緊急救命:現場から学ぶWebアプリ開発のトラブルハック(14)(2/2 ページ)
本連載は、現場でのエンジニアの経験から得られた、APサーバをベースとしたWebアプリ開発における注意点やノウハウについて解説するハック集である。現在起きているトラブルの解決や、今後の開発の参考として大いに活用していただきたい。(編集部)
■ステップ【3】コネクションプールのリーク検出機能を試す
幸い、最近のコネクションプールには、コネクションの解放漏れを検出する機能を持つものがある。今回のシステムでは、TomcatのDBCPによるコネクションプールが利用されており、DBCPはコネクションの解放漏れを検出できる。
「context.xml」に次のように記述することにより、コネクションの解放漏れが発生した際にメッセージをログに出力するようになる。
<Resource name="jdbc/postgres" auth="Container" type="javax.sql.DataSource" driverClassName="org.postgresql.Driver" url="jdbc:postgresql://127.0.0.1:5432/tomcat" username="xxx" password="xxx" maxActive="20" maxIdle="10" maxWait="-1" removeAbandoned="true" removeAbandonedTimeout="300" logAbandoned="true" />
上記の設定を行った後、アプリケーションを再起動すると、次のメッセージがログメッセージに追加され、コネクションの解放漏れを検出できるコネクションプール(AbandonedObjectPool)が利用されていることが確認できる。
AbandonedObjectPool is used (org.apache.tomcat.dbcp.dbcp.AbandonedObjectPool@4fc156) LogAbandoned: true RemoveAbandoned: true RemoveAbandonedTimeout: 300
しばらくアプリケーションを動作させすると、次のようなスタックトレースがログに出力され、コネクションの解放漏れが検出された。
DBCP object created 2010-05-01 08:16:19 by the following code was never closed: java.lang.Exception at org.apache.tomcat.dbcp.dbcp.AbandonedTrace.setStackTrace(AbandonedTrace.java:160) at org.apache.tomcat.dbcp.dbcp.AbandonedObjectPool.borrowObject(AbandonedObjectPool.java:86) at org.apache.tomcat.dbcp.dbcp.PoolingDataSource.getConnection(PoolingDataSource.java:96) at org.apache.tomcat.dbcp.dbcp.BasicDataSource.getConnection(BasicDataSource.java:880) at org.ultimania.servlet.ConnectionManager.getConnection(ConnectionManager.java:17) at org.ultimania.servlet.ItemManager.service(ItemManager.java:29) at javax.servlet.http.HttpServlet.service(HttpServlet.java:717) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233) at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191) at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127) at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102) at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109) at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:298) at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:852) at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:588) at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:489) at java.lang.Thread.run(Unknown Source)
このログの7〜8行目の部分を見ると、「ConnectionManager」というクラスのgetConnection()メソッドで取得されたコネクションがコネクションの解放漏れを発生させていることが確認できる。ConnectionManager.getConnection()メソッドと、それを呼び出しているItemManager.service()メソッドを調査することにより、問題を修正できた。
予防処置 - 愛と勇気だけではシステムはよみがえらない
今回コネクションリークが発生しているコードを見ていると、あることに気が付いた。コネクションの解放漏れが発生しているコードは、次のように記述されている場合が多い。
// コネクション取得 Connection con = null; try { ds = (DataSource)(new InitialContext.lookup("...."); con = ds.getConnection(); } catch (NamingException e){ //エラー処理 …【略】… } catch (SQLException e){ //エラー処理 …【略】… } //トランザクション処理など業務ロジック …【略】… // コネクションクローズ処理 try { con.close(); } catch (SQLException e) { // エラー処理 …【略】… }
上記のコードは、一見取得したコネクションを確実にクローズしているように見える。しかし、途中の処理の部分で例外をスローした場合、コネクションはクローズされない。下記のようにコネクションを取得するtry句の中でコネクションの取得とトランザクション処理を行い、finally句の中でクローズを行った方が確実である。
Connection con = null; try { ds = (DataSource)(new InitialContext.lookup("...."); con = ds.getConnection(); //トランザクション処理など業務ロジック …【略】… } catch (NamingException e){ // エラー処理 …【略】… } catch (SQLException e){ // エラー処理 …【略】… } finally { if (con!=null) { con.close(); } }
この国には、もっと救えるシステムがある
EJBコンテナやDIコンテナのDAO(Data Access Object)機能などを利用すれば、コネクションのクローズを開発者が意識しなくても自動的にフレームワークが行ってくれる。フレームワークの機能を活用してコネクションの解放漏れを防ぐのもいいだろう。
本稿では、コネクションの解放漏れを検出する方法について紹介した。厄介なコネクションの解放漏れも、対処方法を把握しいれば、簡単に対処できる。特にFindBugsによるバグの可能性があるコードの検出は、早期のバグ発見に効果的である。
【おまけ】ほかのアプリケーションサーバでの調べ方
今回は、TomcatのDBCPの設定を例にコネクションの解放漏れを検出する例を紹介したが、Tomcat以外のアプリケーションサーバでも同様にしてコネクションリークを検出できる。まとめとしていくつか紹介しよう。
■Apache CommonsのDBCPを利用したミドルウェア(Tomcat、Jetty、Springなど)
Tomcatと同様、DBCPのremoveAbandonedとlogAbandonedをtrueに設定し、removeAbandonedTimeout(クローズされたコネクションを除去するタイムアウト時間)を設定する。詳細は、下記のドキュメントを参照されたい。
ちなみに、Tomcatのコネクションプールのパッケージ名は「Commons DBCP」と異なるが、Commons DBCPのパッケージ名を変更して利用している。
■C3P0を利用したミドルウェア(Jetty、Spring、Hibernateなど)
C3P0の設定で、debugUnreturnedConnectionStackTracesをtrueにし、unreturnedConnectionTimeout(クローズされなかったコネクションのタイムアウト時間)を設定する。詳細は、下記のドキュメントを参照されたい。
■WebSphere
WebSphereのログやトランザクションの設定処理でConnLeakLogicを設定する。詳細は、下記のドキュメントなどを参照されたい。
- 数百キロのコードでブルー - ドクターTomcat緊急救命
- DB操作の“壁”を壊すJPAが起こした「赤壁の戦い」
- アプリ開発でも、よ〜く考えよう。キャッシュは大事だよ
- スレッドダンプの森で覚えた死のロックへの違和感
- ThreadとHashMapに潜む無限回廊は実に面白い?
- JavaのGC頻度に惑わされた年末年始の苦いメモリ
- 肥え続けるTomcatと胃を痛めるトラブルハッカー
- 【トラブル大捜査線】失われたコネクションを追え!
- 【真夏の夜のミステリー】Tomcatを殺したのは誰だ?
- OutOfMemoryエラー発生!? GCがあるのに、なぜ?
- DBアクセスのトラブルは終盤で発覚しがち……
- 【実録ドキュメント】そのログ本当に必要ですか?
- “Stop the World”を防ぐコンカレントGCとは?
- Webアプリの問題点を「見える化」する7つ道具
Copyright © ITmedia, Inc. All Rights Reserved.
関連記事
- MySQLの常識を知りセットアップしてJSPからDB操作
Webアプリの常識をJSPとStrutsで身につける(8) 昨今のWebアプリケーション開発において必須ともいえるDBとの連携の仕組みを、サンプルを作りながら説明します - 悲観もあれば楽観もある「トランザクション」の常識
企業システムの常識をJBossで身につける(8) トランザクションの概要やJDBCでの基本的なDB接続、Java標準のJTA/JTSを紹介しJBoss Transactionsでサンプルを作成 - 現場にキく、Webシステムの問題解決ノウハウ
本連載は、日立製作所が提供するアプリケーションサーバ「Cosminexus」の開発担当者へのインタビューを通じて、Webシステムにおける、さまざまな問題/トラブルの解決に効くノウハウや注意点を紹介していく。現在起きている問題の解決や、今後の開発のご参考に - 第1回 Java EEサーバからレスポンス返らず。何から調べる?
- 第2回 WebアプリのHTML/画像表示を速くする3つの方法
- 第3回 Webの表示速度を遅くする「SSLハンドシェイク」とは
- 第4回 調査の難しい「OutOfMemoryError」事例、5選
- 第5回 OutOfMemoryError発生! その解決への近道とは
- 第6回 ここが大変だよ、JavaのGC/メモリ管理
- 第7回 サーブレットやJSPの“バージョン”意識してますか?
- 第8回 Hadoopの死角、COBOLバッチ処理の並列化
- 事例に学ぶWebシステム開発のワンポイント
現場のエンジニアの経験から得られた、アプリケーション・サーバをベースとしたWebシステム開発におけるノウハウ、注意点について解説 - 第1回 クラスタ化すると遅くなる?
- 第2回 キャッシュが性能劣化をもたらす謎を解く
- 第3回 クラスタは何台までOK?
- 第4回 マルチスレッドのいたずらに注意
- 第5回 クラスタによるアプリケーションの動的アップデート
- 第6回 APサーバからの応答がなくなった、なぜ?
- 第7回 低負荷なのにCPU使用率が100%?
- 第8回 文字化け“???”の法則とその防止策
- 第9回 メモリは足りているのに“OutOfMemory”のなぞ
- 第10回 レスポンスキャッシュでパフォーマンス向上
- 第11回 JDBC接続を高速化―PreparedCacheの活用
- 第12回 ブラウザキャッシュでパフォーマンス向上
- 第13回 ファイルアップロード/ダウンロードに潜むわな
- 高負荷なのに片方のサーバにだけ余裕が……なぜ?
Linuxトラブルシューティング探偵団 第1回 Linuxベースのシステムで起こるトラブルに、百戦錬磨の達人が立ち向かう! 実例を元に障害対応のプロセスを紹介します