Although Apache performance can be improved by adding additional hardware resources such as more RAM, faster CPU, but most of the times, the real problem is that the webserver hasn’t been configured properly and is not delivering optimal performance. Hence, the reason for this post is to get the important Apache parameters configured properly so as to get the maximum performance out of Apache with existing hardware resources. Also this post will mainly be dealing with the prefork MPM.
The biggest issue that affects webserver performance is RAM. A webserver should always have enough RAM available so that it should never have to swap at all. Swapping is detrimental to webserver performance. But having enough RAM available is not the end of the story, you should also have the correct configuration. Thinking in terms of “bigger is better” is not always the right way of going about configuring the webserver.
Of course, if you allow too many clients to be connected simultaneously, without having regard to the amount of RAM available, then the webserver is going to start swapping. Suppose you have a traffic spike, then as each incoming request arrives, new child processes are forked and the rate at which they are forked is higher than the rate at which the already forked processes are servicing the old requests. This causes the system to keep creating new processes that overflow the available RAM and start using the swap space. This almost always causes the system to start thrashing, where the system is just swapping pages and not doing any real work.
That is exactly the reason why you should control the MaxClients setting, so that the webserver does not spawn so many child processes that it starts swapping. But how do you determine the correct number?? Its pretty simple, first determine the average size of a single Apache child process, and then divide the RAM that you have allotted to Apache by the average size of child processes. For most cases the average Apache process size is between 15M to 20M.
Suppose you have 2000M of RAM available for Apache, then following is how you will calculate the number of MaxClients:
Available Memory for Apache / Memory Per Process => 2000M / 20M => 100
MaxRequestsPerChild is a setting that controls Apache child process death. By default this is set to a value of 0, which means that there is no limit to the number of requests handled per child. Ideally this value should be high enough, a value of 1000 to 2000 is recommended. So if you currently have this set to a low number, then you may want to increase it significantly. Now although Apache let’s you configure this value such that there is no limit, but you should never do that, the child processes should always be killed off after handling a reasonable number of requests, so that the risk of memory leaks is mitigated.
Configuring Keep Alive
When a client connects to a webserver, it is allowed to request multiple resources over the same connection. This is useful say for a web page that consists of multiple images, the client can request the web page and all the images over the same connection, hence, avoiding the latency associated with multiple connections. But there is also a downside. When keep-alives are being used, the child processes will be kept busy doing nothing but waiting for more requests on the already open connection. This literally means child processes consuming RAM while doing nothing.
Thankfully enough Apache lets you configure both the number of requests that are allowed to be handled by a single connection and also how long to wait for another request before closing the connection. The trade-off here is between network bandwidth and server memory.
Apache allows you to configure keep-alives through the following configuration options:
Off, it decides whether Apache should allow multiple requests to be handled by a single connection. The default Apache configuration file sets KeepAlive to be
KeepAliveTimeout: how long, in seconds, should Apache wait between multiple requests over the same connection, before closing the connection. The default value is a KeepAliveTimeout of 15 seconds. In no event should you raise this above about 60 seconds, otherwise you would be wasting RAM doing nothing. It is advisable to use a low timeout value such as 3 seconds. This ensures that any client that wishes to make another request over the same connection has enough time, and that processes are not idling while waiting for another request that may never arrive.
MaxKeepAliveRequests: how many requests can a client issue over a single connection before forcing the connection closed. The default is 100 requests over the same connection.
Apache is pretty much a general-purpose webserver, and it has to be configured properly according to your needs for it to perform in an optimal manner. In this post, I have touched just a few of the many configuration parameters, but these are ones that if you get right will go a long way in ensuring that your webserver performs optimally. As for the remaining of the important configuration parameters, I will discuss them in a subsequent post.