RubyのCGIプログラムがWindowsで激重な件の対応
症状
Linux上でサクサク動いていた Ruby の CGI プログラムを Windows に移植するとレスポンスがめちゃくちゃ遅くなってしまった。いろいろ調べると require 時のI/O処理が重いらしい。
I/O自体を高速化する方法などを調べたがヒットしなかった。さすがに重すぎて実用に耐えられないのでどうしようか悩む。。。
対応策
dRubyを使って処理を分散させる方法を見つけた。
要するにボトルネックとなる require を含む重い処理をまとめてマシン立ち上げ時に一発実行し、アクセスの度に起きる cgi では dRuby で立ち上げておいたリモートオブジェクトにリクエストを渡して処理するという方法。
リモートオブジェクトは戻り値としてレスポンスの文字列を返すようにし、受け取った cgi はそれを print する。 cgi では 'drb/drb' と 'cgi' くらいしか require しなくて済むため高速化が期待できる。
具体例
■todo_srv.rb #!C:/ruby/bin/ruby.exe require 'drb/drb' # こいつらが重い処理 require "rubygems" require "active_record" require "uri" require "kconv" class Todo def do_request(input) mode = input['mode'].first # レスポンス作成処理 case mode : return res end end def main() # dRuby でリモートオブジェクトを生成して寝て待つ uri = "druby://localhost:12345" DRb.start_service(uri, Todo.new) puts DRb.uri sleep end main()
■todo.cgi #!C:/ruby/bin/ruby.exe require "drb/drb" require "cgi" input = CGI.new # 作っておいたリモートオブジェクトを取得 todo = DRbObject.new_with_uri('druby://localhost:12345') print "Content-type: text/html\n\n"; # リクエストを渡し、結果を print することでレスポンスを返す print todo.do_request(input.params)
上記のように元々1ファイルの cgi で頑張っていた処理を2ファイル構成にし、todo_srv.rb をあらかじめマシン起動時に実行しておくことで、ボトルネックとなっていた重いrequire の処理群を初回の一度のみに集約できる。そして todo.cgi ではリモートオブジェクトから結果をもらうだけなのでレスポンスが劇的に速くなった。(約10秒掛かっていたレスポンスが1秒未満に!)
dRuby は初めて使ってみたけれど、かなり使えるなぁ。