Pounding Mongrel Light(tpd)ly

Posted by theBlatherskite Mon, 20 Nov 2006 22:27:00 GMT

As witnessed by my recent(ish) articles on installing and optimizing FreeBSD, I’ve been spending my spare bits of time developing a production server for our internal environment. There’s been quite a push within the rails community away from Apache+FCGI, and when it came time to look at the server application I decided to jump in and see what other options are out there.

My eventual deployment decisions: lighttpd to serve static files, a mongrel cluster taking care of business on the rails side, and the pound load-balancer sitting up front managing customer service (and, for bonus points, reverse-proxing to allow the mongrels to serve content over https).

Note that this is by no means the only possible choice. A little research into what other rubyists have been doing reveals a number of other options that would also be worth exploring (for example, Coda Hale and Jonathan Weiss seem to prefer apache feeding the mongrel pack).

Mongrel

Mongrel is an easily-configured web server, tuned for serving up rails apps, that’s sweeping the RoR community. The software’s author, the oh-so-entertaining Zed Shaw, is also quite dedicated to supporting users.

Details can be found by scouring the mongrel website, but the general gist of using Mongrel is pretty easy. Mongrel is a single-threaded application (as is rails itself), so we can scale to handle higher loads by deploying multiple mongrel processes in parallel as a mongrel “cluster.”

Obtaining

First, we need to install Mongrel and Mongrel Cluster:

$ sudo gem install mongrel
$ sudo gem install mongrel_cluster

(On a windows machine, you may also want to install mongrel_service)

Configuring

Second, we need to configure the cluster. From your rails application’s root:

$ mongrel_rails cluster::configure -e production -p 8000 -N 3 -a 127.0.0.1

Where p is the port for the first mongrel instance to bind to, and -N is the number of mongrels to be released (so in this case, we’ll end up with three servers listening on 8000, 8001, and 8002). Finally, the -a switch tells the daemons to ignore all requests that don’t originate from the given IP (in this case, localhost, which allows us to enforce a single point-of-entry into our server).

Running

Third… actually, that’s about it. The following do pretty much what you’d expect:

$ mongrel_rails cluster::start
$ mongrel_rails cluster::restart
$ mongrel_rails cluster::stop

Lighttpd

Lighttpd is an amazingly tight webserver that apparently rocks the socks off apache in terms of pretty much everything but load balancing (that’s why we’ll be using Pound as the front end, rather than letting lighty manage the distribution of work to the mongrel cluster).

You can read all about how to configure it as a standalone server in the manual, or you can just install it on your machine and work with what rails gives you. You’ll see what I mean.

Obtaining

Lighttpd can be downloaded from here or extracted from SVN at svn://svn.lighttpd.net/lighttpd/branches/lighttpd-1.4.x/. For FreeBSD users, a port exists in /usr/ports/www/lighttpd.

Configuring

This is where I spent a good bit of time reading through the lighttpd configuration docs and trying to translate all the examples (written using PHP) into the rails world. I’m pretty new to FreeBSD, and I was having difficulty understanding where to find the appropriate socket to attach the fcgi processes to… I finally gave up and went to bed around 6am.

When I woke up the next day, however, I realized all I need to do was type script/server at my application’s root (funny how you don’t think of these things late at night). Once lighttpd is installed on the system, rails automatically leverages this as the default server… which means it writes out a functioning config file for us.

$ nano -w config/lighttpd.conf

Since we know this configuration already functions correctly, we just need to tune it as desired. Set server.port to whatever you wish (we’ll use 3000 for this example), and server.bind to 127.0.0.1 (if server.bind is set to 0.0.0.0, it will accept connections from any IP address (e.g., it’ll respond to outside users). Since we want all traffic to be proxied through pound, we only want lighttpd to respond to the localhost).

Running

$ script/server

Viola.

Pound

Pound is the glue that will bind our various servers together. Pound will be the only web-facing component of our application. It will accept a connection from a remote user, and then pass that connection off for another program to handle (in our case the web servers all reside on the same machine, but Pound would also work with a physical cluster of boxes).

