Apache Web server could frequently be bottleneck for your LAMP stack, or you might be wasting resources on your web servers. The problem with Apache server comes from “client per process” architecture which you have to stick to at least for dynamic content served by PHP or ModPerl. With “client per process” you end up having large amount of processes if you have many clients. As processes service all requests they can get you end up having a lot of memory allocated per process which is not fully released to OS even if process is serving static requests or doing keepalive. So why do you need many processes ? Keep alive is one thing, which you can disable of course. But the real problem is slow clients which need to be spoon feed. This is especially the problem for large pages and files but with bad/slow networks even small objects may cause the stall. There are multiple solutions and workarounds to this problem:
- Just get more memory/more boxes. The good thing with Web servers is – it is easy to scale, this is if you have money to waste of course. Just get more servers, beef them up with memory and you should be fine. If this is your choice you can stop reading 🙂
- Restrict resources. You can limit number of Apache children (MaxClients 50) , disable keep alive (KeepAlive Off) and relay on Operation System connection buffering (ListenBacklog 1024) but such approach is often bad for site performance. Even if you can balance it to work right in normal case, minor network or database server slowdowns may cause overload.
- Use LingerD. I have not ever used this one, but in theory it should relieve apache from closing connection which is part of the job, however it does not play good with keep alive and does not eliminate all problems.
- Use FastCGI instead of mod_php etc. Apache itself without any programming language modules is light, futhermore you may use threaded worker models to keep overhead lower. However FastCGI is a bit less tested interface, so some software might not play well with it, some, including APC requires careful configuration to work like you expect it to work.
- Use other server, ie lighttpd with FastCGI. Honestly I like this solution more – it allows you to get rid of all the fat Apache server has and get efficient event driven socket processing. This is however hard step as it may require changes in your application if you used apache specific modules – ie mod_rewrite, .htaccess, apache specific environment variables etc. So this is typically the path for new applications which do not require legacy applications.
- Use Reverse proxy in front. You may configure other Apache server to use as reverse proxy, you may also use Squid, Lighttpd, Nginx etc, in fact Most of light http servers support such configuration. There are several benefits in this configuration. One obvious one is Caching – it however requires you to provide cache expiration information for dynamic contents etc which your applications might not be doing at this point. The other benefit is more important for scope of this article. Now you have proxy server spoonfeeding the clients, doing keep-alive and your apache is relieved from this job, so you can shrink number of needed children dramatically. One more benefit is load balacing and HA – you may have round robin or random request routing to your proxy servers, which pretty much any load balancer can do, but you may configure each of them to do hash routing to real servers (especially for static content this may help to increase file cache efficiency dramatically). Such solution also typically allow you to relieve Apache from serving static content – Proxy may be configured to handle only dynamic requests, serving static files by itself. The tiny but annoying with such configuration could be logging. Instead of real IP of your clients you would see 10.0.0.1 or whatever IP your proxy server is located. Just recently I found out – there is great module out where – mod_rpaf which can replace remote host with IP passed by your local proxy. So now you can put reverse proxy infront of your Apache web server in 10 minutes and you will likely need no changes in your application.
- Dedicated server for static content. If you serve a lot of static content – music, videos, file download I guess it is good idea anyway as such servers might be configured differently. You also may have different routing policies set for these servers – you want Web pages do be real time while you do not really care about latency for large files download. If your mostly static contents are few images used in pages, setting them to be directly services by reverse proxy servers could be enough.
The note about LigHTTPD – I like this one in particular because it is really easy to set up, it is pretty stable which is proved by number of major sites using it. It has good set of modules, decent documentation and community helping to develop it. So it is not single guy project any more. I however can’t say it is best one – I simply did not test too much of other alternatives as it already worked well. There are few features which it lacks and which could make it faster. Few missing items I should mention:
- Persistent connections to FastCGI servers
- Keep alive from Reverse proxy to web server
- Async IO for serving large large files
The good thing I hear most of these are already in works. Thanks Jan and Lighttpd contributors.