Understanding And Optimizing Apache 2.4 – Prefork MPM

Apache is one of the popular webservers used widely. It is used in different MPM configuration based on kind of websites hosted, traffic, security needs. By default, it uses prefork. In this blog, we are going in detail about only prefork MPM. There is no explanation about any other MPM. If you are trying to understand apache prefork and looking for how it can be optimised, go ahead.

Prefork uses multiple processes and each process handles single connection at a time. It does not use thread. So each request is isolated from other and problem with one request does not affect other.

More details are available here.  https://httpd.apache.org/docs/2.4/mod/prefork.html

Here we tried our best to explain by showing example from a test server. If you have any questions, please leave a comment.

Let’s start.

  • First check which MPM is used by the apache
[root@apache ~]# httpd -V | grep “Server MPM”
Server MPM:     prefork
  • Check the prefork configurations used in apache conf file.

Ex:

<IfModule mpm_prefork_module>
ServerLimit                  10
StartServers                        2
MinSpareServers           3
MaxSpareServers          4
MaxRequestWorkers     10
MaxConnectionsPerChild 20
</IfModule>

Understanding directives

  • ServerLimit:-

Maximum number of child processes that apache is allowed to run.

  • StartServers:-

Number of child processes created during apache startup.

  • MinSpareServers:-

Minimum number of idle child processes running. If apache parent process finds that there are idle child processes lesser than minispareservers, it will start the new child processes until it reaches the number setup in MinSpareServers directive.

  • MaxSpareServers:-

Maximum number of idle child processes allowed to run. If apache parent process finds that there are idle child processes more than the number specified in MaxSpareServer directive, it will terminate them until it reaches the limit configured..

  • MaxRequestWorkers:-

Maximum number of child processes allowed to run. In case of prefork, this is the number of concurrent requests that apache can handle. Because in prefork configuration, each child process handles one request at a time.

  • MaxConnectionsPerChild:

If this value is set to 0, a child process will never die.

If this value is set to some value. For example let’s say 10. Then, the child process will die after handling 10 connections. This is recommended to set to some value such as 1000 or more for busy servers to avoid memory leak.

Getting better picture of apache prefork.

  • As per the above configuration, StartServer is 2 and MinSpareServers is 3. So when apache is started, we should be able to find 3 child processes in few seconds.
[root@apache ~]# ps -C httpd
PID TTY          TIME CMD
1152 ?        00:00:00 httpd
1154 ?        00:00:00 httpd
1155 ?        00:00:00 httpd
1156 ?        00:00:00 httpd
  • Here, there are 4 processes instead of 3. This is because, the first process is parent process.
  • To get better picture, run $pstree -alp and scroll through to find the processes.
 ├─httpd,1152 -DFOREGROUND
 │   ├─httpd,1154 -DFOREGROUND
 │   ├─httpd,1155 -DFOREGROUND
 │   └─httpd,1156 -DFOREGROUND
  • A test is made with 100 concurrent connections. But webserver is handling only 10 requests at a time and website was taking long time to load.
[root@apache ~]# ps -C httpd
PID TTY          TIME CMD
1152 ?        00:00:00 httpd
1367 ?        00:00:02 httpd
1661 ?        00:00:01 httpd
1670 ?        00:00:01 httpd
1671 ?        00:00:01 httpd
1680 ?        00:00:01 httpd
1681 ?        00:00:01 httpd
1682 ?        00:00:01 httpd
1688 ?        00:00:00 httpd
1689 ?        00:00:00 httpd
[root@apache ~]# ss -tn src :80 or src :443 | wc -l
101
  • Once all the requests are served, the child processes becomes idle. This is when parent process starts killing the children until it reaches MaxSpareServers limit.
  • In this case, MaxSpareServers is set to 4.
 ├─httpd,1152 -DFOREGROUND
 │   ├─httpd,3750 -DFOREGROUND
 │   ├─httpd,3777 -DFOREGROUND
 │   ├─httpd,3786 -DFOREGROUND
 │   └─httpd,3805 -DFOREGROUND

Lets change ServerLimit to 8 and see what happens to MaxRequestWorkers

[root@apache ~]# ps -C httpd
PID TTY          TIME CMD
3906 ?        00:00:00 httpd
4078 ?        00:00:05 httpd
4085 ?        00:00:05 httpd
4086 ?        00:00:04 httpd
4095 ?        00:00:04 httpd
4101 ?        00:00:04 httpd
4102 ?        00:00:04 httpd
4111 ?        00:00:03 httpd
4112 ?        00:00:03 httpd
  • Even though MaxRequestWorkers is 10, only 8 child processes are running. Because it cannot override the value set in ServerLimit.

Optimization

  • The memory used by the apache is the total memory used by all the children processes and parent process. To find the total memory used by apache, run the following command.

[root@apache ~]# ps -C httpd -o rss | sed ‘1d’ | awk ‘{x += $1}END{print “Total Memory used (kb):

Total Memory usage: 78284

To find average memory used by each apache process, following command can be used.The memory usage is in kb. It is approximately 78MB here.

[root@apache ~]# ps -C httpd -o rss | sed ‘1d’ | awk ‘{x += $1;y += 1}END{print “Total Memory usage (KB): “ x “\nAverage memory usage (KB): “(x/y)}’
Total Memory usage (KB): 78284
Average memory usage (KB): 15656.8

Memory usage by each apache process is aproximately 16MB here.

You can also run the following command and check the first column.

[root@apache ~]# ps -C httpd -o rss,ucmd
RSS CMD
14188 httpd
16028 httpd
16024 httpd
16024 httpd
16020 httpd

Let’s allocate 400MB for apache and it should never cross this limit because there could be memory shortage in the server.Let’s say the server is having 1GB ram. 600MB of ram be required for other services such as mysql, exim, php etc.

Each process takes 16M and available ram for apache is 400MB.

Dividing 400 by 16 gives 25.

That means we can run maximum of 25 apache processes. If we exclude parent process, then it leaves us 24 child processes.

So MaxRequestWorkers can be up to 24 or Server limit can be set to 24.

Here it is set according to the memory capacity. But it may not be ideal if the cpu cores are less. During busy hours, the apache could be running maximum number of child processes and processing the requests. It passes the requests to php, mysql to process and provides the result. So php and mysql might consume the resources. So optimise them or try by reducing MaxRequestWorkers to limit the connections.

D KarthiKeyan