In addition, Pound has the capability to reverse-proxy HTTPS traffic, thus allowing our regular mongrel cluster to serve content securely without changing any configuration whatsoever (outside of Pound, of course).

Obtaining

The source is accessible in RPM format, as a FreeBSD port (/usr/ports/www/pound), and as source from the main page (scroll down).

You may also want to install the PCRE (/usr/ports/devel/pcre) and hoard (/usr/ports/devel/libhoard) libraries – Pound will link against them automatically, which helps performance significantly.

Configuring

Configuration of pound is relatively simple, compared to lighttpd or, to take it up a notch, apache. This entry is already getting quite long, so I’ll refer you to Rob Orsini’s walkthrough (Step 3 – Configure Pound), which provides a detailed information on a complex deployment environment, and Aidan’s article, which focuses on a more practical deployment. In addition, pound’s official documentation is available here – it’s not pretty, but it gets the job done.

Note that while the install apparently should create a default config file at /usr/local/etc/pound.cfg, there was no such file after my FreeBSD install. Perhaps I was looking at old docs, or perhaps there’s just a snafu somewhere along the line – at any rate, you may need to create this file yourself.

For our example, the configuration file:

User        "www" 
Group       "www" 
LogLevel    2
Alive       30

ListenHTTP
    Address 0.0.0.0
    Port    80

        # Lighttpd instance on 3000 for static content
        Service
            URL "\.(jpg|gif|png|js|css|jpeg|html|txt)"

            BackEnd
                Address 127.0.0.1
                Port 3000
            End
            Session
                Type IP
                TTL  300
            End
        End

        # Mongrel cluster from 8000
        Service

            BackEnd 
                Address 127.0.0.1
                Port    8000    
            End
            BackEnd 
                Address 127.0.0.1
                Port    8001    
            End
            BackEnd 
                Address 127.0.0.1
                Port    8002    
            End    
            Session 
                Type    IP   
                TTL     300     
            End
        End
End


# Also serve content over HTTPS
ListenHTTPS
        Address 0.0.0.0
        Port 443

        # Change this path to your SSL certificate
        Cert "/usr/local/etc/domain-cert.pem"

        # pass along https hint
        AddHeader "X-Forwarded-Proto: https"
        HeadRemove "X-Forwarded-Proto"

        --- SNIP ---
    [Copy and paste the two 'Service' sections from above -- there's no difference]
        --- SNIP ---

End

Running

$ pound

That’s about it. Type man pound for full documentation.

Final notes

Once everything’s been properly configured, presumably deployment should be relatively simple. During the development process, however, I found two techniques (applicable in *nix environments) to be very helpful in keeping track of which servers were, or were not, running on which ports:

$ ps aux | grep pound

To list all running processes from a specific program, replace ‘pound’ with lighttpd / mongrel as necessary.

In addition,

$ lsof -i -P

Lists all open network sockets on the local machine, as well as the executable which is listening behind each socket.

If anyone has similar tips and tricks, feel free to share them below for the benefit of all :)

Note: apparently Mongrel runs dramatically faster on FreeBSD if you compile the nopthreads version of ruby (/usr/ports/lang/ruby18-nopthreads).

Posted in ,  | Tags , , , ,  | 3 comments | no trackbacks

Comments

  1. Scott Stevenson said about 4 hours later:

    This is a great article. Thanks.

  2. Stephane said 10 months later:

    Thank you for this interesting serie about freebsd and rails deployement.

  3. Marcel said about 1 year later:

    Hey,

    Thanks for writing this up, it was very useful for setting up my stack.

    By the way, I found that Pound didn’t start and (like you said) provided me with nothing more then sweet silence… Investigation showed that my machine didn’t have a “www” user yet. A swift “useradd www -M” and “groupadd www” solved the issue and left me a happy camper.

Trackbacks

Use the following link to trackback from your own site:
http://www.theblatherskite.com/trackbacks?article_id=pounding-mongrel-light-tpd-ly&day=20&month=11&year=2006

(leave url/email »)

   Comment Markup Help Preview comment