2008年5月5日月曜日

backgrounDRbのworkerメソッドはThread Safeでした

【状況】
apache + mod_proxy_balancer + 複数のmongrelインスタンスが待機しており、mod_proxy_balancerによってリクエストが各mongrelインスタンスに振り分けられる。

【疑問】
あるControllerのaction(worker_test)内でMiddleMan.worker(:hoge_worker).hugaを呼び出す記述を行った場合、同時にworker_testへリクエストが投げられた際にhugaは排他的に呼ばれるのか?

【実験準備】
以下のようなController, Worker, tmpファイルを用意した。

- HogeController

def worker_test
 MiddleMan.worker(:hoge_worker).huga
 render :layout => false
end


- HogeWorker

def huga
 count = 0
 open('/path-to-tmpfile', 'r') do {|f| count = f.read.to_i + 1 }
 open('/path-to-tmpfile', 'w') do {|f| f.write(count) }
end

- /path-to-tmpfile
0


以下のコマンドをターミナルから実行した。

$ ab -n 100 -c 100 http://path-to-worker-test

【結果】
Server Software: Mongrel
Server Hostname: localhost
Server Port: 80

Document Path: /path-to-worker_test
Document Length: 639 bytes

Concurrency Level: 100
Time taken for tests: 10.275617 seconds
Complete requests: 100
Failed requests: 0
Write errors: 0
Non-2xx responses: 100
Total transferred: 107900 bytes
HTML transferred: 63900 bytes
Requests per second: 9.73 [#/sec] (mean)
Time per request: 10275.617 [ms] (mean)
Time per request: 102.756 [ms] (mean, across all concurrent requests)
Transfer rate: 10.22 [Kbytes/sec] received

Connection Times (ms)
min mean[+/-sd] median max
Connect: 2 3 0.9 3 5
Processing: 584 5098 3022.2 4912 10268
Waiting: 583 5058 3002.2 4718 10268
Total: 588 5101 3021.3 4915 10270

Percentage of the requests served within a certain time (ms)
50% 4915
66% 6754
75% 7984
80% 8561
90% 9608
95% 10030
98% 10183
99% 10270
100% 10270 (longest request)


$ less /path-to-tmpfile
100

ちゃんと100になってた。ここまできてvendor/plugin/backgroundrb以下のファイルを漁ってみると、
  1. ruby script/backgroundrb startでBackgrounDRb::MasterProxy.new()してdaemonを作成
  2. vendor/plugins/backgroundrb/server/lib/master_worker.rbのMasterProxyにload_and_invokeなる関数ハケーン。「#method will load the worker and invoke worker method」と書いてあるし、workerに定義した関数を呼び出している箇所はここで間違いなさそう。
  3. worker.send_requestで関数を呼び出しているようなので、vendor/plugins/backgroundrb/lib/backgroundrb.rbを見てみる
  4. send_request内で@mutex.synchronizeしてた。
【結論】
backgrounDRbのworkerメソッドはThread Safeでした。つまり、例えばworker内でファイルを開いてどうのこうのして、という処理を行ったとしても同時に同じファイルへアクセスすることはないのでファイルが壊れる心配はないと。

【追記】
何度もテストを重ねてみると、稀にnオプションで指定した以上の数値がtmpfileに現れる現象が確認されたが、この現象が起こった際には必ずapache_access_logの行数もその分だけ増えていたので、apacheに対してnオプションで指定した以上のリクエストが投げられていたことになる。恐らくサーバーが高負荷状態にあったので何度かabコマンドによるリクエストが途中でやり直された?可能性が高い。これはRailsとかbackgrounDRbの責任ではないよね。

0 コメント: