原因が分かれば対処は簡単だ。今回のシステムでは、TomcatのmaxThreads値を350に変更した。
Apacheの全スレッド数より50多く設定した理由は、Apacheからの再接続が発生した際でも耐えられるよう、多少余裕を持つようにしたためである。どれくらい余裕を持てばよいかは、各システムの状況によって異なる。今回のシステムではこの設定変更以降、無応答となる事象は起こらなくなった。
今回のシステムでは冒頭で述べたとおり、試験環境で負荷試験を行っていた。それにもかかわらず、なぜこの問題が発見できなかったのか?
実は、後から分かったことだが、負荷試験の際、APサーバの台数は本番環境と同じ2台用意したが、マシン台数を確保できなかったため、負荷の低いWebサーバは1台で試験を行っていた。そのため、スレッド数は抑えられ、この問題を発見できなかったのだ……
今回のトラブルはApacheとTomcatとの連携に関する設定値をきちんと理解していなかったために発生したといってよいだろう。そこで、ここでは特に重要となる設定値について、注意点を挙げておく。
Tomcatのスレッド数がApacheからのコネクション数に対して不足すると、無応答やエラーの原因となる。そのため、Tomcatのスレッド数が常に上回っているように設定する。
Apacheからのコネクション数の最大値は、ApacheのMPM(Multi Processing Module)の設定によらず、MaxClientsの値になる。
Tomcatのスレッド数は、Connector要素のmaxThreads属性で設定する。古いTomcat(バージョン5.0以前)では、maxProcessorsという属性名になっている。また、Connectorは受け付けるportごとに設定するので、異なるportに設定してしまわないよう注意してほしい。
なお、Apacheが複数台存在し、それぞれ複数台のTomcatに負荷分散を行っているような環境では、Tomcatに接続してくるすべてのApacheのMaxClients値の総和が必要となる。
一定時間やりとりがないApacheとTomcatの間のコネクションをいったん切って、Tomcatのスレッドをプールに戻すことができる。システムの安定化につながる以下のような効果が期待できる。
ただし、高負荷環境ではコネクションを切ることができないため、残念ながらmaxThreadsの値を下げる効果はない。
TomcatのConnector要素のconnectionTimeout属性で、コネクションのタイムアウト値を設定する。デフォルト値は0(無限大)である。
また、mod_jk側でもconnection_pool_timeoutにより、一定時間やりとりがないコネクションを再利用せずに破棄できる。こちらもデフォルト値は0(無限大)である。
mod_jkでは、各種タイムアウト値を設定できる。これらのパラメータを適切に使用すれば、問題発生時に無応答を回避し、フェイルオーバやユーザーにエラーページを返すことが可能となる。
これらのパラメータについての詳細はmod_jkのドキュメントを参照してほしい。
本記事では、Tomcatのスレッド数に関するトラブル事例を紹介し、Apacheとの連携における注意点を示した。
今回の事例からは、負荷試験についての教訓も得られる。負荷試験を行う際は、本番相当のサーバ台数、データ量、トラフィックを用意するのが基本だ。しかし、何らかの制約により本番環境と試験環境に差がある場合には、その差が生むシステムへの影響を十分に考慮しておく必要がある。
また、当たり前のことではあるが、トラブル解析においてはログの解析が非常に大事だ。今回のトラブルでも、ログの解析がもっと早く終わっていれば、もっと早くトラブルを解決できたかもしれない。出力レベルについても、トラブル解析に必要な情報を出力できているかどうかを確認しておく必要がある。
トラブルが発生してからログを解析するのではなく、ログを常時監視する仕組みを導入すべきだろう。
金子 崇之(かねこ たかゆき)
NTTデータ先端技術株式会社 オープンソース事業部所属。
入社よりJavaを用いたWebシステムの開発支援にかかわる。最近では、主にオープンソースのアプリケーションサーバに関する検証や技術支援、トラブルシューティングに明け暮れている
Copyright © ITmedia, Inc. All Rights Reserved.