I had to handle high-traffic loads a few months ago for my client and we were going through with downtime, not using memory, and a lot of trouble in my past. In this article, I want to give a step-by-step guide to apache2 performance settings, which is a concentrated result of a lot of reading and trying.
My environment
- AWS EC2 (m4.xlarge): 4 *2,4GHz | 16GB RAM
- Ubuntu 16.04
- Apache 2.4 using mpm_event
- PHP FPM (5.6, 7.4)
Precalculation of average memory usage and max clients/max-children
1. Calculate process size
You need to know how many processes can run on your machine. So calculating the process size of your main CPU/memory drivers is necessary.
There are several calculation methods out there. Personally, I prefer this Python script as it takes shared memory into account and will give insights into actual memory usage.
cd ~
wget https://raw.githubusercontent.com/pixelb/ps_mem/master/ps_mem.py
chmod a+x ps_mem.py
sudo python ps_mem.py
ps_mem.py will produce output like this:
Here you can see that there are 30 apache2 processes, consuming a total of 139MiB, so each Apache process uses roughly 5MiB of RAM. The PHP-fpm5.6 process will use about 50MiB.
2. Calculate Apache MaxRequestWorkers
To be safe though, I’ll reserve 15% of memory for all other processes (in my case ~2,4GiB) and round up Apache process size to 5MiB.
MaxRequestWorkers = (Total RAM - Memory used for Linux, DB, etc.) / process size
MaxRequestWorkers = (16384MB - 2400MB) / 5MB = 2800
3. Calculate php-fpm max-children
To be safe though, I’ll reserve 1 GiB for all other processes and round up the php process size to 55MiB.
maxclients = (Total RAM - Memory used for Linux, DB, etc.) / process size
maxclients = (16384MB - 2400MB) / 55MB = 256
I found, this Excel Sheet for the calculation: https://s3.buckpesch.io/downloads/apache_performance.xlsx
Detailed Setup
In the /etc/apache2/mods-enabled/mpm-event.conf
or /etc/apache2/mods-enabled/mpm-worker.conf
file:
<IfModule mpm_*_module>
ServerLimit (Total RAM - Memory used for Linux, DB, etc.) / process size
StartServers (Number of Cores)
MinSpareThreads 25
MaxSpareThreads 75
ThreadLimit 64
ThreadsPerChild 25
MaxRequestWorkers (Total RAM - Memory used for Linux, DB, etc.) / process size
MaxConnectionsPerChild 1000
</IfModule>
Note that the default settings did not contain the “ServerLimit”, so I added it here.
In the /etc/php/7.4/fpm/pool.d/www.conf
change the following locations:
pm = dynamic
pm.max_children (total RAM - (DB etc) / process size)
pm.start_servers (cpu cores * 4)
pm.min_spare_servers (cpu cores * 2)
pm.max_spare_servers (cpu cores * 4)
pm.max_requests 1000
To learn about all php-fpm settings I recommend watching the video on that page: https://serversforhackers.com/c/php-fpm-process-management
My final settings
My server has 16GB RAM and 4 CPUs à 2,4GHz. My average apache process has 5MB, and an average PHP process takes 55MB.
/etc/apache2/mods-available/mpm_event.conf
# Optimized settings for avg. apache process 15MB and AWS EC2 m4.xlarge Server
<IfModule mpm_event_module>
ServerLimit 2800
StartServers 4
MinSpareThreads 25
MaxSpareThreads 75
ThreadLimit 64
ThreadsPerChild 25
MaxRequestWorkers 2800
MaxConnectionsPerChild 1000
</IfModule>
/etc/php/7.4/fpm/pool.d/www.conf
; Optimized for php-fpm request size of 55MB on AWS EC2 m4.xlarge (4CPU cores, 16GB RAM)
pm = dynamic
pm.max_children = 256
pm.start_servers = 20
pm.min_spare_servers = 10
pm.max_spare_servers = 20
pm.max_requests = 1000
Save your settings and restart your Apache and php-fpm processes
sudo service apache2 restart
sudo service php7.4-fpm restart
Also, read Enable HTTP/2 with Apache in Ubuntu 2023
Test you settings
To test your server settings you can run Apache Bench tests and see how your server behaves in htop
.
Open 2 terminals and the following command to test 5000 requests with a concurrency of 100 parallel requests:
ab -n 5000 -c 100