Squeezing the most performance out of your Apache server can make a difference in how your Web site functions and the impression it makes. Even fractions of a second matter, especially on dynamic sites.
1. Selecting the correct MPM
Apache is modular in that you can add and remove features easily. Multi-Processing Modules (MPMs) provide this modular functionality at the core of Apache -- managing the network connections, binding to ports and dispatching the requests. MPMs let you use threads or even move Apache to a different operating system.
Only one MPM can be active at a time, and it must be compiled in statically with:--with-mpm=(worker|prefork|event)
.
The traditional model of one process per request is called prefork. A newer, threaded, model is called worker, which uses multiple processes, each with multiple threads to get better performance with lower overhead. Finally, event MPM is a module that keeps separate pools of threads for different tasks.
- To determine which MPM you're currently using, execute
httpd -V
- You can view what Apache modules have been compiled by entering
httpd -l
Choosing the correct MPM to use depends on many factors. On the surface, threading sounds better than forking, if all the underlying modules are thread safe, including all the libraries used by PHP.
Prefork is the safer choice; you should do careful testing if you choose worker. The performance gains also depend on the libraries that come with your distribution and your hardware.
- Worker MPM
uses multiple child processes that can have multiple threads each. Each thread handles one connection at a time. Worker generally is a good choice for high-traffic servers running Apache versions prior to 2.4 because it has a smaller memory footprint than the prefork MPM. However, it suffers due to incompatibilities with non-thread safe libraries. - Event MPM
is threaded like the Worker MPM, but is designed to allow more requests to be served simultaneously by passing off some processing work to supporting threads, freeing up the main threads to work on new requests. Event MPM functions identically as worker MPM in the event of SSL connections. Apache has the lowest resource requirements when used under the Event MPM. Event MPM is only available from Apache 2.4 - Prefork MPM
uses multiple child processes with one thread each. Each process handles one connection at a time. On many systems, prefork is comparable in speed to worker, but it consumes more memory. Prefork's threadless design has advantages over worker in some situations: Prefork is the safest module and can be used with non-thread-safe third-party modules. Prefork MPM is also easier to debug on platforms with poor thread debugging support.
Regardless of which MPM you choose, you must configure it appropriately. In general, configuring or performance tuning an MPM involves telling Apache how to control the active and inactive workers and whether they're threads or processes. From Apache 2.2 Prefork is the default MPM.
Other MPM options
The optional mod_mpm_itk
Apache module causes the Apache process to switch to the domain owner's user identifier (UID) and group identifier (GID) before it responds to the request. This allows each user to isolate their files from others with the standard file permission settings. It essentially allows for the isolation of each vhost directly in its configuration file.
The main limitation of the ITK lies in its performance, because it creates and then destroys a process for each query, which degrades performance, especially compared to Prefork or Worker MPM.
mod_mpm_itk
does not function as a stand-alone MPM. You must install the prefork MPM in order to use the MPM ITK module, which needs to be installed separately.
mpm_winnt
is part of Apache’s integration into the Microsoft Windows operating system. Usage of this MPM is a requirement when utilizing Apache on this system type.
There are other experimental MPMs available, but we do not recommend to use them in a production environment.
2. Locating Apache.conf
To start, locate and open the Apache configuration file and find the MPM directives section:
- CentOS / RHEL / Fedora:
/etc/httpd/conf/httpd.conf
- Ubuntu / Debian:
/etc/apache2/httpd.conf
- DirectAdmin:
/etc/httpd/conf/extra/httpd-mpm.conf
- cPanel:
/etc/apache2/conf.d/httpd.conf
- Plesk:
/etc/httpd/conf/
If you are using nano, vi or vim: once you open the file, you can find the directives by scrolling through the file. Using VI or VIM you can also search by typing forward-slash ‘/’ and typing the exact string that you are looking for (search is case specific).
Below you can find an example configuration for the MPM prefork module:
#nano /etc/httpd/conf/httpd.conf < IfModule mpm_prefork_module> StartServers 4 MinSpareServers 20 MaxSpareServers 40 MaxRequestWorkers 200 MaxConnectionsPerChild 4500 </IfModule >
To change the MPM in plain RHEL or Debian based systems replace mpm_prefork_module
with mpm_worker_module
or mpm_event_module
, respectively.
In DirectAdmin the MPM module can be selected by using Custombuild
or by editing /usr/local/directadmin/custombuild/options.conf
cPanel administrators can change the MPM by following WHM > Home > Software > EasyApache 4
3. MPM Directives
Below you may find links to the Apache documentation for all 3 MPM modules:
StartServers (Prefork, Event, Worker MPM)
sets the number of child server processes created on startup. As the number of processes is dynamically controlled depending on the load there is usually little reason to adjust this parameter, unless you frequently restart your server and contains a large number of requests upon reboot.
Hint: Mirror this value to what is set in MinSpareServers
.
MinSpareServers (Prefork MPM)
Sets the desired minimum number of idle child server processes. An idle process is one which is not handling a request, but waiting for a new request.
If there are fewer spareservers idle then specified by this value, then the parent process creates new children at a maximum rate of 1 per second. From Apache 2.4, this rate increases exponentially starting with 1 and ending with 32 children spawned per second.
The benefit is that when a request comes in it can take an idle thread; should a thread not be available, Apache would have to spawn a new child, taking up resources and extending the time it takes for the request to go through.
Woktron recommends adjusting the value for this setting as follows. These values are based on the total amount of memory (RAM) that is installed:
- Virtual Private Server 5
- Dedicated server with 1-2GB RAM 10
- Dedicated server with 2-4GB RAM 20
- Dedicated server with 4+ GB RAM 25
Setting this parameter to a high number is almost always a bad idea, unless it involves very busy websites.
MaxSpareServers (Prefork MPM)
Sets the desired maximum number of idle child server processes. An idle process is one which is not handling a request, but waiting for a new request.
If there are more than MaxSpareServers
idle, then the parent process will kill off the excess processes. If there are more idle processes than this number, then they are terminated.
If the MaxSpareServers value is less than MinSpareServers, Apache will automatically adjust MaxSpareServers to equal MinSpareServers plus one.
Unless your website is extremely busy, this number should not be set too high, since idle processes consume valuable resources.
ServerLimit (Prefork, Event, Worker MPM)
In Prefork MPM The ServerLimit
directive represents the upper limit of MaxRequestWorkers. This setting is generally used as a safeguard or ceiling against input errors when modifying MaxRequestWorkers.
With Prefork MPM ServerLimit is only used in case you need to set MaxRequestWorkers
higher than 256 (default). In this case you should match the value you have set for MaxRequestWorkers, but you should not set the value of this directive any higher than what you might want to set MaxRequestWorkers to.
In Event MPM and Worker MPM ServerLimit
represents the upper limit of children Apache is allowed. The cap prevents spawning vastly more children than a system can handle, resulting in downtime, or even data loss.
For the worker and event MPMs, this directive in combination with ThreadLimit
sets the maximum configured value for MaxRequestWorkers
for the lifetime of the Apache httpd process.
For the event MPM, this directive also defines how many old server processes may keep running and finish processing open connections.
ThreadLimit (Event, Worker MPM)
This directive sets the maximum configured value for ThreadsPerChild
for the lifetime of the Apache httpd process. Any attempts to change this directive during a restart will be ignored, but ThreadsPerChild
can be modified during a restart up to the value of this directive.
Special care must be taken when using this directive. If ThreadLimit
is set to a value much higher than ThreadsPerChild
, extra unused shared memory will be allocated. If both ThreadLimit
and ThreadsPerChild
are set to values higher than the system can handle, Apache httpd may not start or the system may become unstable.
Do not set the value of this directive any higher than your greatest predicted setting of ThreadsPerChild
for the current run of Apache httpd.
ThreadsPerChild (Event, Worker MPM)
This directive sets the number of threads created by each child process. Every thread running can handle a single request. The child creates these threads at startup.
If using an MPM like mpm_winnt, where there is only one child process, this number should be high enough to handle the entire load of the server.
If using an MPM like worker, where there are multiple child processes, the total number of threads should be high enough to handle the common load on the server.
There is an upper limit on this directive as well, and the limit is controlled by the ThreadLimit
directive, which defaults to 64 threads.
The adjustments to increase ThreadsPerChild
past 64 threads also need to be made to ThreadLimit
.
Increasing this value allows each child to handle more requests keeping memory consumption down while allowing a larger MaxRequestWorkers
directive. A key benefit of running more threads within each child is shared memory cache access. Threads from one child cannot access caches from another child. Boosting the number of threads per child squeezes out more performance due to this sharing of cache data
The default value for ThreadsPerChild
is 64 when used with mpm_winnt and 25 when used with Prefork, Event or Worker MPM. This works well in most cases and is a fair balance between children and threads.
MaxRequestWorkers / MaxClients (Prefork, Event, Worker MPM)
MaxRequestWorkers
was called MaxClients
before Apache version 2.3.13. However, the old name is still supported. It sets the limit on the number of simultaneous requests that will be served. Any connection attempts over 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 a different request, the connection will then be serviced.
If this value is set too low, connections sent to queue eventually time-out; however, if this directive is set too high, it causes the memory to start swapping.
For non-threaded servers (i.e., 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 must also raise ServerLimit
.
MaxRequestWorkers
and ServerLimit
should have equal or near equal values with MaxRequestWorkers
never exceeding ServerLimit
. For servers under high load this value should be increased.
See below for more information on how to define the MaxRequestWorkers
directive.
I define Critical Services as services such as mySQL, Plesk, DirectAdmin; any service that is required for proper operation of your server.
I’ve used the following commands via shell to determine values for Total Memory, OS Memory, MySQL Memory, and Apache Process Size:
TOTAL MEMORY
[root@vps httpd]# free -m total used free shared buffers cached Mem: 1002 599 402 0 28 337
-/+ buffers/cache: 233 769
Swap: 2047 124 1922
MYSQL MEMORY
[root@vps httpd]# ps aux | grep ‘mysql’ | awk ‘{print $6}’
408
21440
704
APACHE PROCESS SIZE
[root@vps httpd]# ps aux | grep ‘httpd’ | awk ‘{print $6}’
22468
11552
41492
40868
41120
41696
39488
41704
15552
16076
16084
728
In this case the server has 1002Mb of memory allocated, xx used by the OS itself, 21Mb used by mySQL, and each Apache thread averages about 30Mb. MaxClients = (1002 – 21) / 30 therefore MaxClients = 32.7
The required values can also be determined with one single command
free -mps aux | grep 'mysql' | awk '{print $6}'ps aux | grep 'postgresql' | awk '{print $6}'ps aux | grep 'httpd' | awk '{print $6}'
MaxConnectionsPerChild (Prefork, Event, Worker MPM)
MaxConnectionsPerChild
sets the limit on the number of connections that an individual child server process will handle. After MaxConnectionsPerChild
connections, the child process will die. If MaxConnectionsPerChild
is 0, then the process will never expire.
Setting MaxconnectionsPerChild to a non-zero value limits the amount of memory that process can consume by (accidental) memory leakage. Code executed through Apache may contain faults which leak memory. These leaks add up over time making less and less of the shared memory pool of the child usable. The way to recover from leaked memory is to recycle the affected Apache child process.
How to determine the best value for MaxConnectionsPerChild
:
Determining these values is a bit more complex as it requires some type of statistics package or thorough knowledge of interpreting Apache access logs.
This directive does not adversely effect memory usage, only a small amount of cpu time to cycle the process. Therefore, if you are unable to determine this information the default setting of 1000 should be used.
4. Core Apache Directives
The core directives for Apache can be edited in the files below:
On a DirectAdmin based server it will be located in: /etc/httpd/conf/extra/httpd-default.conf
On a cPanel server, it will be located in /etc/apache2/conf.d/httpd.conf
On a Plesk server, it will be in /etc/httpd/conf/
If you are using nano, vi or vim: once you open the file, you can find the directives by scrolling through the file. Using VI or VIM you can also search by typing forward-slash ‘/’ and typing the exact string that you are looking for (search is case specific).
Timeout
The Timeout
setting is the number of seconds before data "sends" or "receives" (to or from the client) times out. The default value is set to 60
seconds.
Determining the ideal Timeout
value depends on both traffic habits and hosted applications. Ideally, Timeout
should be as low as possible while still allowing the vast majority of regular traffic to operate without issue.
Large timeouts force site visitors to "wait in line" which adds extra load to the server. It also opens the server to SlowLoris style DOS attacks and could cause a long wait in the browser when it does encounter a problem.
Low timeouts allow Apache to recover from errant stuck connections quickly. Lowering the Timeout
value too much will cause a long running script to terminate earlier than expected.
It becomes necessary to strike a balance between the two extremes.
A reasonable value is 100-120 for Virtual Private Servers with limited resources, or heavily loaded dedicated servers. For servers under normal load a lower value, preferably below 60, is recommended.
KeepAlive
The KeepAlive
directive can provide as much as a 50% reduction in latency, while providing a reduction in CPU usage. It helps significantly with boosting the performance of Apache. The default value is ON
.
This performance boost is accomplished by enabling persistent connections on the web server. These persistent connections reuse the same initial connections a browser creates when connecting to Apache for all follow-up requests which occur within a short period.
KeepAlive
should be set to On in most situations.
However, KeepAlive
increases memory usage and should be disabled on servers that have only a limited amount of RAM available.
This is because Apache processes have to keep connections open waiting for new requests from established connections. While they are waiting they are occupying RAM that could be used to service other clients. If you turn off KeepAlive fewer apache processes will remain active.
You should also disable KeepAlive if you have bursty traffic where a lot of concurrent users access your sites during a short time period. KeepAlive will cause your RAM usage to skyrocket.
In short, Disabling KeepAlive will lower memory usage and allows Apache to serve more users, while enabling KeepAlive improves performance and decreases CPU load.
MaxKeepAliveRequests
and KeepAliveTimeout
. Discussed in the next section, play a vital role in fine-tuning the KeepAlive directive.
MaxKeepAliveRequests
This setting limits the number of requests allowed per persistent connection when KeepAlive
is on. If it is set to 0, unlimited requests will be allowed. The default value is 100
.
Generally, you want this value to be at least as high as the largest count of elements (HTML, Text, CSS, Images, Etc..) served by the most heavily trafficked pages on the server.
It is recommended to not increase this value beyond 100 for virtualized accounts like VPS accounts. On dedicated servers with ample of RAM it is possible for this value to be increased.
KeepAliveTimeout
The number of seconds Apache will wait for another request before closing the connection.
Setting this to a high value may cause performance problems in heavily loaded servers. The higher the timeout, the more server processes will be kept occupied waiting on connections with idle clients.
The default value of 10
seconds is a good value for average server performance. This value should be kept low as the socket will be idle for extended periods otherwise. It is recommended that this value be lowered to 5
on servers under heavy load.
5. Other Performance Improvements
Remove Unused Modules
Preserve memory by disabling unneeded modules from loading, including but not limited to mod_php, mod_ruby, mod_perl, etc. Remember, you can view what Apache modules have been compiled by entering httpd -l
Set ExtendedStatus Off
ExtendedStatus
will produce several system calls for each request to gather statistics, which negatively impacts performance. When possible it is better to utilize ExtendedStatus
for a set time period in order to benchmark, but then turn it back off.
Disable HostnameLookups
Avoid doing DNS lookups that always cost additional CPU time. You will rarely ever need HostnameLookups
and when you do, you can look them up after the fact. If you have HostnameLookups
off, avoid using hostname in configs as this will prevent you from having to wait for the DNS of the hostnames in your configs to resolve. You should use IP addresses instead.
Utilize mod_gzip/mod_deflate
Gzip your content before sending it off, which then the client will uncompress upon receipt. This will minimize the size of file transfers and will generally improve the user experience.
Avoid DirectoryIndex Wildcards
Select a specific DirectoryIndex
, i.e. index.html or index.php, not index.
Use mod_disk_cache NOT mod_mem_cache
mod_mem_cache
will not share its cache among different apache processes. This results in high memory usage with little performance gain, because mod_mem_cache
will rarely serve the same page twice in the same apache process.
Instead, use mod_disk_cache
with a flat hierarchy. Set values CacheDirLength=2
and CacheDirLevels=1
to ensure htcacheclean will not take forever when cleaning up your cache directory.
To utilize your cache you must also be sure to setup appropriate Expires, Etag, and Cache-Control Headers i.e. you must tell when a file expires, otherwise you will not experience any caching benefits.
Move Cache to external drive
Place your cache on a separate physical disk for fastest access without slowing down other processes. A Solid State Drive provides the fastest access times.
6. Testing and Restarting Apache
Be sure once you’ve saved the file to perform a configuration test before restarting Apache. This test parses the configuration files and either reports a Syntax Ok
or it offers information about the particular syntax error.
To test your Apache configuration enter:
[root@vps httpd]# service httpd configtest Syntax OK
Or:
[root@vps httpd]# apachectl -t Syntax OK
To restart Apache enter:
[root@vps httpd]# service httpd restart Stopping httpd: [ OK ] Starting httpd: [ OK ]
cPanel Only: More information about the correct procedure to edit your Apache configuration can be found here
7. Apache2Buddy
Apache2Buddy is a script similar to MySQLTuner, that reviews your Apache setup, and makes suggestions based on your Apache process memory and overall RAM. The apache2buddy.pl script will check for the following:
- PHP memory limits
- Memcache
- MaxClients
- Memory usage
- Max potential memory usage
- Percentage of total RAM allocated to Apache
- MaxRequestWorkers
You can run the script with the following command:
curl -sL https://raw.githubusercontent.com/richardforth/apache2buddy/master/apache2buddy.pl | sudo perl
8. ApacheBench
Apache Bench (ab) is a load testing and benchmarking tool designed for Apache webserver installations (although, it will work without issue on any HTTP server such as nginx).
To install ab
, run the following commands:
CentOS/Fedora
yum install httpd-tools
Debian/Ubuntu
apt-get update apt-get install -y apache2-utils
Syntax
to benchmark your server, enter the command below, replacing yourdomain
with your domain name.
ab -t 60 -n 20 -kc 5 http://yourdomain.com/
Running ApacheBench is similar to directing a denial-of-service attack towards your own server. This particular tool is not designed to be sympathetic to your infrastructure, and provides no ability to increase concurrency in measured intervals over a testing period.
The only option when running a load test through ab
is to flood your web server with an arbitrary number of simultaneous requests all in one instant.
Optional Flags
-n [value]
: The number of requests to send-t [value]
: A duration in seconds for which each connection is alive-c [value]
: The number of concurrent requests to make-l
: ignore length checking-v 2
: will dump each response's body and header to stdout so that you can identify success or failure.-k
: HTTP Keep-Alive
Keep in mind that if you’re using both the -t
and the -n
flags, -t
should always go first
9. Other benchmarking tools
Some additional benchmarking tools for HTTP webservers are:
SIEGE
HTTP load test utility supported on UNIX. You can benchmark multiple URL’s by creating a text file to load test against.
Installation
yum install siege
syntax
siege -q -t 5S -c 500 http://yourdomain.com
Optional flags
-q
: run quietly (not showing request details)-t
: run for 5 seconds-c
: 500 concurrent requests
Gobench
A load testing utility to benchmark web server performance written in Go
language. It supports more than 20,000 concurrent users.
Apache JMeter
One of the most popular open source tools to measure web application performance. JMeter is a java based application. It not only supports webservers, but you can use it to benchmark the performance of PHP, Java. ASP.net, SOAP, REST, etc. .
wrk
With wrk, you can specify to run a load test with a number of threads.
syntax
wrk –t4 –c100 -d120s http://yourdomain.com
Optional flags
-d
: test for 2 minutes (120 seconds)-t
: 4 threads-c
: 100 concurrent users
HTTPLoad
Httpload can read multiple URLs from text files, or you can specify it in the command argument. Httpload supports SSL/TLS encryption, meaning you have the ability to query HTTPS (SSL) enabled web pages.
syntax
httpload -cipher AES256-SHA -parallel 200 -seconds 120 URL_LIST.txt
httperf
syntax
httperf --server yourdomain.com --port 80 --num-conns 1000 --rate 100