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?なぜ、、

だったので、とりあえずググりました。

対処の方法と、メカニズムについて触れていきたいと思います。

まずは対処方法

「困った!すぐになんとかしたい!」というせっかち方は、

とりあえずここだけ見て対処してください。

  1. ELBのパラメータ"Connection Settings: Idle Timeout"をチェック(default:60sec)
  2. httpdタイムアウト値"mod_reqtimeout:header"をチェック(default:20-40sec)
  3. ELBのパラメータ<httpdタイムアウト値となるよう、設定を見直す

※なお、本事象は下記のケースで発生することが多いです。

  • centos7系、ubuntu12.04LTS以降(後述のhttpdバージョンがデフォルト2.4以上のため)
  • httpdのバージョンが2.4以上(httpd -vでチェック)

理由は後述ということで。

なぜ発生するか?

まず、概要図から見ていきましょう。

f:id:iryond:20151025151422p:plain

ざっくりこんな感じですよね。所定のやつです。

今回の原因は、それぞれが下記のような動きをするためです。

f:id:iryond:20151025152917p:plain

  1. ELBは、コネクション生成コストの低減のため、常設コネクションを確立
  2. 1.の常設コネクションは、60秒毎に再生成される。
  3. 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の公式マニュアルを見ると、下記のように記載があります。

f:id:iryond:20151025153336p:plain

今回触れている設定は、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を使用する場合は、同様の事象が発生する可能性がそれなりにあると考えられるため、注意が必要です。




タイムアウトに困らされない豊かな人生を歩みたいものですね。

それでは。