概要
内部ネットワークからインターネットへのアクセスをプロキシしているサーバで稀に 502 Bad Gateway のエラーを返していることがありました。
リクエスト元のサーバではリトライ処理を入れていたので問題は無かったのですが、通常時は 200 で成功しているリクエストが、突然 502 で失敗してしまうのは謎でした。
今回、その時に調査したことをまとめました。
エラー文言
リモートサーバのステータスラインの読み込みに失敗しました。
proxy: error reading status line from remote server...
ステータスラインとは HTTP/1.1 200 OK のことです。
HTTP の Version と HTTPステータスコードとメッセージが一行に記載されています。
おそらくリモートサーバにプロキシ出来ていないんだと思います。
原因
これは Apache 2.1 以降の機能で ProxyPass を利用する際に、コネクションプールを使うようになったのが原因です。
コネクションプールとは、リクエストの度にコネクションを生成するのではなく、コネクションを事前に用意しておいて再利用しようと言う考え方(仕組み)のことです。
コネクションを再利用することで、コネクションを生成する時にかかる(接続に必要とされる)オーバーヘットをカットして双方の負荷を軽減してくれます。
このエラーは事前に用意されたコネクションを使って接続しようとしたら、接続中にコネクションを切られてしまい接続できなかった時に発生するエラーだと思われます。
参考:mod_proxy - Apache HTTP サーバ バージョン 2.4
解決策
コネクションプールを使わない設定を追加します。
SetEnv proxy-initial-not-pooled 1
Apache の公式ドキュメントにも proxy: error reading status line from remote server のエラーが起きたらこれを設定してと書いてあります。
ただし、注意点としてコネクションプールを使わない場合、リクエストの度にコネクションを生成するので、パフォーマンスが劣化するらしいです。
参考:mod_proxy_http - Apache HTTP Server Version 2.4
パフォーマンス確認
パフォーマンスが劣化すると書いてあったので、proxy-initial-not-pooled の設定を追加したサーバでしばらく様子を見ました。
サーバの CPU 使用率やメモリ使用率は設定を追加した前後で変化はありませんでした。
Apache のレスポンスタイムも特に遅くなったりせず、設定を追加したことによって他のエラーが発生するなどの事象も起きませんでした。
おそらく、影響度はサーバの負荷(リクエスト数)によって違うんだと思います。
ちなみに、今回対応したサーバの秒間リクエスト数は 50 以下でした。
パフォーマンスが劣化した場合は、プロキシサーバを増設して負荷を分散できればパフォーマンスの劣化も防げるかも知れませんね。