external process はマルチプロセスで動くのか?

という検証。 http://d.hatena.ne.jp/yssk22/20090615#1245080242 の続き。CouchDBがインテリジェントにプロセスハンドリングをしてくれるのであれば、External Process に対して連続してリクエストがきても、前のプロセスが終了していなければ、別途プロセスを起動して処理する、とかそんなことをしてくれるかなー、という淡い期待を抱いて。

結論。シングルプロセス。期待ははずれました。つまるところ、普通のWebのURIエンドポイントとして使っちゃ駄目。バッチ処理のリクエスト先とした方がいい。


こんな具合に、必ず1秒かかる処理を実施する。

require 'rubygems'
require 'json'
require 'logger'

run = true
while run do
  input = gets
  if input == nil
    run = false
  else
    res = { :code => 200,
      :json => { :data => "Hello" },
      :headers => { "Content-Type" => "text/plain" }}
    puts res.to_json
    sleep 1
    puts ""
    $stdout.flush
  end
end

で、ab -n 100 -c 10 でとばすわけです。/social/rpc? となっているのは、OpenSocial のRPCエンドポイントとして使おうとしているからなんです。

Server Software:        MochiWeb/1.0
Server Hostname:        webjourney.local
Server Port:            5984

Document Path:          /social/rpc?st=john.doe%3Ajohn.doe%3Aappid%3Acont%3Aurl%3A0%3Adefault
Document Length:        16 bytes

Concurrency Level:      10
Time taken for tests:   100.507 seconds
Complete requests:      100
Failed requests:        9
   (Connect: 9, Receive: 0, Length: 0, Exceptions: 0)
Write errors:           7
Total transferred:      18624 bytes
HTML transferred:       1552 bytes
Requests per second:    0.99 [#/sec] (mean)
Time per request:       10050.651 [ms] (mean)
Time per request:       1005.065 [ms] (mean, across all concurrent requests)
Transfer rate:          0.18 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0 5677 2389.2   4930   10076
Processing:     0 3923 3094.7   5086   17304
Waiting:        0 3963 3049.4   5086   17304
Total:       2001 9600 1810.6  10017   17305

まぁそういうわけで、Concurrency Level が 10 なのに100発リクエストとばして100秒かかってますから、論外でしょう。プロセスは1個だけ1度起動したら常駐して、死んだら立ち上げ直してくれるけど、同時起動数は1。で、stdin/stdout でJSONをやりとりするわけだから、当然マルチスレッド実行できるわけもなく。しかも、1割失敗していて、これは、ErlangのプロセスとRubyプロセスのパイプがぶっ壊れた、とかそんな感じのログがでてた。

使い方としては、stdin読み取ったらスレッド起動して、すぐに201 Accepted を返すのがいいように思います。スレッドの処理の結果はDBに"あとで"いれるとか、そんな感じで。

RBDだろうがCouchDBだろうが、データを扱う以上、やっぱりバッチシステムというのは考えなければいけな胃ケースはあって、そんなバッチシステムを蹴るためのURI、とかそんな雰囲気の機能だと勝手に解釈しました。