Apache + Tomcatの通信に問題があります。不明なエラーメッセージ。TomcatでホストされているWebサイトを停止する


22

セットアップ:
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ドライバーは、他のすべてのスレッドが完了するまで待機するように強制している可能性があります。何らかの理由で、この読み取り状態のままになっている必要があります(サーバーは自動的に回復しないため、再起動が必要です)。

これは、サーバーとデータベース間のネットワーク、またはデータベース自体に関連している必要があることを示唆しています。診断作業は継続していますが、ヒントがあれば参考になります。


最初に、これは驚くほど書かれた質問です。詳細に素晴らしい仕事!次に、proxy_ajpまたはmod_jkを使用してApacheサーバーとTomcatサーバーを接続していますか?
オフィディアン

proxy_ajpを使用して2つを接続しています。
ジョーディブーム

siege、joedog.org / siege-homeを使用してストレステストを行います。
paalfe 14

回答:


9

このバージョン(クラス12-かなり古い)のOracleドライバーには、デッドロックを引き起こすさまざまなバグがありました(上記のTP-Processor2状態で見られるように)。新しい環境に切り替えるまでアクティブになりませんでした。最新バージョン(ojdbc14)にアップグレードすると、プライマリサーバーの問題が解決されました。


これにより正しい解決策に導かれました。DB行にロックがかかっていましたが、App-Serverで例外が発生しませんでした
cljk 14

6

説明から、問題の原因はデータベースクエリに時間がかかりすぎている可能性があることをお勧めします。クエリに時間がかかると、リクエストに時間がかかるため、より多くのクエリを一度に実行できます。ご覧のとおり、Tomcatスレッドが不足しています。データベースの問題を解決するときは大丈夫です。

  • jstackを使用するか、kill -3 $ process_idを使用して、スタックトレースを取得します。スレッドが死んだときのスレッドの動作を確認します。彼らがすべてデータベースを待っているなら、それは私の理論への良い指針です。彼らはすべて何らかのロックを待っているかもしれません。
  • LambdaProbeをインストールします。あなたのTomcatが何をしているかを知るのに非常に貴重です。
  • Tomcatをアップグレードします。5.5.8は非常に古いです。現在5.5.27になっていると思います。

David、スレッドダンプ/スタックトレースの提案に基づく新しい調査結果で質問(Update 1を参照)を更​​新しました。
ジョーディブーム

データベース接続プールは、Tomcatの最大接続値に比べて小さすぎることをお勧めします。ほとんどのスレッドがデータベース接続の取得を待機しているようです。
デビッドパシュリー

多くのスレッドが存在する唯一の理由は、通常使用されているスレッドがソケットからの読み取りを試みるそのスレッドを待機しているためです。常に使用されるDB接続の数は1から3の間です。それ以上の数の必要はありません。
ジョーディブーム

5

/etc/tomcat7/server.xmlにあるAJPコネクタにconnectionTimeoutとkeepAliveTimeoutを追加します。

<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" 
           connectionTimeout="10000" keepAliveTimeout="10000" />

https://tomcat.apache.org/tomcat-7.0-doc/config/ajp.htmlのAJPコネクタに関する情報

  • connectionTimeout =接続を受け入れた後、要求URI行が表示されるまでこのコネクターが待機するミリ秒数。AJPプロトコルコネクタのデフォルト値は-1(つまり無限)です。

  • keepAliveTimeout =接続を閉じる前にこのコネクターが別のAJP要求を待機するミリ秒数。デフォルト値は、connectionTimeout属性に設定されている値を使用することです。

connectionTimeoutとkeepAliveTimeoutの値が定義されていない場合、AJP接続は無期限に維持されます。多くのスレッドが発生するため、デフォルトの最大スレッド数は200です。

Lambda Probeから分岐したApache Tomcat用の高度なマネージャーおよびモニターであるpsi-probeをインストールすることをお勧めします。https://code.google.com/p/psi-probe/


4

AJPの動作方法により、Apache間の永続的な接続(mod_proxy_ajpまたはmod_jkを使用)は、クライアントによってのみ安全に閉じることができます。この場合、クライアントは、ワーカープロセスの有効期間中、tomcatへの接続を開いて保持するApacheワーカーです。

この動作のため、Tomcatワーカースレッドより多くのApacheワーカーを持つことはできません。これを行うと、追加のhttpワーカーがTomcatに接続できなくなり(受け入れキューがいっぱいになるため)、バックエンドをDOWNとマークします!


1
長年のコメントで申し訳ありませんが、ProxyPass構成内のmax-flagをサーブレットコンテナのMaxThreadsの数に設定することでこれを保証できませんでしたか?
ホルストガットマン

2

安定性の観点から、mod_ajpの代わりにmod_proxyを使用した方が良い結果が得られたので、その解決策を試してください。非侵襲的です-せいぜい問題を解決し、最悪の場合mod_ajpを除外します。

それ以外は、Tomcatが応答を停止し、すべての要求スレッドが拘束されているように聞こえます。開発チームに現在の状況を調べてもらいます - スレッドダンプを取得して配信するのが便利です。


mod_proxyには接続が簡単であるにもかかわらず、スケーラビリティの問題があるという印象を受けました。Apache財団はmod_jk(wiki.apache.org/tomcat/FAQ/Connectors#Q2)を推奨しているようです
オフィディアン

スティッキーセッションを提供しません、本当。しかし、それ以外には問題はありませんでした。
ロバートムンテアヌ

1

サーバーがしばらく実行され、突然スローダウンし、サービス障害が発生し始めると聞いたときに最初に思うのは、RAMが不足してスワップがスラッシングしていることです。表示されているAJPの障害がタイムアウトの結果である可能性があるかどうかは明確ではありませんが、完全に不合理とは思えません。ただし、NICに接続する明白な方法はありません。いずれにせよ、これらのイベントが発生したときのメモリ使用量の推移を把握することをお勧めします。

RAMが不足している場合は、Apache MaxClientsを停止してを増やす必要がありますListenBacklog

ところで、質問をきちんと整理して完成させてくれてありがとう。


これが発生しているときに「トップ」を観察すると、メモリ使用量はほぼ一定のままです。少なくともスパイクはありません。CPU使用率が高いのはほんの一瞬です。
ジョーディブーム

1

proxy_ajpとTomcatを使用したRedhat環境でも同様のログエラーが発生しました。httpdパッケージを更新することにより解決:

yum update httpd

から:

  • httpd-devel-2.2.3-43.el5_5.3.x86_64
  • httpd-2.2.3-43.el5_5.3.x86_64

に:

  • httpd-2.2.3-45.el5_6.3.x86_64
  • httpd-devel-2.2.3-45.el5_6.3.x86_64

次に、Apacheを再起動してから、Tomcatを再起動しました。

それは私のためにそれを修正しました!

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.