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

   1  #!/usr/bin/env ruby
   2  
   3  PID = "/var/run/swiftiply.pid"
   4  
   5  case ARGV[0]
   6  when 'start'
   7    if File.exist?(PID)
   8      puts "swiftiply is already started."
   9      exit 1
  10    end
  11    print "Starting swiftiply: "
  12    pid = fork do
  13      Process.setsid
  14      Process.exec "swiftiply", "-c", "/etc/swiftiply.yml"
  15    end
  16    begin
  17      open(PID, "w"){|file| file.write pid}
  18      puts "done"
  19    rescue Exception => e
  20      puts e.message
  21      Process.kill 9, pid
  22    end
  23  when 'stop'
  24    print "Stopping swiftiply: "
  25    begin
  26      pid = open(PID).read.to_i
  27      File.unlink PID
  28      Process.kill 9, pid
  29      puts "done"
  30    rescue Exception => e
  31      puts e.message
  32    end
  33  when 'restart'
  34    system $0, 'stop'
  35    system $0, 'start'
  36  else
  37    puts "usage: {start|stop|restart}"
  38  end

アプリケーションの起動、停止は以下のようにおこないます。

   1  cd #{current_path}; #{merb} -K all
   2  cd #{current_path}; #{merb} -e production -a swift -c 1 -p 30000

これで動きますが、プロセスが死んだりすると不安なので、 monitを使って死活管理をおこなうようにします。

/etc/monit/monitrc

   1  check process swiftiply
   2    with pidfile /var/run/swiftiply.pid
   3    group root
   4    start program = "/etc/init.d/swiftiply start"
   5    stop program = "/etc/init.d/swiftiply stop"
   6    if failed port 4000 then restart
   7    if 5 restarts within 5 cycles then timeout
   8  
   9  check process merbist
  10    with pidfile /mnt/app/merbist/current/log/merb.30000.pid
  11    group root
  12    start program = "/mnt/app/merbist/shared/script/start"
  13      as uid app and gid app
  14    stop program = "/mnt/app/merbist/shared/script/stop"
  15      as uid app and gid app
  16    if failed port 30000 then restart
  17    if 5 restarts within 5 cycles then timeout
  18    depends on swiftiply

以上で完了。

現在、http://merbi.st/ は上記の設定で動いています。

See Aslo

追記

しばらく運用してみたのですが、プロセスが数時間に一回ぐらいのペースで落ちる問題があったので、Swiftiplyの代わりにPoundを使う構成に変えました。 Swiftiplyは次のバージョン0.7.0から、クラスタリングのサポートが強化されるようなので、それまで待ってみた方が良いかもしれないですね。

posted by Png genki on Fri 20 Feb 2009 at 16:23

Ruby-1.9.1を使うと、 以下のようにして簡単にRubyVMのInstaractionSequenceを見る事が出来ます。

   1  >> puts RubyVM::InstructionSequence.new("puts 'Hello, world!'").disasm #=> nil
   2  == disasm: <RubyVM::InstructionSequence:<compiled>@<compiled>>==========
   3  0000 trace            1                       (   1)
   4  0002 putnil           
   5  0003 putstring        "Hello, world!"
   6  0005 send             :puts, 1, nil, 8, <ic>
   7  0011 leave            

生成したInstractionSequence(aka iseq)は、evalメソッドを呼び出して実行する事もできます。

   1  >> RubyVM::InstructionSequence.new("puts 'Hello, world!'").eval #=> nil
   2  Hello, world!

さらに、to_aメソッドで個々のインストラクションに分解する事も出来ます。

   1  >> RubyVM::InstructionSequence.new("puts 'Hello, world!'").to_a
   2  ["YARVInstructionSequence/SimpleDataFormat", 1, 1, 1, {:arg_size=>0, :local_size=>1, :stack_max=>2}, "<compiled>", "<compiled>", :top, [], 0, [], [1, [:trace, 1], [:putnil], [:putstring, "Hello, world!"], [:send, :puts, 1, nil, 8, nil], [:leave]]]

posted by Png genki on Fri 20 Feb 2009 at 01:49
Contents
ruby-1.9.1でSwiftiply+merbクラスタ
Ruby-1.9.1を使ってRubyVMを身近に感じてみる
Comments
dsjf: https://gist.github.com/6bf1bf2c3cbb5eb6e7a7 これ... '13-1
瀧内元気: おお、チェックしてみます。thx! '11-12
overisland: Reeder for iPhone もこの UI を実装していますね。 '11-12
瀧内元気: その情報は見たのですが、以下のサイトによると、現在はまた必要になってるっぽいんですよね。 ... '11-12
tkawa: http://devcenter.heroku.com/articles/rails31_he... '11-12
Services from s21g
twpro(ツイプロ)
Twitterプロフィールを快適検索
地価2009
土地の値段を調べてみよう
MyRestaurant
自分だけのレストラン手帳
Formula
ブログに数式を埋め込める数式コミュニティ