PHP-FPM tuning: Using ‘pm static’ for Max Performance

Share this article

PHP-FPM tuning: Using ‘pm static’ for Max Performance

An unedited version of article was originally published at HaydenJames.io and republished here with the author’s permission.

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.max_children, pm.start_servers, pm.min_spare_servers, pm.max_spare_servers.

  • pm = ondemand: the processes spawn on demand when requested, as opposed to dynamic, where pm.start_servers are started when the service is started.

  • pm = static: the number of child processes is fixed by pm.max_children.

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.

Linux top php-fpm static pm

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

When to Use pm ondemand and dynamic

Using pm dynamic you may have noticed errors similar to:

WARNING: [pool xxxx] seems busy (you may need to increase pm.start_servers, or pm.min/max_spare_servers), spawning 32 children, there are 4 idle, and 59 total children

You may try to increase/adjust settings and still see the same error as someone describes in this Serverfault post. In that case, the pm.min was too low and because web traffic fluctuates greatly with dips and spikes, using pm dynamic can be difficult to tune correctly. The common advice is to use pm ondemand. However, that’s even worse, because ondemand will shut down idle processes right down to 0 when there’s little to no traffic and then you’ll end up with just as much overhead issues as traffic fluctuates — unless, of course, you set the idle timeout extremely high … in which case you should just be using pm.static + a high pm.max_requests.

PM dynamic and especially ondemand can save you, however, when you have multiple PHP-FPM pools. For example, hosting multiple cPanel accounts or multiple websites under different pools. I have a server, for example, with 100+ cPanel accounts and about 200+ domains, and it would be impossible for pm.static or even dynamic to perform well. Only ondemand performs well, since more than two thirds of the websites receive little to no traffic. And with ondemand, it means all children will be shut down saving tons of server memory! Thankfully, cPanel devs figured this out and now it defaults to ondemand. Previously with dynamic as default it made PHP-FPM not an option on busy shared servers. Many would use suPHP because of pm dynamic eating up memory even on idle cPanel PHP-FPM pools/accounts. Chances are, if you receive good traffic, you won’t be hosted on a server with lots of PHP-FPM pools (shared hosting).

Conclusion

When it comes to PHP-FPM, once you start to serve serious traffic, ondemand and dynamic process managers for PHP-FPM can limit throughput because of the inherent overhead. Know your system and set your PHP-FPM processes to match your server’s max capacity. Start with pm.max_children set based on max usage of pm dynamic or ondemand and then increase to the point where memory and CPU can process without becoming overwhelmed. You will notice that with pm static, because you keep everything sitting in memory, traffic spikes over time cause less spikes to CPU and your server’s load and CPU averages will be smoother. The average size of your PHP-FPM process will vary per web server requiring manual tuning, thus why the more automated overhead process managers — dynamic and ondemand — are more popular recommendations. Hope this was a useful article.

Update: Added A/B benchmark comparison graph. Having PHP-FPM processes sit in memory helps performance at the price of increased memory usage to have them sit in wait. Find your setup sweet-spot.

alt PHP-FPM PM comparison

Frequently Asked Questions (FAQs) about PHP-FPM Tuning

What is PHP-FPM and why is it important for my server’s performance?

PHP-FPM, or FastCGI Process Manager, is an alternative PHP FastCGI implementation with some additional features useful for sites of any size, especially busier sites. It’s important for server performance because it allows the server to handle more simultaneous visitor requests by utilizing a pool of worker processes. These processes are responsible for parsing PHP files, generating dynamic content, and serving it to the client. By efficiently managing these processes, PHP-FPM can significantly improve the performance and scalability of your server.

How does PHP-FPM improve the performance of my website?

PHP-FPM improves website performance by effectively managing PHP processes. It uses a master process to control multiple child processes, which handle PHP scripts. This allows for efficient use of server resources, as idle processes can be killed and new ones can be spawned as needed. Additionally, PHP-FPM supports opcode caching, which can significantly speed up PHP execution by storing precompiled script bytecode in shared memory, thereby eliminating the need for PHP to load and parse scripts on each request.

What is the ‘pm static’ configuration in PHP-FPM and how does it affect performance?

The ‘pm static’ configuration in PHP-FPM sets the number of child processes to a fixed number. This means that there will always be a certain number of processes ready to serve incoming requests, regardless of the current server load. This can lead to better performance under high load, as new processes don’t need to be spawned. However, it can also lead to higher memory usage, as these processes are always running, even when not needed.

How can I tune PHP-FPM for maximum performance?

Tuning PHP-FPM for maximum performance involves adjusting several configuration settings. These include the ‘pm’ setting, which determines the process manager to use, and the ‘pm.max_children’ setting, which sets the maximum number of child processes. Other important settings include ‘pm.start_servers’, ‘pm.min_spare_servers’, and ‘pm.max_spare_servers’, which control the number of servers that start up, the minimum and maximum number of idle servers, respectively. Adjusting these settings to match your server’s resources and traffic patterns can significantly improve performance.

What are some common issues with PHP-FPM and how can I troubleshoot them?

Some common issues with PHP-FPM include high CPU usage, slow response times, and errors related to reaching the maximum number of child processes. These issues can often be resolved by adjusting PHP-FPM configuration settings, such as increasing the ‘pm.max_children’ setting or switching to a different process manager. Additionally, monitoring tools can be used to identify bottlenecks and performance issues.

How does PHP-FPM compare to other PHP handlers?

PHP-FPM is generally considered to be more efficient and flexible than other PHP handlers. It supports a variety of process managers, which can be tuned to match your server’s resources and traffic patterns. Additionally, PHP-FPM supports opcode caching and can handle a large number of simultaneous requests, making it a good choice for busy sites.

Can I use PHP-FPM with any web server?

Yes, PHP-FPM can be used with any web server that supports the FastCGI protocol. This includes popular web servers like Apache, Nginx, and Lighttpd.

What is opcode caching and how does it improve PHP performance?

Opcode caching is a technique that improves PHP performance by storing precompiled script bytecode in shared memory. This eliminates the need for PHP to load and parse scripts on each request, resulting in faster execution times.

How can I monitor the performance of PHP-FPM?

There are several tools available for monitoring the performance of PHP-FPM. These include the PHP-FPM status page, which provides information about the current state of the worker processes, and various command-line tools like ‘top’ and ‘ps’. Additionally, there are several third-party monitoring solutions that provide more detailed metrics and alerts.

What are some best practices for using PHP-FPM?

Some best practices for using PHP-FPM include tuning the process manager settings to match your server’s resources and traffic patterns, enabling opcode caching, and regularly monitoring performance to identify and resolve issues. Additionally, it’s important to keep PHP-FPM and your web server software up to date to benefit from the latest performance improvements and security fixes.

Hayden JamesHayden James
View Author

Hayden James is a Linux Systems Analyst and Internet Entrepreneur from the Caribbean. He relocated to the US ten years ago, where he maintained Linux servers and sold small startups. Today, he supports clients remotely from his island home while also managing a niche web hosting venture. His web blog features Sysadmin and other PHP related articles: haydenjames.io.

BrunoSCPUmemoryperformanceperformance-hubperformance-toolsPHP-FPM
Share this article
Read Next
Get the freshest news and resources for developers, designers and digital creators in your inbox each week