A recurring question we get from customers is how to fine tune PHP-FPM settings. The official PHP documentation kind of lacks recommendations in this regard. So we’ve made this article explaining how you can calculate the optimal PHP-FPM settings for your server.
PHP-FPM is an acronym for PHP FastCGI Process Manager, one of the most popular PHP FastCGI implementations out there today. When responding to a web request, the server devotes most of its time generating dynamic content. To allow for better concurrency and scaling, PHP-FPM uses pools of processes to simultaneously serve web requests that use PHP code.
The size of these pools either grows or diminishes to accommodate the volume of incoming requests at any given time. Should the amount of incoming requests surpass the current pool size’s capability to serve these requests, the process manager creates additional PHP-FPM processes. On the other way around, if there are too many processes running without being in use, the manager will destroy superfluous processes to conserve resources.
In order to get the best PHP-FPM settings, one must first gather some details about the server’s specifications:
- How many CPU cores does your server have?
- How much RAM is available on your server?
- How much memory your PHP processes consume in average?
Gathering Server Information
Most server administrators know the server resources, but it so may happen that you don’t, as so many times there are so many machines to administer and often we may come across a server without full detail.
In order to find out what resources your server has, we provide a couple of useful commands you can use to figure it out.
For the purpose of this tutorial, we’ll be using as example the PHP-FPM tune we did for one of our customers using an IX-M Server from our Cloud Offer.
Total CPU Cores
When a request is made, one PHP process locks to one CPU core which will be responsible to handle that request. It can be a simple PHP render, but it can also mean that this lock will stand while PHP waits for a SQL query to complete. This happens as PHP was not originally designed for multithreading.
So when your web server is handling multiple requests, you’ll have several PHP processes running concurrently, each using a CPU core. So, CPU is fundamentally important for performance, and our settings must reflect the CPU availability.
In order to get the total cores from your server, run the following command and write down the result:
echo Total CPU Cores = $(( $(lscpu | awk '/^Socket/{ print $2 }') * $(lscpu | awk '/^Core/{ print $4 }') ))
Code language: Shell Session (shell)
The result tells us this server has a total of 2 CPU cores.
Available RAM
We must consider that one system won’t have all the RAM available to be used by PHP, as some amount of memory is used by other processes, either system processes or others such as Apache and/or NGINX, MySQL/MariaDB, etc.
In order to check the available RAM, we can use the free
command. This will tell us how much memory the server has in total, how much is currently used by the system, and the available memory.
free -hl
The IX-M servers have a total of 8 GB of RAM, and we see that less than 2 GB are being used by other processes, resulting in a bit over 6 GB of available memory.
In this case, 6 GB will be the available RAM we will consider, as it is important to leave a little margin.
Average PHP process memory consumption
This is something that depends on several factors, the most important is the application itself, and also the PHP version. It is known that older versions of PHP tend to use more memory than the latter.
The following command looks for processes named php-fpm
, but the PHP process on your server may be under a different name. One simple way to check the correct process name is to run the following command:
ps alx | grep 'fpm'
Finally, in order to get the average memory consumption per PHP process, run the following command:
ps --no-headers -o "rss,cmd" -C php-fpm | awk '{ sum+=$1 } END { printf ("Average memory per PHP process: " "%d%s\n", sum/NR/1024,"M") }'
Code language: Shell Session (shell)
In this server, the average PHP process is using 147M of RAM.
Tuning PHP-FPM settings
Now that we have gathered all the information required, let’s proceed to configure the PHP-FPM settings. The server at hand uses the www
pool only, so we will edit its configuration file located at /etc/php-fpm.d/www.conf
The PHP-FPM settings we’ll be changing are:
- pm.max_children
- pm.start_servers
- pm.min_spare_servers
- pm.max_spare_servers
PHP-FPM: pm.max_children
The PHP-FPM max_children
setting is a limit that designates the maximum number of concurrent PHP-FPM processes allowed to run on a server.
So far we’ve determined that we have 6 GB of RAM to allocate to PHP. We have also calculated that in average, each PHP process is around 147M in size. To determine how many concurrent PHP processes may run, we divide the available memory amount per the average PHP process size:
Available RAM / Average PHP process memory consumption = x
6000 / 147 = x
x = 40
So we will set the setting pm.max_children
to 40
.
PHP-FPM: pm.start_servers
The PHP-FPM start_servers
setting tells the PHP-FPM process manager how many child processes should be started when the PHP-FPM service starts.
To determine the value for pm.start_servers
we multiply the number of CPU Cores by 4. Since the server has 2 CPU cores, the formula is:
Total CPU Cores * 4 = y
2 * 4 = y
y = 8
So we set pm.start_servers
to 8.
PHP-FPM: pm.min_spare_servers
The min_spare_servers
setting determines the minimum number of children processes in the ‘idle’ state (waiting for requests to process). If the number of ‘idle’ processes is less than the value defined here, new child processes will be created.
To determine the value for pm.min_spare_servers
we multiply the number of CPU Cores by 2. So the formula is:
Total CPU Cores * 2 = z
2 * 2 = z
z = 4
So we set the value of pm.min_spare_servers
to 4.
PHP-FPM: pm.max_spare_servers
The max_spare_servers
setting determines the maximum number of children processes in the ‘idle’ state (waiting for requests to process). If the number of ‘idle’ processes is greater than the value defined here, some child processes will be killed.
The formula to determine the value for pm.max_spare_servers
is just alike the one we used to calculate the pm.start_servers
, so we multiply the number of CPU Cores by 4. Just like before:
Total CPU Cores * 4 = y
2 * 4 = y
y = 8
And we set the value of pm.max_spare_servers
to 8.
Applying the new PHP-FPM settings
Now that we’ve determined the optimal PHP-FPM settings for our pool, it’s time to put these changes into effect. To do this, all we have to do is to restart the PHP-FPM process:
systemctl restart php-fpm
We hope you found this article interesting and useful. And don’t forget, if you’re having trouble finding the best settings for your server, you can always reach out to us.