本連載は、現場でのエンジニアの経験から得られた、APサーバをベースとしたWebアプリ開発における注意点やノウハウについて解説するハック集である。現在起きているトラブルの解決や、今後の開発の参考として大いに活用していただきたい。(編集部)
前回の記事「【真夏の夜のミステリー】Tomcatを殺したのは誰だ?」では、WebサーバとTomcatの間の接続において、スレッド数の不整合により発生したトラブル事例を紹介した。
今回はTomcatとDBサーバの間のトラブル事例を紹介しよう。
アプリケーションサーバとDBサーバとの間のトラブルと聞いてすぐに思い付くのは、DBコネクションのクローズ漏れだ。しかし、O/Rマッピングツールなどのフレームワークが普及したことで、コネクションのオープン/クローズをアプリケーションのコード中から行う必要性は減っている。そのため、クローズ漏れに遭遇する機会も減っている。
今回問題が発生したシステムでは、ベンチマークを行うためのプログラムを組んでおり、サーブレットを中心としてロジックが実装されていた。つまり、上記のようなフレームワークを使わず、アプリケーション中から直接DBコネクションを処理していた。現在では、なかなかお目に掛かれないアプリケーションの組み方だ。しかし、そういうケースもまれにあるということをご理解いただいたうえで、以降の記事を読んでいただけるとありがたい。
トラブルの第一報は、「負荷を掛けていると、突然応答を返さなくなる」という知らせだった。例によって、これだけでは何のことかまったく分からない。早速、現場に行き、ベンチマーク担当者からヒアリングを行った。その結果、以下のような状況であることが分かった。
調査対象は試験環境であり、かつ問題も再現性があるため、原因追究は簡単に思われた。
早速、Webアプリの問題点を「見える化」する7つ道具を利用し、トラブル切り分けフローに従い分析を行うことにした。
「0:基本データ分析」と「1:GC分析」はすでに終わっており、問題はないことが確認できている。そこで、次のステップである「2:スレッドダンプ解析」に取り掛かることにした。
Java環境で無応答な事象の原因を追求するときには、スレッドダンプ解析が最も有効だ。ここでスレッドダンプについて、見方を簡単におさらいしておこう。例として、リスト1のような処理を多数のスレッドで実行したとき、得られるスレッドダンプはリスト2のようになる。
リスト1 ロックを取得する処理 |
01: package ctest.list; |
リスト2 スレッドダンプ例 |
"Thread-80" prio=6 tid=0x02cf0f48 nid=0x824 runnable [0x042ef000..0x042ef9e8] |
スレッドダンプからは、ロックの使用状況を知ることができる。Thread-80はArrayListのロックを獲得(locked)している。そのほかのスレッドはロック獲得待ち(waiting to lock)であることが分かる。ロック待ちのスレッドが待っている行はListTestWorke.javarの20行目、ロック対象となるオブジェクトは「0x230d0fa8」という値で識別されるjava.util.ArrayListであることが分かる。
複数のスレッドが同じオブジェクトを操作するとき、整合性を保つためにはロックが必要だ。同じロックを多数のスレッドが獲得しようとしている場合、スレッド数が多過ぎる、ロックの保持期間が長いなど、そのロック付近に並行処理上の問題があるケースが多い。
また、2つ以上のロックを獲得しようとするような処理の場合、デッドロックになってしまう場合もある。
複数回のスレッドダンプを比較してスレッドごとの状態変化を確認するのも、無応答の解析には有効だ。まったく状態が変化していないスレッドの場合、やはりその処理の近辺に問題が隠れている場合がある。
前置きが長くなってしまったが、無応答の状態でスレッドダンプを取得してみた。すると、リスト3のようにGenericObjectPool#borrowObjectメソッドで待っているスレッドが多数検出された。
リスト3 ロック状態のスレッド (拡大したものはこちら) |
"http-8080-Processor24" daemon prio=6 tid=0x03b62560 nid=0x150 in Object.wait() [0x04bff000..0x04bffbe8] |
Tomcatの持つコネクションプールであるDBCPでは、コネクションがすぐに取得できなかったとき、Object.wait()によってスレッドを待たせる処理になっている。
どうやら、コネクションプール回りで問題が起こっていると見て間違いなさそうだ。
Copyright © ITmedia, Inc. All Rights Reserved.