PHP-FPM tuning: Using ‘pm static’ for Max Performance
Let's take a very quick look at how best to set up PHP-FPM for high throughput, low latency, and a more stable use of CPU and memory. By default, most setups have PHP-FPM’s PM (process manager) string set to dynamic and there’s also the common advice to use
ondemand if you suffer from available memory issues. However, let's compare the two management options based on php.net’s documentation and also compare my favorite for high traffic setup --- static pm:
pm = dynamic: the number of child processes is set dynamically based on the following directives:
pm = ondemand: the processes spawn on demand when requested, as opposed to dynamic, where
pm.start_serversare started when the service is started.
pm = static: the number of child processes is fixed by
See the full list of global
php-fpm.conf directives for further details.
PHP-FPM Process Manager (PM) Similarities to CPUFreq Governor
Now, this may seem a bit off topic, but I hope to tie it back into our PHP-FPM tuning topic. Okay, we’ve all had slow CPU issues at some point, whether it be a laptop, VM or dedicated server. Remember CPU frequency scaling? (CPUFreq governor.) These settings, available on both *nix and Windows, can improve the performance and system responsiveness by changing the CPU governor setting from ondemand to performance. This time, let's compare the descriptions and look for similarities:
Governor = ondemand: scales CPU frequency dynamically according to current load. Jumps to the highest frequency and then scales down as the idle time increases.
Governor = conservative: scales the frequency dynamically according to current load. Scales the frequency more gradually than ondemand.
Governor = performance: always run the CPU at the maximum frequency.
See the full list of CPUFreq governor options for further details.
Notice the similarities? I wanted to use this comparison first, with the aim of finding the best way to write an article which recommends using pm static for PHP-FPM as your first choice.
With CPU governor, the performance setting is a pretty safe performance boost because it’s almost entirely dependent on your server CPU’s limit. The only other factors would be things such as heat, battery life (laptop) and other side effects of clocking your CPU frequency to 100% permanently. Once set to performance, it is indeed the fastest setting for your CPU. For example read about the ‘force_turbo’ setting on Raspberry Pi, which forces your RPi board to use the performance governor where performance improvement is more noticeable due to the low CPU clock speeds.
Using ‘pm static’ to Achieve Your Server’s Max Performance
The PHP-FPM pm static setting depends heavily on how much free memory your server has. Basically, if you are suffering from low server memory, then pm ondemand or dynamic may be better options. On the other hand, if you have the memory available, you can avoid much of the PHP process manager (PM) overhead by setting pm static to the max capacity of your server. In other words, when you do the math,
pm.static should be set to the max amount of PHP-FPM processes that can run without creating memory availability or cache pressure issues. Also, not so high as to overwhelm CPU(s) and have a pile of pending PHP-FPM operations.
In the screenshot above, this server has
pm = static and
pm.max_children = 100 which uses a max of around 10GB of the 32GB installed. Take note of the self explanatory highlighted columns. During that screenshot there were about 200 ‘active users’ (past 60 seconds) in Google Analytics. At that level, about 70% of PHP-FPM children are still idle. This means PHP-FPM is always set to the max capacity of your server’s resources regardless of current traffic. Idle processes stay online, waiting for traffic spikes and responding immediately, rather than having to wait on the pm to spawn children and then kill them off after
x pm.process_idle_timeout expires. I have
pm.max_requests set extremely high because this is a production server with no PHP memory leaks. You can use
pm.max_requests = 0 with
static if you have 110% confidence in your current and future PHP scripts. However, it’s recommended to restart scripts over time. Set the number of requests to a high number since the point is to avoid pm overhead. So for example at least
pm.max_requests = 1000 depending on your number of
pm.max_children and number of requests per second.
The screenshot uses Linux top filtered by ‘u’ (user) option and the name of the PHP-FPM user. The number of processes displayed are only the ‘top’ 50 or so (didn’t count), but basically top displays the top stats which fit in your terminal window --- in this case, sorted by %CPU. To view all 100 PHP-FPM processes you can use something like:
top -bn1 | grep php-fpm
Continue reading %PHP-FPM tuning: Using ‘pm static’ for Max Performance%