Cygwin + apache2 + mongrel_cluster の構成が流行らしい(2年前?)

最初に言っておく

Cygwin は流行ではないよ・・・。

mongrel_cluster をインストール

薄々気づいていたけど(いや、めちゃめちゃ遅いんだけど)rails は 1 プロセスで 1 リクエストしか処理できないとな。単純に、

$ ruby script/server

としても 1プロセスしか起動していないので、複数リクエストが来た場合には処理待ちとなってしまう。なのでプロセス数を増やして同時に処理できる数を増やす構成にするようだ。rails のプロセスを増やすには mongrel_cluster を使うのだ。

$ gem install mongrel_cluster -y

でインストール(mongrelが入ってる前提で)。その後、rails アプリケーションのルートに移動して

$ mongrel_rails cluster::configure -N 5

とする。これでプロセスが 5 つ立ち上がる設定が config/mongrel_cluster.yml にできる。デフォルトでポートは3000から使用されるので、この場合「3000,3001,3002,3003,3004」となる。

Apache2 を setup.exe からインストールする

Admin にある cygrunserv と Web にある apache2 をインストール
そして、Cygwin 用のおまじないを・・・

export CYGWIN='server'
export ntsec='binmode server'

↑.bashrc に環境変数を登録。

$ cygserver-config

↑yes を入力。

net start cygserver

↑サービス開始のメッセージが表示される。

次はリクエストの振り分け。apache2 の proxy_balancer_module という優れものを使用する。httpd.conf を編集。

ProxyPass / balancer://127.0.0.1/
ProxyPassReverse / balancer://127.0.0.1/

BalancerMember http://127.0.0.1:3000 loadfactor=10
BalancerMember http://127.0.0.1:3001 loadfactor=10
BalancerMember http://127.0.0.1:3002 loadfactor=10
BalancerMember http://127.0.0.1:3003 loadfactor=10
BalancerMember http://127.0.0.1:3004 loadfactor=10

これにより、デフォルトの80番ポートへ来たリクエストを各 mongrel のプロセスへ渡してくれる。

後は起動するのみ。

$ mongrel_rails cluster::start
starting port 3000
starting port 3001
starting port 3002
starting port 3003
starting port 3004

$ usr/sbin/apachectl2 -k start

http://apl/control の様な url へアクセスすると、 http://apl:3000/control へアクセスした場合と同じ(?)になる。もちろん loadfactor で指定した重み付けに従ってプロセスが変わってくる。

log フォルダの下に mongrel.3000.log というポート番号が付いたログファイルができるので、config/routes.rb に puts "hogehoge" とか入れておくとログに出力されて各プロセスにリクエストが飛んでいるかが分かるかと。

セション情報

rails の場合、セション情報を tmp/sessions の下に保存しているので、 Aプロセスで動いてる rails アプリ上で例えば session[:key] = value で値を保持したとしても、Bプロセスでそれを取り出すことができる。ファイルIOがどれほど性能に影響有るのかは良く分からんけど・・・DBアクセスに比べればゴミみたいなもんだろう。あと同時にセションのファイルに書き込みが走った場合はどうなるのかな、次試してみよう。

もう一つ問題

$ mongrel_rails cluster::stop

としても停止しない・・・。仕方ないので強引に止めると言うより消すスクリプト書いてみた。ruby のプロセスを kill して、pid ファイルと session ファイルを削除する。

require 'fileutils' 
 
self_pid = Process.pid 
puts "self_pid = #{self_pid}" 
 
list = `ps -ef | grep ruby` 
 
for line in list 
  pid = line.split[1] 
  if pid.to_i != self_pid 
    cmd = "kill -9 #{pid}" 
    puts cmd 
    `#{cmd}` 
  end 
end 
  
Dir.chdir("tmp/pids") 
FileUtils.remove(Dir.glob("mongrel.*")) 
  
Dir.chdir("../tmp/sessions") 
FileUtils.remove(Dir.glob("*"))