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、とかそんな雰囲気の機能だと勝手に解釈しました。