Railsの最適化に関する10の事柄
http://weblog.textdrive.com/article/175/rails-optimizing-resource-usage
TextDriveで、Optimizing Rails Resource Usageという記事が公開されました。Railsの最適化について10の事柄を挙げています。興味がある人は原文を読んでもらうとして、ここでは軽くサマリー(意訳)を。間違っていたらコメント歓迎!
1. 最小限のFastCGI
開発には1つのDispatcherで十分。A list Apartでも4つのFastCGI Dispatcherで動かしてて速くてloadも0.01だよ。あとFCGIが増えるとDBコネクションも増えるからね。
2. キャッシュを使う
Dispatcherを通さずキャッシュを使う。Railsではとっても簡単にキャッシュ使えるし、期限設定も楽だし。lighttpdだったらこんな風に設定すればOKさ!
url.rewrite = ( "/$" => "index.html", "([^.]+)$" => "$1.html" )
俺注: Railsのキャッシュの仕組みの一つでは、http://example.com/module/action のキャッシュが静的htmlとして http://example.com/module/action.html に作られる。そのためlighttpdに上記の設定をしておくと、http://example.com/module/action にアクセスしたとき http://example.com/module/action.html にリライトされ、静的htmlがあるとそちらが呼ばれるため、Dispatcherを通さなくてすむ。ていうかこの方法使えばRails on CGI(not FastCGI)が現実的になる、かも。
3. 1,2時間以上development環境のFastCGIで動かしてはならない
developmentだとclassがリロードされ、メモリリークが生じるからだ。
4. メモリ消費量を監視する
大抵FastCGI Dispacher一つにつき20〜50-70 Mbのメモリが消費される。メモリリークしてる場合もあるよ。
5. Dispatcherファイルを変更する
デフォルトじゃGCが走らないからdispatch.fcgiを変更しよう。
RailsFCGIHandler.process! nil, 50
とRailsHCGIHandler.proccess!の第二引数に数値を指定することで、その回数Dispatcherが呼ばれたら明示的なGCが走る。development環境は5-10でいいんじゃないかな。
Psychs さんからの指摘で、現在原文ではこの設定はGC を一切実行しなくなるので良くないだろうと訂正されてます。ありがとうございます。
6. ログローテート
log/ 以下のログローテートしようよ。
俺注:ログ消してもいいときは rake clean_logs使うと便利。
7. ユニットテストを書いて走らせる
時間浪費しなくてすむよ。(俺注: わざわざRails立ち上げなくてもtestできるから、なのかな?)
8. 開発中にメモリリークをチェックする
config/enviroments/development.rbに
dependencies.mechanism = :require
って書くとdevelopmentでもメモリリークのチェックができる。Dispatcherが90MB超えるのは決してないし、通常20-70MBに収まる。そうじゃない場合はlighttpdの再起動時のdispatch.fcgiがkillできなかったか、メモリリークが起きてるかだ。
俺注:dependencies.mechanism = :require より、config.cache_classes = true (デフォルトはdevelopment.rbではfalse)にすべき。
9. 繰り返しに注意
ActiveRecordはスマートだけどこんな風に使っちゃダメだよ。
# やっちゃいけない例
#don't do this, write a JOIN query
Post.find(:all).each do |p|
p.subscribers << @user unless p.subscribers.include?(@user)
end
Post.find(:all).reject{|p| p.comments_closed? }
# こうすべき
Post.find(:all, :conditions=>"comments_closed = 0")
Post.find_all_by_comments_closed(false)
俺注: AR#findで全部取得してからイテレータ内部で条件指定するんじゃなくて、joinやconditionsつけて条件つけて取得すべきと。Webプログラマならかけ出しのころ単純なSQL条件句ですむ場合にも全部のresult取得して各種言語で取捨選択した経験があるはず。俺はあるorz
10. RailsのTracバグレポートをウォチ
毎日Railsで開発してるならウォチ必須!
http://dev.rubyonrails.com/report/1
http://dev.rubyonrails.com/report/3
俺注: RSSリーダに登録しとくといいよ