ActiveRecord vs Sequel

Written by Walter

Started on writing a lightweight Sinatra application and did some benchmarks.
First fill a user table with some records:
(1..9999).each{|n|User.create( :phone=>"+111111"+n.to_s, :password=>"anysecret" )}

Then tested the exact same sinatra app first with sinatra-activerecord and then with the excellent sequel gem:

Basic sinatra app and then we can do for active record:

Active record version for testing:


require 'sinatra'
require 'mysql2'
require 'sinatra/activerecord'
require 'yaml'
require 'json'


... connect db ...

class User < ActiveRecord::Base
set_table_name :user
end


Sequel version for testing:

require 'sinatra'
require 'mysql2'
require 'sequel' #alternative orm as activercord
require 'yaml'
require 'json'


#sequel model
class User < Sequel::Model(:user)
end



Then we query all users in a page and return json:


#json request active record
get '/active/user/:id' do
u = User.find( params[:id] )
content_type :json
{ :name => u.phone, :login => u.login }.to_json

end

#json request sequel
get '/sequel/user/:id' do
u = User[params[:id]]
content_type :json
{ :name => u.phone, :email => u.email }.to_json
end


So we have '/sequal/users' and '/active/users'
When running ruby 1.9.2 and rails 3.0.7 on my laptop I get different benchmark results. I'm not even using passenger just runnning ruby app.rb just to see some results quickly.

Basically just firing ruby app.rb takes 5 times longer with activerecord than with sequel gem. But now for actually testing the loading of the page with apache benchmark tool I get more accurate results:

ab -n 2000 -c 10 'http://localhost:4567/active/users'
... just hangs basically, to be honest we should try it with passenger on my webserver instead of locally on laptop, still it's not looking good for just concurrency 10

ab -n 2000 -c 10 'http://localhost:4567/sequel/users'
Total transferred: 3453700 bytes
HTML transferred: 3435900 bytes
Requests per second: 39.05 [#/sec] (mean)
Time per request: 25.606 [ms] (mean)
Time per request: 25.606 [ms] (mean, across all concurrent requests)
Transfer rate: 1317.15 [Kbytes/sec] received

With sequel however it runs just fine.
So either something is wrong with my sinatra-activerecord gem or it does not like the low startup times here and we need passenger to get it running properly...

In short sequel+sinatra seems to be a winner here ;).

Can't wait to see how fast it will be with passenger since I get speeds up to 800req/sec easily when running a rails app in production on the webserver this little sequel/sinatra app should be going at laser speeds ;)

UPDATE: Not so good news, when running this sinatra/sequel app and actually benchmark it with passenger/apache2 running it just locks up before ab can finish.

I posted a question on the sequel gem author, maybe they can help me out.
For now sticking with activerecord.

I switched back to sinatra/activerecord. Ran my benchmarks on my webserver and bam 4000+ req/second baby!!!


1 require 'sinatra'
2 require 'mysql2'
3 require 'sinatra/activerecord'
4 require 'yaml'
5 require 'json'
6 #require './data/init.rb'
7
8 #this is solely for benchmarking, cleaning up and restructuring code now ;)
9 set :database_extras, { :password=>'thepass', :encoding=>'utf8', :max_connections=>5 }
10 set :database, URI.encode( "mysql2://root:nowayM@localhost/ScaleChampion_development" )
11
12 class User < ActiveRecord::Base
13 #set_table_name :users
14 end
15
16
17 get '/' do
18 erb :getAuthToken
19 end
20
21 get '/getAuthToken' do
22 erb :getAuthToken
23 end
24
25
26 post '/getAuthToken' do
27 erb :getAuthToken
28 end
29
30
31 get '/users' do
32 content_type :json
33 User.all.map{|u|
34 { :id=>u.id, :name => u.name, :email => u[:email] }.to_json
35 }
36 end
37
38 #json request sequel
39 get '/user/:id' do
40 #u = User[params[:id]]
41 u = User.find( params[:id] )
42 #u = { :name=>"walter", :email=>"somethingfast@bla.com" }
43 content_type :json
44 { :name => u.name, :email => u.email }.to_json
45 end
46



Following test 6000 requests with 200 concurrency:

ab -n 6000 -c 200 'http://viu.sitweb.eu/user/100'

HTML transferred: 264000 bytes
Requests per second: 4095.47 [#/sec] (mean)
Time per request: 48.834 [ms] (mean)
Time per request: 0.244 [ms] (mean, across all concurrent requests)
Transfer rate: 1103.86 [Kbytes/sec] received


Fast enough for me. And the good news is that this sinatra json app can reuse all my models allready written for the rails app of viu2, hurrai ;)

After restructuring and cleaning I have following sinatra app (cool is that it now uses the same database.yml format as a rails app and has views+layout.rb):


root@Debian-60-squeeze-64-LAMP:/var/www/viu2_json# tree .
.
├── app.rb
├── config.ru
├── data
│   ├── database.yml
│   ├── database.yml.option
│   ├── init.rb
│   └── models.rb
├── public
├── Rakefile
├── README.install
├── tmp
│   └── restart.txt
└── views
├── getAuthToken.erb
├── layout.erb
└── showUser.erb



Performance is still equal as before. And for regular pages without mysql queries I get 6000 req/sec. Awesome! Now it's a matter of using some smart require's to include the models from the rails app so we have 0 code duplication ;)


Back to archive