ruby-1.9.1でSwiftiply+merbクラスタ
EC2のサーバ上でruby-1.8.x系で動作しているpassenger(aka mod_rails)
と平行して、ruby-1.9.1を動かす環境を用意するために色々と試行錯誤を繰り返していたのですが、ひとまず良さそうな構成に落ち着いたのでメモしておきます。
構成
入り口から順に並べるとこんな感じです。
- apache2 (:80)
- mod_proxy_balancer (:80 -> :4000)
- swiftiply (:4000 <- :30000)
- merb cluster with SwiftipliedMongrel adapter (:30000)
apache2はpassengerを使っているので外せないとして、
ruby-1.9.1で動かすサービスはmod_proxy_balancerを使う事にしました。
最初はバックエンドに直接merb clusterを当てていたのですが、
現状のmerb clusterにはgraceful reloadする機能が無いようだったので、
間になにか挟む事にしました。
そこで、以前から目を付けていた
Swiftiply
を試す事にしました。
Swiftiplyはとても面白い設計のウェブサーバで、そのへんは
rakutoさんの記事
「[Rails] Swiftiplyのアーキテクチャとベンチマーク」
を読むのがわかりやすいでしょう。
merbはbuilt-inでSwiftiply用のアダプター(SwiftipliedMongrel adapter)を備えているので、Swiftiplyを起動する設定をおこなえば、使うのはわりと簡単です。
しかし、例によってswiftiplyが依存しているeventmachineがruby-1.9.1
でインストール出来なかったので、原因を調査。
単純にテストの実行だけがうまく動いてないようだったので、テスト無しでインストールしました。
あとは、swiftiplyの起動スクリプトを用意。
/etc/init.d/swiftiply
ruby>>
#!/usr/bin/env ruby
PID = "/var/run/swiftiply.pid"
case ARGV[0]
when 'start'
if File.exist?(PID)
puts "swiftiply is already started."
exit 1
end
print "Starting swiftiply: "
pid = fork do
Process.setsid
Process.exec "swiftiply", "-c", "/etc/swiftiply.yml"
end
begin
open(PID, "w"){|file| file.write pid}
puts "done"
rescue Exception => e
puts e.message
Process.kill 9, pid
end
when 'stop'
print "Stopping swiftiply: "
begin
pid = open(PID).read.to_i
File.unlink PID
Process.kill 9, pid
puts "done"
rescue Exception => e
puts e.message
end
when 'restart'
system $0, 'stop'
system $0, 'start'
else
puts "usage: {start|stop|restart}"
end
<<--
アプリケーションの起動、停止は以下のようにおこないます。
pre>>
cd #{current_path}; #{merb} -K all
cd #{current_path}; #{merb} -e production -a swift -c 1 -p 30000
<<--
これで動きますが、プロセスが死んだりすると不安なので、
monitを使って死活管理をおこなうようにします。
/etc/monit/monitrc
pre>>
check process swiftiply
with pidfile /var/run/swiftiply.pid
group root
start program = "/etc/init.d/swiftiply start"
stop program = "/etc/init.d/swiftiply stop"
if failed port 4000 then restart
if 5 restarts within 5 cycles then timeout
check process merbist
with pidfile /mnt/app/merbist/current/log/merb.30000.pid
group root
start program = "/mnt/app/merbist/shared/script/start"
as uid app and gid app
stop program = "/mnt/app/merbist/shared/script/stop"
as uid app and gid app
if failed port 30000 then restart
if 5 restarts within 5 cycles then timeout
depends on swiftiply
<<--
以上で完了。
現在、http://merbi.st/ は上記の設定で動いています。
See Aslo
追記
しばらく運用してみたのですが、プロセスが数時間に一回ぐらいのペースで落ちる問題があったので、Swiftiplyの代わりにPoundを使う構成に変えました。
Swiftiplyは次のバージョン0.7.0から、クラスタリングのサポートが強化されるようなので、それまで待ってみた方が良いかもしれないですね。