ActiveScaffold の性能をみてみました
ここ最近、各アプリケーションサーバにおける性能比をみるために、render :text => 'xxx' ばかり動かしてました。
で、ちょっと数字がですぎている気がしたので、もうちょっと複雑なアプリケーションでのスループット感覚をつかんでおきたくてやってみました。
やったこと
- ActiveScaffold を利用して単純なマスタメンテ画面を作成して、Apache Bench で性能計測
- 静的ファイル化して、public 以下に配置して性能計測
- 静的ファイル化して、app/views 以下に配置して性能計測
- ふつうの scaffold で単純なマスタメンテ画面を作成して性能計測
- will_paginate で表示データサイズを絞って (ActiveScaffold のときと同じにして) 性能計測
結果
上記番号 | Mongrel での RPS | Thin での RPS |
---|---|---|
1 | 12.91 | 13.89 |
2 | 225.01 | 1254.29 |
3 | 87.16 | 137.80 |
4 | 27.28 | 28.87 |
5 | 47.18 | 54.26 |
# RPS = Requests per second [#/sec]
# 1回ずつしか測ってないので、おかしな数字がはいってるかもしれません。 <(_ _)>
なんだかとっても遅いのですが、こんなものでしょうかね? (^^;
# PostgreSQL も Rails も ab も同一筐体ですが、CPU は振りきれてなかったです...
環境
- iMac (intel Core 2 Duo 2.33GHz)
- Mac OS X 10.5.6
- 処理系、ライブラリのバージョンは以下のとおり
% ruby186 -v ruby 1.8.6 (2008-08-11 patchlevel 287) [i686-darwin9.6.0] % pg_ctl --version pg_ctl (PostgreSQL) 8.3.5 % ab -V This is ApacheBench, Version 2.3 <$Revision: 655654 $> % rails -v Rails 2.2.2 % gem list --local *** LOCAL GEMS *** mongrel (1.1.5) postgres-pr (0.5.1) rails (2.2.2) thin (1.0.0) will_paginate (2.2.2) ... # 目ぼしいものを適当に抜粋
作業ログ
1. ActiveScaffold を利用したアプリで性能測定
- いつものように..
% rails activescaffold --database=postgresql % cd activescaffold
% ruby186 script/plugin install git://github.com/activescaffold/active_scaffold.git -r rails-2.2 Initialized empty Git repository in .git/ warning: no common commits remote: Counting objects: 207, done. remote: Compressing objects: 100% (193/193), done. remote: Total 207 (delta 25), reused 95 (delta 9) Receiving objects: 100% (207/207), 136.30 KiB, done. Resolving deltas: 100% (25/25), done.
- データベースの準備
% sudo su postgres -c '/usr/local/pgsql/bin/createdb activescaffold_production' % sudo su postgres -c '/usr/local/pgsql/bin/createuser activescaffold' Shall the new role be a superuser? (y/n) y
- model を作成して migrate
(その前に database.yml をちょこちょこっと修正...)
% ruby186 script/generate model person name:string address:text note:text % rake db:migrate RAILS_ENV=production
- controller を作成
% ruby186 script/generate controller Addressbooks % vi app/controllers/addressbooks_controller.rb class AddressbooksController < ApplicationController active_scaffold :customer ## <=== 追加 end
- ActiveScaffold 用の layout を作成
% vi app/views/layouts/addressbooks.html.erb <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> <head> <meta http-equiv="content-type" content="text/html;charset=UTF-8" /> <title>Todos: <%= controller.action_name %></title> <%= javascript_include_tag :defaults %> ## <=== 重要 <%= active_scaffold_includes %> ## <=== 重要 </head> <body> <p style="color: green"><%= flash[:notice] %></p> <%= yield %> </body> </html>
- データの作成
script/server のときとちがって、-e オプション付かないことに注意!
このあたりは masuidrive さんの昔の記事を参考にしつつ...
% ruby186 script/console production Loading production environment (Rails 2.2.2) >> Person.find(:all) => [] >> (1..40).each do |index| ?> Person.create :name => "Test#{index}", :address => "Address#{index}"*10, :note => "Note#{index}"*10 >> end => 1..40
- 動作確認
partial がやたらあることや、SQL を確認しておきます
% ruby186 script/server => Booting Mongrel (use 'script/server webrick' to force WEBrick) => Rails 2.2.2 application starting on http://0.0.0.0:3000 => Call with -d to detach => Ctrl-C to shutdown server ** Starting Mongrel listening at 0.0.0.0:3000 ** Starting Rails with development environment... ** Rails loaded. ** Loading any Rails specific GemPlugins ** Signals ready. TERM => stop. USR2 => restart. INT => stop (no restart). ** Rails signals registered. HUP => reload (without restart). It might not work well. ** Mongrel 1.1.5 available at 0.0.0.0:3000 ** Use CTRL-C to stop. SQL (0.2ms) SET client_min_messages TO 'panic' SQL (0.2ms) SET client_min_messages TO 'notice' SQL (0.2ms) SET client_encoding TO 'unicode' Processing AddressbooksController#index (for 127.0.0.1 at 2009-02-03 16:32:29) [GET] SQL (1.0ms) SELECT count(*) AS count_all FROM "people" Person Load (2.8ms) SELECT "people".* FROM "people" ORDER BY people."created_at" ASC LIMIT 15 OFFSET 15 Rendering template within layouts/addressbooks Rendering addressbooks/list Rendered _list_header (1.5ms) Rendered _list_column_headings (4.1ms) Rendered _messages (0.2ms) Rendered _list_actions (1.8ms) Rendered _list_record (30.8ms) Rendered _list_actions (1.1ms) Rendered _list_record (3.8ms) Rendered _list_actions (1.0ms) Rendered _list_record (3.5ms) Rendered _list_actions (1.0ms) Rendered _list_record (3.4ms) Rendered _list_actions (1.0ms) Rendered _list_record (3.4ms) Rendered _list_actions (1.0ms) Rendered _list_record (3.4ms) Rendered _list_actions (1.2ms) Rendered _list_record (3.5ms) Rendered _list_actions (1.0ms) Rendered _list_record (3.4ms) Rendered _list_actions (1.0ms) Rendered _list_record (3.4ms) Rendered _list_actions (1.0ms) Rendered _list_record (3.4ms) Rendered _list_actions (1.0ms) Rendered _list_record (3.4ms) Rendered _list_actions (1.0ms) Rendered _list_record (3.3ms) Rendered _list_actions (1.0ms) Rendered _list_record (3.4ms) Rendered _list_actions (1.0ms) Rendered _list_record (3.3ms) Rendered _list_actions (1.0ms) Rendered _list_record (3.4ms) Rendered _list_pagination_links (2.3ms) Rendered _list (95.1ms) Completed in 123ms (View: 107, DB: 4) | 200 OK [http://127.0.0.1/addressbooks]
- production 環境で起動
% ruby186 script/server -e production => Booting Mongrel (use 'script/server webrick' to force WEBrick) => Rails 2.2.2 application starting on http://0.0.0.0:3000 => Call with -d to detach => Ctrl-C to shutdown server ** Starting Mongrel listening at 0.0.0.0:3000 ** Starting Rails with production environment... ** Rails loaded. ** Loading any Rails specific GemPlugins ** Signals ready. TERM => stop. USR2 => restart. INT => stop (no restart). ** Rails signals registered. HUP => reload (without restart). It might not work well. ** Mongrel 1.1.5 available at 0.0.0.0:3000 ** Use CTRL-C to stop. Processing AddressbooksController#index (for xx.xx.xx.xx at 2009-02-03 14:21:27) [GET] Rendering template within layouts/addressbooks Rendering addressbooks/list Completed in 81ms (View: 66, DB: 6) | 200 OK [http://xx.xx.xx.xx/addressbooks]
- 測定
% ab -c 10 -n 1000 http://127.0.0.1:3000/addressbooks This is ApacheBench, Version 2.3 <$Revision: 655654 $> Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/ Licensed to The Apache Software Foundation, http://www.apache.org/ (snip) Requests per second: 12.91 [#/sec] (mean) (snip)
遅い... orz
# 以降は Requests per seconds の部分だけ表示することにします
- Thin にも載せて測定
% ab -c 10 -n 1000 http://127.0.0.1:3000/addressbooks Requests per second: 13.89 [#/sec] (mean)
2. public 以下に静的ファイルをおいて測定
- 静的ファイルの取得
% wget http://127.0.0.1:3000/addressbooks/list --output-document=public/static_list.html
- Mongrel で測定
% ab -c 10 -n 10000 http://127.0.0.1:3000/static_list.html Requests per second: 225.01 [#/sec] (mean)
- Thin で測定
% ab -c 10 -n 10000 http://127.0.0.1:3000/static_list.html Requests per second: 1254.29 [#/sec] (mean)
Mongrel と Thin の差が気になります...??
3. app/views 以下に静的ファイルをおいて測定
(これで、フレームワークを通すことによるオーバーヘッドがわかるはずです)
% mv public/static_list.html app/views/addressbooks
- Mongrel で測定
% ab -c 10 -n 10000 http://127.0.0.1:3000/addressbooks/static_list Requests per second: 87.16 [#/sec] (mean)
- Thin で測定
% ab -c 10 -n 10000 http://127.0.0.1:3000/addressbooks/static_list Requests per second: 137.80 [#/sec] (mean)
静的ファイルにする前と比べると、render 処理にかなり時間がとられてるのがこの結果からもわかりますね。
4. ふつうの scaffold を利用したアプリで性能測定
- いつものように..
% rails normalscaffold --database=postgresql % cd normalscaffold % ruby186 script/generate scaffold person name:string address:text note:text
- 動作確認
database.yml の接続先を修正しておいて、先のデータを利用します
% ruby186 script/server => Booting Mongrel (use 'script/server webrick' to force WEBrick) => Rails 2.2.2 application starting on http://0.0.0.0:3000 => Call with -d to detach => Ctrl-C to shutdown server ** Starting Mongrel listening at 0.0.0.0:3000 ** Starting Rails with development environment... ** Rails loaded. ** Loading any Rails specific GemPlugins ** Signals ready. TERM => stop. USR2 => restart. INT => stop (no restart). ** Rails signals registered. HUP => reload (without restart). It might not work well. ** Mongrel 1.1.5 available at 0.0.0.0:3000 ** Use CTRL-C to stop. Processing PeopleController#index (for 127.0.0.1 at 2009-02-03 15:52:10) [GET] SQL (0.3ms) SET client_min_messages TO 'panic' SQL (0.2ms) SET client_min_messages TO 'notice' SQL (0.2ms) SET client_encoding TO 'unicode' Person Load (5.9ms) SELECT * FROM "people" Rendering template within layouts/people Rendering people/index Completed in 46ms (View: 35, DB: 7) | 200 OK [http://127.0.0.1/people]
- Mongrel で測定
(もちろん production 環境で動かしてます)
% ab -c 1 -n 1000 http://127.0.0.1:3000/people Requests per second: 27.28 [#/sec] (mean)
- Thin で測定
% ab -c 1 -n 1000 http://127.0.0.1:3000/people Requests per second: 28.87 [#/sec] (mean)
ちなみに、ページングされてないので、ActiveScaffold のときより 3倍近いデータをデータベースから取得して表示しています
ちょっと不公平でしょうか...
5. ふつうの scaffold + ページングで測定
- will_paginate のインストール
最新版は github に移行し、rails での使い方もちょびっと変わったらしい
% gem install will_paginate % vi config/environment.rb (snip) ... require 'will_paginate' ## <=== 追加
- controller の修正
% vi app/controllers/people_controller.rb class PeopleController < ApplicationController # GET /people # GET /people.xml def index # @people = Person.find(:all) @people = Person.paginate(:page => params[:page], :per_page => 15) ## <=== 修正 (snip)
- view の修正
% vi app/views/people/index.html.erb <h1>Listing people</h1> <table> <tr> <th>Name</th> <th>Address</th> <th>Note</th> </tr> <% for person in @people %> <tr> <td><%=h person.name %></td> <td><%=h person.address %></td> <td><%=h person.note %></td> <td><%=h person.created_at %></td> ## <=== 追加 <td><%= link_to 'Show', person %></td> <td><%= link_to 'Edit', edit_person_path(person) %></td> <td><%= link_to 'Destroy', person, :confirm => 'Are you sure?', :method => :delete %></td> </tr> <% end %> </table> <br /> ## <=== 追加 <%= will_paginate(@people) %> ## <=== 追加 <br /> <%= link_to 'New person', new_person_path %>
- 動作確認
% ruby186 script/server => Booting Mongrel (use 'script/server webrick' to force WEBrick) => Rails 2.2.2 application starting on http://0.0.0.0:3000 => Call with -d to detach => Ctrl-C to shutdown server ** Starting Mongrel listening at 0.0.0.0:3000 ** Starting Rails with development environment... ** Rails loaded. ** Loading any Rails specific GemPlugins ** Signals ready. TERM => stop. USR2 => restart. INT => stop (no restart). ** Rails signals registered. HUP => reload (without restart). It might not work well. ** Mongrel 1.1.5 available at 0.0.0.0:3000 ** Use CTRL-C to stop. Processing PeopleController#index (for 127.0.0.1 at 2009-02-03 16:26:22) [GET] SQL (0.3ms) SET client_min_messages TO 'panic' SQL (0.2ms) SET client_min_messages TO 'notice' SQL (0.2ms) SET client_encoding TO 'unicode' Person Load (3.5ms) SELECT * FROM "people" LIMIT 15 OFFSET 0 SQL (0.7ms) SELECT count(*) AS count_all FROM "people" Rendering template within layouts/people Rendering people/index Completed in 52ms (View: 34, DB: 5) | 200 OK [http://127.0.0.1/people]
:condition の設定をしてないので Order by は違いますが、LIMIT は ActiveScaffold のときと同じになっています
- Mongrel で測定
% ab -c 10 -n 1000 http://127.0.0.1:3000/people Requests per second: 47.18 [#/sec] (mean)
- Thin で測定
% ab -c 10 -n 1000 http://127.0.0.1:3000/people Requests per second: 54.26 [#/sec] (mean)
ActiveScaffold のときより 4倍くらいはよいですね...