How to optimize Apache speed for serving static content?

I'm well aware ngix is much better for static content, but I can't use it. Otherwise I have full access to my server (VPS).

I've found numerous articles and posts about optimizing apache, but it's always about PHP apps performance.

I'm using latest Apache 2.4.7

I'm already using MPM. I was thinking about tweaking KeepAlive MaxClients etc. for (static content) performance, if it makes any sense?


Solution 1:

Before trying to tune Apache make sure you have a proper monitoring in place so you can see how many requests Apache serves and how the system resources correlate to each other. An easy to use solution for this is munin.

Next, prepare load tests with which you can put your system under load to see what effect the different tuning options have. There are quite some solutions for this, ranging from a very simple ab over JMeter to very sophisticated cloud based solutions with which you can simulate thousands of visitors from all over the world. Search for "website load testing" and you will find plenty of solutions.

Finally, here are the points which I consider important when tuning Apache:

  • Remove unused modules: Use apache2ctl -M to see which modules are loaded. Modules which are marked (shared) should be removed if they are not needed. This will reduce the memory footprint of Apache and lets your OS use the available RAM for other purposes (e.g. caching).

  • Don't use .htaccess files: Put all your settings in the Apache configuration and set AllowOverride None so Apache doesn't have to look for .htaccess files and parse them while it is serving requests.

  • Explicitly allow symbolic links: By setting Options +FollowSymLinks -SymLinksIfOwnerMatch you tell Apache that symlinks are allowed so it is free to serve the files it reads without having to verify if they are symlinks. This saves some system calls.

  • Depending on your monitoring needs, consider switching off ExtendedStatus: This will save some system calls but will give you less monitoring information. Not sure if it is really worth it.

  • Avoid excessive logging: Logging every request can cause quite some I/O. Using selective logging you can control which requests you want to log. The following will log only requests to URLs ending in .html:

    SetEnvIf Request_URI ".html$" dolog
    CustomLog /var/log/apache2/access.log combined env=dolog
    
  • If you don't need SSL, consider using the Event MPM, it causes open connections (e.g. due to keepalives) to be handled much more efficiently. If you need SSL, the Event MPM functions the same as the Worker MPM. See How do I select which Apache MPM to use? for more information on the different MPM modules.

  • Compress or even pre-compress data: By using mod_deflate content is compressed before it is being sent to the clients. Since you have static data, it may be worth pre-compressing the content rather than compressing the same data over and over again. See http://httpd.apache.org/docs/2.4/mod/mod_deflate.html#precompressed on how to accomplish this.

  • Tune the OS: Use large TCP write buffers so fewer system calls are needed to submit the requested data to the clients. Also ensure that the maximum number of open files is high enough so Apache doesn't run into that limit.

Solution 2:

KeepAlive normally makes a lot of sense, requires more memory but lowers the number of connections, CPU usage and connections overhead. MaxClients and other stuff must be tuned to your situation instead. Normally you'll want Apache to have a number of idle instances big enough to serve all of your users without having it to spawn new child processes all the time; at the same time you want to avoid excessive values for maxclients in order to keep memory usage under control. Unless you have sudden usage spikes though, the default Apache settings are usually adequate and will self adapt well enough to your environment.

If you serve content through https and since you're not using php you might want to give a try to mod_spdy module too, many browsers support that already (waiting for a global support for http 2.0).

Finally another option is to use caching/precaching. In that regard some functionality is already available in Apache thanks to several modules (please see http://httpd.apache.org/docs/2.4/caching.html ), or you can put something else in front of the server (Varnish is a popular option).