AddThis Social Bookmark Button


Introducing LAMP Tuning Techniques

by Adam Pedersen

I'm getting to know far more about servers than I ever wanted to, after hundreds of hours of Google research trying to squeeze/beat performance out of Apache. I do have 15 years programming experience in other areas, and I've reached the conclusion that the only experts in Apache/Linux are the programmers who wrote (and poorly documented) all this stuff. So I've gathered everything I could learn after countless hours of frustration and I'm writing this up in return for the immense amount of help I've received from the documentation of others.

If you're reaching the limits of your Apache server because you're serving a lot of dynamic content, you can either spend thousands on new equipment or reduce bloat to increase your server capacity from 2 to 10 times. This article concentrates on important and weakly documented ways of increasing capacity without the need for additional hardware.

Understanding Server Load Problems

There are a few common areas of server load problems, and a thousand uncommon. Let's focus on the top three I've seen:

  • Drive Swapping, where too many processes (or runaway processes) use too much RAM.
  • CPU, from poorly optimized DB queries, poorly optimized code, and runaway processes.
  • Network, whether hardware limits or moron attacks.

Managing Apache's RAM Usage

Apache processes use a ton of RAM. This issue becomes major when you realize that after each process has done its job, the bloated process sits and spoon-feeds data to the client, instead of moving on to bigger and better things. This problem is compounded by a bit of essential info that should really be more common knowledge:

If you serve 100% static files with Apache, each httpd process will use around 2-3 megs of RAM.

If you serve 99% static files and 1% dynamic files with Apache, each httpd process will use from 3-20 megs of RAM (depending on your MOST complex dynamic page).

Related Reading

Web Performance Tuning
Speeding up the Web
By Patrick Killelea

This occurs because a process grows to accommodate whatever it is serving, and NEVER decreases until that process dies. Unless you have very few dynamic pages and major traffic fluctuation, most of your httpd processes will soon take up an amount of RAM equal to the largest dynamic script on your system. A very smart web server would deal with this automatically. As it is, you have a few options to manually improve RAM usage.

Reduce Wasted Processes by Tweaking KeepAlive

This is a tradeoff. The KeepAliveTimeout configuration setting adjusts the amount of time a process sits around doing nothing but taking up space. Those seconds add up in a huge way. Using KeepAlive can increase speed for both you and the client — disable it and the serving of static files such as images may be a lot slower. I think it's best to have KeepAlive on, and KeepAliveTimeout very low, perhaps one or two seconds.

Limit Total Processes with MaxClients

If you use Apache to serve dynamic content, your simultaneous connections are severely limited. Exceed a certain number, and your system begins cannibalistic swapping, getting slower and slower until it dies. Personally, I think the system and/or web server should automatically take steps to prevent this, but by default, they tend to allow the server to consume itself. Use trial and error to figure out how many Apache processes your server can handle, and set this value in MaxClients.

Note: the Apache docs on this are misleading — if this limit is reached, clients are not "locked out," they are simply queued, and their access slows. Based on the value of MaxClients, you can estimate the values you need for StartServers, MinSpareServers, and MaxSpareServers.

Force Processes to Reset with MaxRequestsPerChild

Forcing your processes to die after awhile makes them start over with lower RAM usage. This can reduce total memory usage in many situations. The less dynamic content you have, the more useful this will be. This is a game of catch-up, with your dynamic files constantly increasing total RAM usage, and restarting processes constantly reducing it. Experiment with MaxRequestsPerChild (even values as low as 20 may work well), but don't set it too low, because creating new processes does have overhead.

You can figure out the best settings under-load by examining ps axu --sort:rss. A word of warning: the results can be impressive, but are NOT consistent. If the only way you can keep your server running is by tweaking this, you will eventually run into trouble. That being said, by tweaking MaxRequestsPerChild, you may be able to increase MaxClients as much as 50%.

Finally, think outside the box: replace or supplement Apache.

Use a Second Server

You can use a tiny, lightning fast server to handle static documents and images, and pass more complicated requests on to Apache on the same machine. This way Apache won't tie up multi-megabyte processes serving simple streams of bytes. You can bring Apache into play, for example, only to execute PHP scripts. Good options for this include:

Try lingerd

Lingerd takes over the job of feeding bytes to the client after Apache has fetched the document, but requires kernel modification. It sounds pretty good, but I haven't tried it.

Use a Proxy Cache

A proxy cache can keep a duplicate copy of everything it gets from Apache, and serve the copy instead of bothering Apache with it. This has the benefit of also being able to cache dynamically generated pages, speeding up requests at the expense of using more memory.

Recompile Apache

You could custom build Apache, with optimal settings for your situation, removing parts that you don't require. This is not for the faint of heart.

Replace Apache Completely

If you don't need all the features of Apache, replace it with something more scalable. Currently, the best options appear to be servers that use a nonblocking I/O technology and connect to all clients with the same process. The best include:

Apache Tuning References

Managing PHP's CPU and RAM Usage

Use an Accelerator

Compiling PHP scripts is usually more expensive than running them. Why not use a simple tool that keeps them precompiled? Options include Turck MMCache (fast and free but buggy), PHP Accelerator, APC, and Zend Accelerator. You will likely see a speed increase of 2 to 10 times and a PHP RAM reduction of 50%-85%.

See Optimizing PHP for more ideas.

Managing MySQL's CPU and RAM Usage

Optimize your Queries

This is covered in detail everywhere, so just keep in mind a few important points. One bad query statement running often can bring your site to its knees. Two or three bad query statements don't perform much differently than one. In other words, if you optimize one query you may not see any server-wide speed improvement. If you find and optimize ALL your bad queries you may suddenly see a fivefold server-speed improvement. The log-slow-queries feature of MySQL can be very helpful.

Put your Volatile Data Somewhere Else

If you don't need all the extra features of a relational database, storing data with your own method can be many times faster than MySQL. For temporary data, store it in each user session, or globally with a shared memory library (like the one included with Turck MMCache). More important data can be stored in files, or in your own flat-file database system. A combination of both could be very powerful — your own flat-file database with a copy cached in memory, going to disk only on write.

MySQL Tuning References

Other Solutions

Here are a few other things you may find useful.

Use top and ps axu to check for processes that are using too much CPU or RAM. But beware, these programs will actually lie to you. The total RAM used doesn't always match up — an application's threads share the same memory pages, though it may not look that way.

Use netstat -anp | sort -u to check for network problems.

Use ApacheBench ab to benchmark your results — but keep in mind this tool doesn't accurately simulate actual usage, most notably the effect of many dialup users, who keep connections open longer than you'd like.



If it makes you ill to think about a 20-meg process spending 15 seconds waiting on a KeepAlive after serving a 2k JPEG file, you're not alone! I come from the days of 1 MHz machines running multi-line BBSs. The idea that gigahertz machines with gigabytes of RAM are being limited to 200 simultaneous connections suggests that we're far more influenced by a certain mega-corporate mindset than we'd like to believe. With some basic knowledge of the software and a few of the tips here, you can decrease the bloat and get your server running at least within a reasonable range of how it should, without investing in more hardware.

Adam Pedersen is a freelance web programmer and game developer.

Return to