酒日記

2002 09 10

Tue, 10 Sep 2002

秋味 (6% × 1000 ml)

昨日の続き。Ruby でスレッドを使った ab (Apache Bench) もどきを作ってみる。

Ruby は初めて使うので、おそらく作法的に変なことをしているであろう サンプルスクリプト。 ソースは以下。(Ruby は Kondara-2.1 附属の、ruby 1.6.5 (2001-09-19) [i586-linux])

#!/usr/bin/ruby

require 'net/http'
require 'getoptlong'

opts = {}
opts_p = GetoptLong.new(
    [ "--c", "-c", GetoptLong::REQUIRED_ARGUMENT ],
    [ "--n", "-n", GetoptLong::REQUIRED_ARGUMENT ],
    [ "--u", "-u", GetoptLong::REQUIRED_ARGUMENT ]
)
opts_p.each do |opt, arg|
    opts[opt] = arg
end

url = opts["--u"].to_s
proto, host, path = url.split("/+", 3)
path = "/" + path

threads = []
total_requests = 0
success = 0
failed  = 0
count = opts["--c"].to_i
counts = (1 .. count).to_a
limit_requests = opts["--n"].to_i

start_time = Time.now
for i in counts
    threads << Thread.new(host) { |host|
        while total_requests < limit_requests
            h = Net::HTTP.new(host, 80)
            resp, data = h.get(path, nil)
            if resp.code == "200"
                success = success + 1
            else
                failed = failed + 1
            end
            total_requests = total_requests + 1
        end
    }
end
  
threads.each { |aThread| aThread.join }

end_time = Time.now
t = end_time - start_time
requests_per_second = sprintf('%.2f', total_requests / t.to_f)

puts "Concurrency Level:      #{count}"
puts "Time taken for tests:   #{t.to_f} seconds"
puts "Complete requests:      #{success}"
puts "Falied requests:        #{failed}"
puts "Requests per second:    #{requests_per_second} [#/sec] (mean)"

特に GetoptLong の使い方は絶対間違っている気がするが・・・

起動方法などは昨日の fake_ab.pl と同じ。

$ ./fake_ab.rb -c 10 -n 1000 -u http://aqua/

とする。

...

fake_ab.pl と、fake_ab.rb、本物の ab で実行してみた結果 (-c 10 -n 1000) の Requests per second を以下に。

/index.html.dist (静的ファイル)
Perl      236.42
Ruby      124.18
ab        343.05

/index.shtml (SSI html)
Perl      178.88
Ruby      106.28
ab        229.52

/cgi-bin/printenv.cgi (環境変数を出力するだけの mod_perl CGI)
Perl      110.07
Ruby       88.74
ab        118.72

/cgi-bin/index.cgi?rm=view (PostgreSQL に接続して数十レコードを閲覧する mod_perl CGI)
Perl       12.56
Ruby       12.28
ab         12.53

(サーバ側の負荷が)軽い場合は ab > Perl > Ruby 。 重い場合は ab == Perl >= Ruby 。これだけ見ると、この処理 (標準モジュールでの HTTP GET) に関しては Ruby は Perl より重い、と結論付けたくなるのだが、gkrellm で、クライアント側の転送量を観察していると、 なぜか Ruby の時だけ output が多いことに気がつく。

ethereal でパケットキャプチャしてみたところ、Ruby は http://aqua/ を GET するにあたって、 DNS に AAAA レコードと A レコードをリクエストしている。Perl と ab は、A レコードしか引いていない。 もしかして、Ruby が遅いのはこれが原因?

ということで、名前を引かなくていいように URL を IP アドレスで指定した結果。

/index.html.dist (静的ファイル)
Perl      244.24
Ruby      191.55
ab        328.84

/index.shtml (SSI html)
Perl      197.33
Ruby      191.64
ab        222.57

/cgi-bin/printenv.cgi (環境変数を出力するだけの mod_perl CGI)
Perl      113.77
Ruby      107.18
ab        122.09

/cgi-bin/index.cgi?rm=view (PostgreSQL に接続して数十レコードを閲覧する mod_perl CGI)
Perl       12.50
Ruby       12.42
ab         12.19

Perl と Ruby の差が接近。つまり、Ruby の IPV6対応な名前解決が足を引っ張っていたらしい。 ベンチマークって、こういうことがあるから簡単に結論づけてはいけないわけですな。 奥が深い。


一番絞り 黒 (5.5% × 700 ml)


powered by blosxom