ELB-httpd間で408エラー多発
みなさんこんにちは。
今日は、この間遭遇したちょっとawsな話をしたいと思います。
最近、後輩からこんなお悩み相談を受けました。
「なんかapacheのログに謎の408エラーが出てるんですよね~」
どれどれっ?と、ログを見ると、確かに下記のようなログが出力されていました。
accesslog
x.x.x.x - - [23/Oct/2015:20:23:07 +0000] "-" 408 - "-" "-"
x.x.x.x - - [23/Oct/2015:20:23:11 +0000] "-" 408 - "-" "-"
408?初見、、
request timeout?なぜ、、
だったので、とりあえずググりました。
対処の方法と、メカニズムについて触れていきたいと思います。
まずは対処方法
「困った!すぐになんとかしたい!」というせっかち方は、
とりあえずここだけ見て対処してください。
- ELBのパラメータ"Connection Settings: Idle Timeout"をチェック(default:60sec)
- httpdのタイムアウト値"mod_reqtimeout:header"をチェック(default:20-40sec)
- ELBのパラメータ<httpdのタイムアウト値となるよう、設定を見直す
※なお、本事象は下記のケースで発生することが多いです。
理由は後述ということで。
なぜ発生するか?
まず、概要図から見ていきましょう。
ざっくりこんな感じですよね。所定のやつです。
今回の原因は、それぞれが下記のような動きをするためです。
- ELBは、コネクション生成コストの低減のため、常設コネクションを確立
- 1.の常設コネクションは、60秒毎に再生成される。
- httpdは、tcpコネクションを張ったのち、20-40秒のうちにhttpヘッダがこないコネクションは破棄
→408 request timeout(=クライアントから何も来なかったのでタイムアウト~)となるわけです。
ちなみに、この408はhttpdがクライアントに対して発行するタイムアウトであって、サーバ側の問題ではありません。
ELBの動きについての詳細は下記にのっています。
http://aws.typepad.com/aws_japan/2014/07/elb-idle-timeout-control.html
備考
apache側の動きについて
mod_reqtimeoutの公式マニュアルを見ると、下記のように記載があります。
今回触れている設定は、3のケースですね。
3.Allow at least 10 seconds to receive the request including the headers. If the client sends data, increase the timeout by 1 second for every 500 bytes received. But do not allow more than 30 seconds for the request including the headers:
- コネクション形成から10秒以内のヘッダを含むリクエストを許可
- クライアントがデータ(=ペイロード?)を500byteずつ送る場合、タイムアウト値を1秒ずつ伸ばす
- コネクション形成から30秒以上経過したのち、ヘッダを含むリクエストが届いた場合、拒否
(だいたいこんな感じ?あってるのかな。。)
つまり、apacheの設定がdefaultの場合、40秒未満でELBがコネクションを張りなおせばOKということですかね。
発生しやすい条件について
今回この問題が発生する理由は、
ELBがコネクションを張りなおすまでに、httpdが接続を切るため
なわけです。
そして、httpdの該当の設定は、httpd 2.4系以降でデフォルトの設定となっています。
※httpd 2.2系ではデフォルト無効
そのため、httpdをリポジトリからインストールした際に、2.4系がインストールされる下記のOSは、本ケースにぶつかりやすいと考えられます。
また、Ubuntu12.04 LTSの場合はhttpd2.2系がインストールされますが、今回の問題の原因であるmod_reqtimeoutがデフォルトで有効になっているとのことです。
そのため、12.04以降のUbuntuを使用する場合は、同様の事象が発生する可能性がそれなりにあると考えられるため、注意が必要です。
タイムアウトに困らされない豊かな人生を歩みたいものですね。
それでは。