Apache Bench (ab) の Failed Requests (length) について
なんかabってそれぞれのリクエストでレスポンスの長さが違うとエラーとして扱うよねっていう話。今更感高い記事だけど検証したらスッキリした!
以下のような検証用のコードを書きます。/ にGETリクエストがきたときに、ランダムな数値を文字列化し、HTTP Bodyでレスポンスしているだけのコードです。
test_serv.rb
require 'sinatra' get '/' do rand().to_s + "\n" end
試しに実行し、挙動の確認を行います
$ ruby test_serv.rb -p 4649 == Sinatra/1.4.4 has taken the stage on 4649 for development with backup from Thin Thin web server (v1.6.1 codename Death Proof) Maximum connections set to 1024 Listening on localhost:4649, CTRL+C to stop
別の端末からcurlにより試してみます
$ curl http://127.0.0.1:4649/ 0.860648458247631 $ curl http://127.0.0.1:4649/ 0.7143947518258901
どうやら毎回ランダムな値が返却されているようです。さて、本題であるこのようなAPIに対しapache bench(ab)を実行してみます
先ほどcurlを実行した端末から以下のようなコマンドで確認を行います
$ ab -n 100 -c 10 http://127.0.0.1:4649/ ...(省略)... Complete requests: 100 Failed requests: 35 (Connect: 0, Receive: 0, Length: 35, Exceptions: 0) ...(省略)...
出ました。Failed Requests 35。35件失敗として認識されていて、すべて Length Failed であるようです。本当に「それぞれのレスポンスの長さが違うことによりLengthエラーが起きてること」を確認する術の一つとして、この状態で ab のリクエスト数を1件に 変えて実行してみました。
$ ab -n 1 -c 1 http://127.0.0.1:4649/ Complete requests: 1 Failed requests: 0
無事成功しました。Failed requests 0。こちらのコマンドを3回ぐらい試行しましたがすべて問題なくFailed数は0。
そういえば先程の例で毎回ランダムな数値を返却しているはずなのに、Failed Requestが100ではなく、35だけであるのはなんだかおかしい気がしてきます。
やはり Length Failed という言葉通り、レスポンスの長さだけを見ていて内容の変化を見ていないのではないかと思いテストしてみることに。
今度はきっちりとレスポンスの長さが固定で内容だけがランダムになるようにしてみます。
require 'sinatra' get '/' do random_value = (rand() * 100).round # 0 - 99 の値になるはず random_value_s = sprintf("%02d", random_value) # 0パディングします "#{random_value_s}\n" end
$ curl http://127.0.0.1:4649/ 81 $ curl http://127.0.0.1:4649/ 79 $ curl http://127.0.0.1:4649/ 60
数値はゼロパディングされているはずなので常に二桁の数値になるはずです。
これに対し、abを実行してみた結果が以下です。
$ ab -n 100 -c 10 http://127.0.0.1:4649/ ...(省略)... Complete requests: 100 Failed requests: 0 Write errors: 0 ...(省略)...
うまくいきました。Failed requests 0。というわけでやはりレスポンスのlengthしか見ていないようです。
lengthではなく中身が違っていることを確認するオプションはないのかマニュアルを見てみたけどなさそう?
普通、HTMLのコンテンツは日付情報を含むことも多いだろうからこの仕組みは仕方ないかなとは思います。