It wasn't long ago that I signed up for my first slice over at Slicehost, a cool VPS host out of St. Louis, Missouri. I needed a host for a Django application and Kyle told me that I shouldn't waste my time with anyone else.
Having the whole server to yourself is great, but it also means making sure you get everything right, from the firewall to the Web server, so I've had to do some homework. Specifically, Apache is a beast and needs to be shorn, especially if you are working with a server with 256MB of RAM. I don't claim to be an Apache expert, but here are some tips that have worked for me.
Prefork MPM Settings
Running Django, I've been using Apache's Prefork MPM, so that's what I'll address here. On Slicehost, Apache's defaults look like this:
<IfModule mpm_prefork_module> StartServers 5 MinSpareServers 5 MaxSpareServers 10 MaxClients 150 MaxRequestsPerChild 0 </IfModule>
The important thing to understand is that this section sets how Apache will spawn child servers, and how they will handle requests in turn. Multiple child servers allow us to serve multiple clients simultaneously. However, each child process consumes a certain amount of memory. If not properly configured, Apache may spawn enough child processes to exhaust real memory and begin swapping to disk (especially on small servers). The Apache documentation refers to this swapping as "thrashing"—an apt description as the server performance degrades dramatically.
Here's a look at the Apache processes on one of my 256MB slices:
$ ps o pid,rss,command -u www-data
PID RSS COMMAND
3752 40560 /usr/sbin/apache2 -k start
3754 39536 /usr/sbin/apache2 -k start
3819 1752 nginx: worker process
3820 1748 nginx: worker process
3821 1380 nginx: worker process
3822 1376 nginx: worker process
You'll notice that, along with Apache, I have four proxy nginx processes, a resource-saving tip I learned at punteney.com. That's a way of having a lightweight Web server take care of static pages (like images and stylesheets) and only having Apache do the heavy lifting of serving dynamic content. But let's stay focused on Apache for now.
You can see that I have two Apache processes running, occupying about 40 MB of memory each. This footprint will depend mostly on the type of Web application Apache is serving. On another site of mine, running a more basic Django app, Apache processes average 30.289 MB.
So, at 40 MB per process, I can have about six Apache children running before I completely exhaust my 256 MB of RAM. The trouble is, I have to run a few other processes, like nginx and my PostgreSQL database. I'd also like to have a little memory left over to dedicate to memcached to speed up my site.
Aside from Apache, the processes on my server take up about 54 MB of RAM, under little to no traffic load. This includes nginx, PostgreSQL, and some other lightweight utilities. Taking all these specifics into account, I set up Apache to start no more than four child processes:
So, four times 41 is a 164 MB footprint for Apache. 164 plus 54 is 218 MB for all my necessary server processes except for memcached, leaving me about 40 MB of margin for caching and extra load. At the end of the day, for optimum performance, what I want to see is something like this:
$ free -m
total used free
Mem: 256 245 10
-/+ buffers/cache: 198 57
Swap: 511 0 511
Specifically, zero memory used in swap.
After doing some experimentation, I've come to the conclusion that the default Apache modules don't make a huge difference in the overall memory footprint. For instance, with the default set of Apache modules on Slicehost, my child processes were maximum 42.060 MB, minimum 40.780 MB in size. After going into
/etc/apache2/mods-enabled/ and ruthlessly deleting any module symlinks that didn't cause my site to break, I ended up with process sizes varying from 40.736 to 41.580 MB in size. So, I might be saving a megabyte per process. Obviously the bulk of the memory overhead comes from what my app loads in mod_python.
Honestly, I'm still watching to see if all this theoretical talk works out in production. If I've omitted anything, feel free to comment.