Apache/Tomcat 間の疎通について
Tomcat で Java アプリケーションを動かし、Apache を Web サーバとして利用して公開している Web アプリケーションがある。Tomcat/Apache は同一の EC2 インスタンス上で動作しており、同様の構成の EC2 インスタンス 2 つが ALB 以下にぶら下がっている。
このような構成の Web アプリケーションに対し、30 分以上かかるかなり重い処理を任せた結果、以下のようなエラーが出力された。
code:html
Internal Server Error
The server encountered an internal error or misconfiguration and was unable to complete your request.
Please contact the server administrator, you@example.com and inform them of the time the error occurred, and anything you might have done that may have caused the error.
More information about this error may be available in the server error log.
このレスポンスがどこから返ってきたものなのか知りたい。レスポンスヘッダ見ればわかったりするのかもしれないが確認するのを忘れていた。
今回の場合だと、
ALB が返してきている場合
Apache が返してきている場合
Web アプリケーション (フレームワーク) が返してきている場合
等がある。
上記エラーはどうやら Apache から返ってきているもののようで、you@example.com には ServerAdmin で設定されたメールアドレスが埋め込まれるようだ。このエラーメッセージは NCSA HTTPd 1.3 によって生成されている、といったようなことが 2.2 では記述されているが、2.4 では消えている。いずれにしろ、Apache 内で生成されているエラー文言であることは間違いない。
https://httpd.apache.org/docs/2.2/en/custom-error.html
https://httpd.apache.org/docs/2.4/en/custom-error.html
More information about this error may be available in the server error log. とエラー文にもあるように、上記エラーが発生した場合にはまず Apache のログを参照するのが良い。
ログの場所は httpd.conf 内で、CustomLog ディレクティブや ErrorLog ディレクティブで定められている。今回はエラーをみたいので後者に設定されているファイルパスに見にいけば良い。
https://httpd.apache.org/docs/current/en/mod/mod_log_config.html
今回の場合、エラーログを参照すると以下のようなエラーが発生していた。
code:text
XXX XXX 00 00:00:00 20XX error (70007)The timeout specified has expired: ajp_ilink_receive() can't receive header
ajp_ilink_receive() can't receive header というエラーは mod_proxy_ajp という Apache モジュールから吐かれているらしい。このモジュールは「mod_proxy で AJP をサポートするためのモジュール」と説明されている。
そもそも AJP ってなんだよ... となったので、それは別にまとめる。
https://httpd.apache.org/docs/2.4/en/mod/mod_proxy_ajp.html
AJP は Web サーバと Servlet コンテナ (アプリケーションサーバ) 間で通信を行うためのプロトコル。mod_proxy_ajp はリバースプロキシやフォワードプロキシでこの AJP を利用するためのモジュール。
https://weblabo.oscasierra.net/tomcat-mod-proxy-ajp/
httpd.conf を見ても、LoadModule されてないなーと思ったが、どうやら Apache のコンパイル時にオプションで ./configure --enable-so --enable-rewrite --enable-expires --enable-proxy --enable-headers --enable-proxy-ajp といった感じで、モジュール込みでインストールされていたようだった。
httpd.conf 内で、この mod_proxy_ajp を利用して、以下のように Tomcat コンテナへのプロキシが設定されていた。
code:xml
<Location /hoge/>
ProxyPass ajp://localhost:8009/hoge/
ProxyPassReverse ajp://localhost:8009/hoge/
</Location>
このプロキシのためのコネクションがタイムアウトした、というのが、今回のエラーのはず。
タイムアウトについては以下の Qiita 記事が綺麗にまとまっていそうに見える。
https://qiita.com/i_learnin/items/c7e09a3e930016226d93
Tomcat 側
HTTP コネクタは 8080 ポートでタイムアウトが 20000 秒、AJP コネクタはタイムアウトなしになっていた。
code:xml
<!-- A "Connector" represents an endpoint by which requests are received
and responses are returned. Documentation at :
Java HTTP Connector: /docs/config/http.html (blocking & non-blocking)
Java AJP Connector: /docs/config/ajp.html
APR (HTTP/AJP) Connector: /docs/apr.html
Define a non-SSL HTTP/1.1 Connector on port 8080
-->
<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" />
<!-- Define an AJP 1.3 Connector on port 8009 -->
<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />
Apache 側
特にタイムアウトの設定はされていない。
code:xml
<Location /hoge/>
ProxyPass ajp://localhost:8009/hoge/
ProxyPassReverse ajp://localhost:8009/hoge/
</Location>
しかし、よく見ると以下のタイムアウト設定がされていたので、これっぽい
code:xml
Timeout 1800
KeepAlive Off
MaxKeepAliveRequests 100
KeepAliveTimeout 5
1800 秒なので、30 分でタイムアウトする設定になってしまっているようだ。
この TimeOut がなんの TimeOut なのかについて調べて見る
WIP: 眠いので寝る
---
ちなみに、似たような状況下 (重い処理を走らせた場合) の別のパターンとして、504 Gateway timeout が発生する場合がある。自分のケースだと、これは ALB のタイムアウト時間の問題だった。
---
以下: メモ
挙動が理解できていなかったので調べる
そもそも KeepAlive が理解できていない
https://dev.classmethod.jp/cloud/aws/set_keepalivetimeout_on_apache_for_resolve_elb_timeout/
https://qiita.com/mechamogera/items/3e79ad1095ef23552da4
Apache のタイムアウトと、ELB 上の設定のアイドルタイム時間に差がある場合、どっちがどういう振る舞いを決めているのか、知りたい
50X 系が発生した時はログで観れる
https://docs.aws.amazon.com/ja_jp/elasticloadbalancing/latest/classic/ts-elb-http-errors.html#ts-elb-error-metrics-ELB_5XX
https://docs.aws.amazon.com/ja_jp/elasticloadbalancing/latest/classic/ts-elb-error-message.html#ts-elb-errorcodes-http504
https://docs.aws.amazon.com/ja_jp/elasticloadbalancing/latest/application/load-balancer-access-logs.html
参考
Apacheのドキュメント
#WIP