「ELBからの通信で408が多発する」件で、結局どうすべきか調べたのでまとめた
少し前にQiitaにこんなエントリが載っていました。問題としては、ELB配下に配置したApacheサーバで、レスポンスコード408で中身のないログが数秒おきに出続けるというものです。
AWS - ELBからの通信で408が多発する - Qiita
この現象は、自分のところでも出ていて、このエントリにあるように公式フォーラムを見ても解決せず、原因がわからず困っていました。このエントリを見て、自分でも検証してみましたが、事象の分析としては、このQiitaのエントリにある内容の通りみたいです。
TCPコネクションを張ったあと、HTTPデータが来ないため、mod_reqtimeoutがDoSと判定して、apacheがコネクションを終了させている。
この件をググって見つけたのですが、qpstudyのリーダーこと、@iaraさんも2年前にこれを取り上げていますね。
この問題に当たっている環境
上記のQiitaの情報を元に検証した結果、具体的にこの問題が出る環境は以下の通り。(CentOS6, 7, Ubuntu12.04 LTS, 14.04 LTSで確認)
Apache 2.2.15以降で、mod_reqtimeoutが有効化されているもの
- 2.2.15 からmod_reqtimeoutが入っているが、2.2系ではデフォルト無効のため、CentOS 6 のhttpdパッケージではこの問題に該当せず。
- ただし、Ubuntu 12.04 LTSのapache2パッケージには、以下の設定が入っているため、問題が発生。
- /etc/apache2/mods-available/reqtimeout.conf
- RequestReadTimeout header=20-40,minrate=500
- RequestReadTimeout body=10,minrate=500
- 参考: mod_reqtimeout - Apache HTTP Server Version 2.2
- 2.2.15 からmod_reqtimeoutが入っているが、2.2系ではデフォルト無効のため、CentOS 6 のhttpdパッケージではこの問題に該当せず。
Apache 2.4系
- Apache 2.4系では、mod_reqtimeoutがデフォルトで有効になっており、デフォルト値は「header=20-40,MinRate=500 body=20,MinRate=500」となっている。
- 参考: mod_reqtimeout - Apache HTTP Server Version 2.4
問題への対処法
対処法は、Qiitaのエントリにある通り、ELBの設定の「Description」タブから「Connection Settings: Idle Timeout」を「RequestReadTimeout header」の最低値よりも小さくすること。
「RequestReadTimeout header」は、HTTPヘッダ受信のタイムアウトで、モバイル通信で極端に回線状態が悪くなければ通常は数秒もかかりません。これはもともと「slowloris」という攻撃の対策で入ったモジュールで、攻撃を受けやすい環境であれば、20秒よりも短くすることも検討した方がいいパラメータです。そのため、こちらを長くしたり無効化するのはあまりおすすめできません。
一方、ELBの「Connection Settings: Idle Timeout」は、アイドル状態のコネクションを維持する時間の設定なので、パフォーマンスチューニングの範囲の設定変更になります。そもそも、Apache2.2、2.4は「KeepAliveTimeout」のデフォルト値は5秒で、そこで接続を切ってコネクション再接続のコストとサーバ側リソースのバランスをとっているので、こちらを特にいじっていない環境では、「Connection Settings: Idle Timeout」も「5秒」まで短くしても問題ないと思います。ただ、ELBとの接続なので、クライアントとサーバとの関係が1対1とないところが、少し悩ましいですね。。。
とはいえ、特に「KeepAliveTimeout」を長く設定している環境でなければ、「Connection Settings: Idle Timeout」を5秒〜20秒に設定するがFAだと思います。
これからCentOS 7が本格的に使われ始めると、これに当たる人が結構出てきそうですね。数年前からこの問題にぶつかっていた人は、Ubuntuユーザが多そうです。
以上。