セットアップ:
Fedora 8
Apache
2.2.8 Tomcat 5.5.8
ApacheはAJPを使用してリクエストを転送しています。
問題:
一定の期間(一定ではない、1〜2時間、または1日以上)後にTomcatがダウンします。応答を停止するか、汎用の「一時的に利用できないサービス」を表示します。
診断:
同じセットアップの2つのサーバーがあります。1つはトラフィックの多いWebサイト(1秒あたり数回のリクエスト)を収容し、もう1つはトラフィックの少ないWebサイト(数分ごとに少数のリクエスト)を収容します。両方のWebサイトは完全に異なるコードベースですが、同様の問題を示しています。
最初のサーバーでは、問題が発生すると、すべてのスレッドが制限(MaxThreads 200)に達するまでゆっくりと開始されます。その時点で、サーバーはもう応答していません(そして、長期間後にサービス利用不可ページが表示されます)。
2番目のサーバーでは、問題が発生するとリクエストに時間がかかり、リクエストが完了すると、サービス利用不可ページのみが表示されます。
MaxThreadsの問題に関する言及を除き、Tomcatのログには、これを引き起こしている可能性のある特定の問題は示されていません。
ただし、Apacheログには、AJPを参照するランダムメッセージが表示されます。ランダムメッセージのサンプルを次に示します(順不同)。
[error] (70007)The timeout specified has expired: ajp_ilink_receive() can't receive header
[error] (104)Connection reset by peer: ajp_ilink_receive() can't receive header
[error] proxy: AJP: disabled connection for (localhost)
[error] ajp_read_header: ajp_ilink_receive failed
[error] (120006)APR does not understand this error code: proxy: read response failed from 127.0.0.1:8009 (localhost)
[error] ap_proxy_connect_backend disabling worker for (localhost)
高トラフィックサーバーで気づいたもう1つの奇妙なことは、問題が発生する直前に、データベースクエリが以前よりもはるかに長くかかっていることです(通常5〜50ミリ秒)。これは、MaxThreadsメッセージが表示されるまで2〜4秒しか続きません。これは、サーバーが突然大量のデータ/トラフィック/スレッドを処理した結果であると想定しています。
背景情報:
これらの2つのサーバーは、かなり長い間問題なく実行されていました。システムは、その間に実際にそれぞれ2つのNICを使用してセットアップされました。内部トラフィックと外部トラフィックを分離しました。ネットワークのアップグレード後、これらのサーバーを単一のNICに移動しました(これはセキュリティ/シンプルさの理由から推奨されました)。その変更の後、サーバーはこれらの問題を抱え始めました。
解決策:
明らかな解決策は、2つのNICのセットアップに戻ることです。それに伴う問題は、ネットワークのセットアップに何らかの問題を引き起こすことであり、問題を無視しているようです。単一のNICセットアップで実行してみてください。
さまざまなエラーメッセージをグーグルで検索しても、有用なものは提供されませんでした(古いソリューションまたは問題とは無関係です)。
さまざまなタイムアウトを調整しようとしましたが、それにより、サーバーが死ぬ前にわずかに長く動作するようになりました。
問題をさらに診断するためにどこを探すべきかわかりません。私たちはまだ問題が何であるかについてstrawを把握しています:
1)AJPとTomcatのセットアップが正しくないか、古い(つまり、既知のバグ?)
2)ネットワークのセットアップ(2つのNIC対1つのNIC)が混乱またはスループットの問題を引き起こしています。
3)Webサイト自体(一般的なコード、使用されているプラットフォーム、サーブレットとJSPを備えた基本的なJavaコードはありません)
更新1:
David Pashleyの有益なアドバイスに従って、問題の発生時にスタックトレース/スレッドダンプを行いました。私が見つけたのは、200個のスレッドすべてが次のいずれかの状態にあったことです。
"TP-Processor200" daemon prio=1 tid=0x73a4dbf0 nid=0x70dd waiting for monitor entry [0x6d3ef000..0x6d3efeb0]
at oracle.jdbc.pool.OracleConnectionCacheImpl.getActiveSize(OracleConnectionCacheImpl.java:988)
- waiting to lock <0x7e3455a0> (a oracle.jdbc.pool.OracleConnectionCacheImpl)
[further stack trace removed for brevity]
"TP-Processor3" daemon prio=1 tid=0x08f142a8 nid=0x652a waiting for monitor entry [0x75c7d000..0x75c7ddb0]
at oracle.jdbc.pool.OracleConnectionCacheImpl.getConnection(OracleConnectionCacheImpl.java:268)
- waiting to lock <0x7e3455a0> (a oracle.jdbc.pool.OracleConnectionCacheImpl)
[further stack trace removed for brevity]
不思議なことに、200個のスレッドのうち、1個のスレッドだけがこの状態にありました。
"TP-Processor2" daemon prio=1 tid=0x08f135a8 nid=0x6529 runnable [0x75cfe000..0x75cfef30]
at java.net.SocketInputStream.socketRead0(Native Method)
at java.net.SocketInputStream.read(SocketInputStream.java:129)
at oracle.net.ns.Packet.receive(Unknown Source)
at oracle.net.ns.DataPacket.receive(Unknown Source)
at oracle.net.ns.NetInputStream.getNextPacket(Unknown Source)
at oracle.net.ns.NetInputStream.read(Unknown Source)
at oracle.net.ns.NetInputStream.read(Unknown Source)
at oracle.net.ns.NetInputStream.read(Unknown Source)
[further stack trace removed for brevity]
このスレッド内のOracleドライバーは、他のすべてのスレッドが完了するまで待機するように強制している可能性があります。何らかの理由で、この読み取り状態のままになっている必要があります(サーバーは自動的に回復しないため、再起動が必要です)。
これは、サーバーとデータベース間のネットワーク、またはデータベース自体に関連している必要があることを示唆しています。診断作業は継続していますが、ヒントがあれば参考になります。