Apache performance tuning

From BitFolk
Jump to: navigation, search

Apache is a popular web server. This article provides some configuration tips to improve performance when Apache is in use on a BitFolk VPS.

Do not run in swap!

One of the most important considerations when trying to increase Apache performance is avoiding use of swap for the Apache processes themselves.

Pick an appropriate number for MaxClients

The typical MPM in use is prefork, and the default value of MaxClients is 150. This is in most cases far too large for a VPS with limited RAM.

When you first install Apache everything may seem to work fine, and this may continue to be the case for a long time, but as soon you serve something popular the number of simultaneous client connections will increase until it reaches MaxClients. Take a look at how big your Apache child processes are:

$ ps -C apache2 -o user,pid,rss,command
www-data 17350 18184 /usr/sbin/apache2 -k start
www-data 17352 18588 /usr/sbin/apache2 -k start
www-data 17537 19452 /usr/sbin/apache2 -k start
www-data 19217 12544 /usr/sbin/apache2 -k start
www-data 19219 18044 /usr/sbin/apache2 -k start
www-data 19231 12084 /usr/sbin/apache2 -k start
www-data 19232 16436 /usr/sbin/apache2 -k start
www-data 26083 17980 /usr/sbin/apache2 -k start
root     26409   728 /usr/sbin/apache2 -k start

In the above example the Apache child processes are about 18MiB in size (RSS). On a VPS with 240MiB of RAM, assuming nothing else were running, we might expect to be able to support 240/18=13.33 simultaneous connections before swap is used.

If the MaxClients were left at the default 150 and we put some popular content up then this might demand up to 150*18=2,700MiB of memory from the virtual memory subsystem. Very quickly this would hit swap, which would kill performance of all Apache children, leading to connections stacking up and users hitting reload, which creates more simultaneous connections. It should be easy to see how what seemed like a perfectly working configuration can bring your VPS to its knees as soon as it gets real web traffic.

If on the other hand the MaxClients had been limited to about 13, all Apache children together could only use about 234MiB of RAM. Under a flash crowd situation ("slashdot effect"), MaxClients simultaneous connections will be reached and subsequent requests will be queued until there is an Apache process available to serve them. Web clients will still experience large delays and your site may still appear to be down, but the difference is that your VPS itself will not be down.

In the above example, if you wanted to serve more than 13 simultaneous clients then you need to either increase your RAM or decrease the size of each Apache process. You cannot simply increase MaxClients beyond your available RAM and expect it to just work - as soon as you actually tried to have more processes running you'll hit swap and performance spirals downwards.

Decreasing the size of Apache processes

A major factor in how big each Apache process needs to be is how many modules you have loaded. On Debian and Ubuntu you can see which modules you have enabled as follows:

$ ls /etc/apache2/mods-enabled/*.load

Read the Apache documentation and see which of these modules you can disable. After disabling a module with a2dismod you can use apache2ctl configtest to check that your configuration still parses:

$ sudo a2dismod authz_host
Module status disabled.
Run '/etc/init.d/apache2 restart' to activate new configuration!
$ sudo apache2ctl configtest
Syntax error on line 12 of /etc/apache2/sites-enabled/000-default:
Invalid command 'Order', perhaps misspelled or defined by a module not included in the server configuration
Action 'configtest' failed.
The Apache error log may have more information.

In the above example the configuration no longer parses because on line 12 of /etc/apache2/sites-enabled/000-default we have:

        <Directory /var/www/>
                Options Indexes FollowSymLinks MultiViews
                AllowOverride None
                Order allow,deny
                allow from all

This is a host-based access list (allow from all) and we just disabled the authz_host module, which is what implements those. Since this configuration currently allows access from everywhere, it needn't actually be there at all and could be commented out, allowing the server to load without the authz_host module.

Serve static content from a different daemon

From earlier discussion we established that there's a limit on how many simultaneous clients can be served, and that this limit was determined by how much RAM is available and how much memory each Apache process requires. You already know that you can reduce the size of the Apache process by disabling modules, but most interesting dynamic content tends to require large built-in interpreters like PHP or at least the CGI module.

Quite a lot of the most-frequently requested content on many sites however is of a static nature: images, CSS, javascript, and so on. You can eke out a bit more performance by installing another HTTP server whose only job is to serve static content. This might be a very stripped down copy of Apache, or maybe even one of the alternate lightweight HTTP daemons. Not only will the stripped down server deal with the request faster but it will also free up an Apache child for doing something more complicated.

You don't need multiple hosts or even multiple IP addresses to do this: if you keep all your static files in a given directory tree then you can reverse proxy that to another server listening on localhost and still get most of the benefit.

Everything else

If you're seeing a lot of CPU usage or disk IO then you might want to consider the advice in the Apache Performance Tuning documentation about FollowSymlinks and AllowOverride.

Alternatives to Apache

Several simpler web servers are available which are more lightweight than Apache and therefore perform better under load, usually at the expense of Apache's highly flexible configuration.

Further info