Sunday, October 28, 2007

Mongrel, Apache, and Rails

When I first started running Rails applications on my web server, I chose to use FastCGI. Specifically, the mod_fcgid module, which had some features I wanted. It also has the unfortunate by-product of corrupting Apache's memory. Bad news.

I've since removed FastCGI entirely and moved to a proxy to mongrel_cluster setup. And I've started deploying with Capistrano.

Capistrano

I have a certain amount of concern with moving to a deployment system I knew very little about. Just like a new backup system, I feel like I'm handing the keys to my data over to something not written by me. And, while it is fairly simple to set up, Capistrano is somewhat complicated internally.

I already push out my operating system upgrades in an automated way. I compile NetBSD on one machine here at home, and push the binaries out to all my machines. This means about 7 machines rsync from the build box with one command. This can be scary, but I've been doing it for 5 years now, and it just works. How can a web site be scary compared to kernels and system binaries?

The answer is, it's not. If something breaks it is fairly easy to manually reconfigure if I need to. So, I've relaxed a bit. My concerns are still there, and I'm keeping a careful watch on how Capistrano runs each time I deploy. I have yet to do a *real* deployment after all! So far, I've not done a single migration, and have not had to roll back. And I'm pushing to a single machine, which runs the database as well as the site.

I suspect that, as I become comfortable with this new method to update my web sites, I'll start thinking of it as rsync++. It really is that simple.

mongrel_cluster

Mongrel is a vary amazing little widget. Sure, it's slower than Apache, but that's ok. Mongrel is still far, far faster than restarting Rails for each web hit, and far more reliable than mod_fcgid.

In my configuration, I run each site on ports 10000, 10010, 10020, etc. with up to 3 servers per. This means application #1 is on 10000 through 10002, with room to grow should I need to run more. If I find myself running more than 10 servers for a site it needs a new machine anyway, or more machines. And if that happens, I hope I'll have a budget.

Apache load balancing

This is a new feature in Apache 2.1, and apparently is very reliable with Apache 2.2. This is currently my favorite way to run a web site.

My configuration, which happens to be for this site:

<proxy balancer://blog>
  BalancerMember http://localhost:10010
  BalancerMember http://localhost:10011
  BalancerMember http://localhost:10012
</proxy>
<VirtualHost blog.flame.org:80>
  DocumentRoot /www/blog/flame-blog/current/public
  <directory "/www/blog/flame-blog/current/public">
    Options FollowSymLinks
    AllowOverride None
    Order allow,deny
    Allow from all
  </directory>

  ProxyRequests off
  <proxy *>
    order deny,allow
    allow from all
  </proxy>

  RewriteEngine on

  # Check for maintenance file. Let apache load it if it exists
  RewriteCond %{DOCUMENT_ROOT}/system/maintenance.html -f
  RewriteRule . /system/maintenance.html [L]

  # Rewrite index to check for static
  RewriteRule ^/$ balancer://blog%{REQUEST_URI} [L,P,QSA]

  # Let apache serve static files (send everything via mod_proxy that
  # is *no* static file (!-f)
  RewriteCond %{DOCUMENT_ROOT}%{REQUEST_FILENAME} !-f
  RewriteRule .* balancer://blog%{REQUEST_URI} [L,P,QSA]
</VirtualHost>

It is important, at least on my host, to use localhost in the balancer destinations. This is due to mongrel suddenly running on IPv6 loopback (::1) rather than the usual IPv4 loopback (127.0.0.1). I don't know why this happened, but the localhost trick makes Apache try both addresses, and whichever works it will use.

This configuration makes Apache serve static content, and sends all other requests off to one of the Mongrel processes.

No comments:

Post a Comment