Apache Performance Tuning on Linux
By Abdulaziz Gebril, Alibaba Cloud Community Blog author.
Apache is a general purpose web server, designed to provide a balance of flexibility, portability, and performance. Apache is capable of providing high performance in a variety real-world situations.
Starting with Apache 2.0, Apache extended its features with a selection of Multi-Processing Modules (MPMs), which are responsible for binding to network ports on the machine, accepting and handling the requests. These modules determine the basis of how Apache addresses multi-processing.
The choice of MPM and setting its values affect the speed and scalability of Apache. This blog article will only be focusing on those settings available for Linux. There are three MPMs available to choose from for Linux.
To check what version of your Apache and which MPM your server currently is running, you can use one of the following command:
- In CentOS or Fedora, run: httpd -V
- On Debian or Ubuntu, run: apache2 -v
By following this article, any changes you want to make must be made directly to the Apache configuration file. Before making any changes to your Apache configuration, make sure to back up the configuration file. The file path is one of the following:
- On CentOS or Fedora: /etc/httpd/conf/httpd.conf
- On Debian or Ubuntu: /etc/apache2/apache2.conf
Types of MPMs
The MPM Prefork uses multiple child processes with one thread each. Each process handles one connection at a time. Prefork is comparable in speed when you only deal with a single request at a time, but it uses more memory. The threadless design of Prefork has advantages over the other MPM in some situations: it can be used with non-thread-safe third-party modules such as mod_php (DSO), it is also the best MPM for isolating requests, so that a single request problem will not affect any other.
The MPM Worker uses multiple child processes with many threads each. It can handle dozens of threads (or requests) simultaneously, and each thread handles one connection at a time. It handles concurrency much easier, since the connections just need to wait for a free thread (which is usually available) instead of a spare server in MPM Prefork. Worker is generally a good choice for servers that receive high levels of traffic because it has a much lower memory footprint than the MPM prefork.
Note that the threads are attached to connections and not requests, which means that a keep-alive connection (explained below) always keeps a hold of a thread until it’s closed, which may be a long time, depending on your configuration. This why there’s also the MPM Event.
The MPM Event is threaded like the MPM Worker, but is designed to allow more requests to be served simultaneously by passing off some processing work to the threads, freeing up the main threads to serve new requests. It uses a dedicated listener thread to deal with the kept-alive connections, and hands requests down to child threads only when a request has actually been made, allowing those threads to free back up immediately after the request is completed.
The number of child server processes created on startup of server. As the number of processes is dynamically controlled depending on the load.
The minimum number of idle child server processes that are desired. An idle process is one that is not handling a request. If there are fewer idles than MinSpareServers, the parent process will create new children and continue exponentially until 32 children are spawned per second. It will stop whenever MinSpareServers setting is satisfied.
The maximum number of idle child server processes that are desired. An idle process is one which is not handling a request but waiting for a new request. If there are more than MaxSpareServers idle, the parent process will kill off the excess processes.
Tuning of this parameter should only be necessary on very busy sites, since idle processes consume resources.
The limit on the number of connections to be handled by an individual child server process. After the limits of MaxConnectionsPerChild connections is reached, the child process will die. If MaxConnectionsPerChild is 0, the process will never expire.
Setting MaxConnectionsPerChild to a non-zero value limits the amount of memory that process can be consumed by memory leakage (accidentally).
MaxConnectionsPerChild was called MaxRequestsPerChild before version 2.3.9. The old name is still supported.
For threaded servers (Event or Worker) The number of threads created by each child process. At startup, the child creates these threads and never creates more. The total number of threads should be high enough to handle the server’s common load.
The limit to the number of simultaneous requests to be served. Any connection attempts above the MaxRequestWorkers limit will normally be queued, up to a number based on the ListenBacklog directive. Once a child process is freed at the end of another request, the connection will then be serviced.
MaxRequestWorkers was called MaxClients before version 2.3.13. The old name is still supported.
For non-threaded servers (Prefork), MaxRequestWorkers translates into the maximum number of child processes that will be launched to serve requests. The default value is 256; to increase it, you also need to raise ServerLimit.
For threaded servers (Event or Worker) MaxRequestWorkers restricts the total number of threads that will be available to serve clients. The default value is 16 (ServerLimit) multiplied by the default value of ThreadsPerChild (25). Therefore, to increase MaxRequestWorkers to a value that requires more than 16 processes, you also need to raise ServerLimit.
You must control the MaxRequestWorkers setting so that your server does not start swapping. Limiting the number of processes to serve requests prevents the server from swapping due to a shortage of RAM. The procedure for doing that is find the proper number of MaxRequestWorkers by using a tool such as Apache2Buddy (described below) or manually calculate it.
You can manually calculate MaxRequestWorkers by determine the average amount of memory consumed by Apache and divide it into your total available memory. If you are hosting other applications on the server, subtract the total memory used by these applications, and leave some free memory. In order to check the process list, we are going to use a tool such as top, by running the command:
Where %MEM is the percentage of memory consumption.
For example, if in average one your Apache process consumes (%MEM) is 0.8 and your server RAM is 2GB (2048MB), other applications consumes 250MB, and you want to leave +100MB as a free memory, then:
MaxRequestWorkers = (2048MB — 250MB — 100MB) / (0.8 / 100 * 2048MB) = ~ 103
For the Prefork MPM, ServerLimit sets the maximum configured value for MaxRequestWorkers for the lifetime of the Apache process.
For the Worker and Event MPMs, ServerLimit in combination with ThreadLimit sets the maximum configured value for MaxRequestWorkers for the lifetime of the Apache server process.
For the Event MPM, ServerLimit also defines how many old server processes may keep running and finish processing open connections.
Special care must be taken when using ServerLimit. If ServerLimit is set to a value that is much higher than necessary, extra, unused shared memory will be allocated. If both ServerLimit and MaxRequestWorkers are set to values higher than the system can handle, Apache server may not start or the system may become unstable.
What Is the Default MPM Settings?
For Prefork Module
MaxClients 250 // MaxRequestWorkers
MaxRequestsPerChild 0 // MaxConnectionsPerChild
For Worker or Event Module
MaxClients 400 // MaxRequestWorkers
MaxRequestsPerChild 0 // MaxConnectionsPerChild
Example configuration for MPM:
Replace MODULE_NAME inside with mpm_worker_module, if you want to use Worker module Or mpm_event_module, if you want to use Event module.
You should alter the module settings with a consideration of what each value does, and how best to change it, then monitor the effects of your changes.
Other Settings That May Affect MPM
The Keep-Alive extension to HTTP/1.0 and the persistent connection feature of HTTP/1.1 provide long-lived HTTP sessions that enable multiple requests to be sent over the same TCP connection. In some cases, this has been shown to result in a nearly 50% speed-up in latency times for HTML documents with many images.
Keep-Alive connections will only be used for HTTP/1.0 clients if they are specifically requested by a client. In addition, a Keep-Alive connection with an HTTP/1.0 client can only be used if the length of the content is known in advance.
When a client uses a Keep-Alive connection, it will be counted as a single “request” for MaxConnectionsPerChild, irrespective of how many requests are sent using the connection.
KeepAlive is enabled in Apache 2.4 by default. Enabling KeepAlive can improve your site’s user experience. If KeepAlive is disabled, you can enable it by setting:
It limits the number of requests per connection allowed when KeepAlive is on. If set to 0, unlimited requests will be permitted. The default value is 100. We recommend keeping this setting to a high value for maximum server performance.
Tools That Would Help You
The following tools would help you for measuring the performance of your server and test the MPM Settings values of your Apache.
Apache2Buddy is a great tool that checks your server setup and performance and makes a report and suggestions based on the information it collects. It calculates the MaxRequestWorkers on remaining RAM, not total installed RAM.
You can run Apache2Buddy by using the following command:
curl -sL https://raw.githubusercontent.com/richardforth/apache2buddy/master/apache2buddy.pl | perl
ApacheBench Tool (ab)
ApacheBench tool comes bundled with the standard Apache source distribution for measuring the performance of HTTP web servers. This especially shows you how many requests per second your Apache is capable of serving by generating a flood of requests to a given URL and returns some easily digestible performance related metrics to the screen.
For example, the following command will execute 1000 HTTP GET requests, processing up to 10 requests concurrently, to the specified URL.
ab -k -n 1000 -c 10 "http://yoursite.com/test"
In order to check the process list, we are going to open a new terminal at the same time and use a tool such as top, by running the command:
After making any changes to your Apache configuration, restart the Apache service to let the changes take effect.
- On CentOS/Fedora:
- sudo systemctl restart httpd
- On Debian/Ubuntu:
- sudo systemctl restart apache2
Finally, keep monitoring the effects of your changes and performance of your server.
References and Useful Links
- Apache Performance Tuning
- Apache Multi-Processing Modules (MPMs)
- Apache MPM Common Directives
- Apache Core Features