Saturday, March 03, 2007

CGI-based Rails deployment

As I mentioned in the previous post, I tried the simplest thing possible for my rails deployment--a CGI based approach. My setup was this:
Installation and Configuration
So, I installed ubuntu, got all updates and installed them and enabled "universe" and "multiverse" in the apt sources list. Now I was ready to install ruby, rails, mysql and apache2.

sudo aptitude update
sudo aptitude install ruby rdoc ri rake apache2 mysql

Then I got RubyGems as source and installed using ruby. I was a bit sad that I couldn't get the "gem" tool using aptitude, but it looked like the ruby installer actually made a gem package and installed it as a gem, so from here on, it can be updated using itself, nice!

Then, I installed Rails:

sudo gem install rails --include-dependencies

And after installing rails, I installed my application:
  • Installed (copied) my application into "/var/opt/rails/app"
  • Recursively changed user and group on that dir to "www-data:www-data", as this is what apache runs as.
  • Edited environment.rb to uncomment line about RAILS_ENV (makes it default to production if nothing explicit set)
Now I was ready to create the apache setup:
  • Created a new file "/etc/apache2/sites-available/app"
  • Linked it to sites-enabled as "001-app"
  • Linked "/etc/apache2/mods-available/rewrite.load" into "mods-enabled" (the .htaccess file in the rails application is using mod_rewrite to dispatch requests to "dispatch.cgi")
  • Edited "/etc/hosts" to make the name "app" resolve to localhost IP (as I am using virtual host based apache setup)
I then edited the "sites-available/app" file to have this content:

NameVirtualHost app
ServerName app
DocumentRoot /var/opt/rails/app/public/
ErrorLog /var/opt/rails/app/log/apache.log

Options ExecCGI FollowSymLinks
AllowOverride all
Order allow,deny
Allow from all

And simply restarted apache.

And then, stuff went wrong, and I found out I had to do these things:
  • Put "socket: /var/run/mysqld/mysqld.sock" into "databases.yml", as ActiveRecord was using the socket file to connect to MySQL and the ubuntu installed MySQL has placed it under "/var/run/mysqld"
  • Enabled x-bit on "dispatch.cgi" (because I had copied files from a windows partition)
  • Change the shebang line in "dispatch.cgi", as it included a horrible "c:/..." line to where ruby is placed on my windows partition
And then it worked, but, ...

Performance was horrible
As mentioned previously, the site is not going to take many hits at all. So I thought, with todays CPUs and forking speeds of Linux, this might be okay. Here are some numbers, from my 2GB, 2.26GHz Dell Latitude D810.
  • 1 request, with no db-access took around 0,8-1,0 second (Auch!)
  • 5 simultanous requests, to same page, ~5 seconds, with an average of ~5 seconds/request
  • 15 simultanous requests, to same page, ~15 seconds, with an average of ~15 seconds/request
Hugh? There seems to be no real advantage in executing requests in parallel. As in, one process working when others are in IO-wait. But then again, the load sky-rocketed when handling the requests, so this must be the ruby VM startup and Rails framework interpretation cost, that is very high. Funny though, that all request are taking equally long to finish, about linear to the number of simultaneous requests.

Maybe it would be better, if I was running the yarv vm?

Next Post
Will be about the mongrel setup I did instead, which performs much better, but is a bit more complex to setup.

Still, even this simple setup, is far more complex than dropping a .war file in a web-container.