Configuring PHP-FPM: using pm static for maximum performance

Configuring PHP-FPM: using pm static for maximum performance

The unedited version of the article was originally published on haydenjames.io and is published here with permission from its author.

I'll briefly explain how to configure PHP-FPM optimally to increase throughput, reduce latency, and use CPU and memory resources more reliably. By default, the pm (process manager) setting in PHP-FPM is set to dynamic, but if you're low on memory, it's better to set it to ondemand. Let's compare the 2 management options based on the documentation from php.net and see how my favorite differs from them, which is static pm for high traffic:

pm = dynamic — the number of child processes is managed dynamically based on the following directives: pm.max_children, pm.start_servers, pm.min_spare_servers, pm.max_spare_servers.
pm = ondemand — processes are created on demand (unlike dynamic creation, where pm.start_servers are launched during service startup).
pm = static — the number of child processes is fixed and specified by the parameter pm.max_children.

See the details in the full list of global directives in php-fpm.conf.

Similarities between the PHP-FPM process manager and CPU frequency governor

This may seem off-topic, but I'm going to relate this to the PHP-FPM configuration topic. Who hasn't experienced a CPU slowdown — on a laptop, virtual machine, or dedicated server? Remember CPU frequency scaling? These settings available for nix and Windows can improve system performance and response time if you change the CPU governor parameter from ondemand to performance*. This time, let's compare the descriptions and look at the similarities:

Governor = ondemand — dynamic CPU frequency scaling based on the current load. It quickly ramps up to the maximum frequency and then reduces it during increased idle periods.
Governor = conservative = dynamic scaling of frequency depending on the current load. It increases and decreases frequency more smoothly than ondemand.
Governor = performance — frequency is always at maximum.

See the details in the the full list of CPU frequency governor parameters.

Do you see the similarity? I wanted to show this comparison to convince you that it’s best to use pm static for PHP-FPM.

For the CPU governor, the parameter performance helps to safely increase performance because it is almost entirely dependent on the server's CPU limit. Besides this, of course, there are other factors such as temperature, battery charge (in laptops), and other side effects of constantly running the CPU at 100%. Configuring performance ensures the fastest operation of the CPU. For example, read about the force_turbo parameter in Raspberry Pi, which the RPi panel will use to control performance, where performance improvements will be more noticeable due to the low CPU clock speed.

Using pm static for maximum server performance

The PHP-FPM parameter pm static largely depends on the free memory on the server. If memory is low, it's better to choose ondemand or dynamic. On the other hand, if you have memory, you can avoid unnecessary costs of the PHP process manager by setting pm static to the server's maximum capacity. In other words, if everything is calculated well, you need to set pm.static to the maximum number of PHP-FPM processes that can run, without causing memory or cache shortages. But not so high as to overload the processors and accumulate a bunch of PHP-FPM operations waiting to be executed..

Configuring PHP-FPM: using pm static for maximum performance

In the screenshot above, the server is set to pm = static and pm.max_children = 100, which takes about 10 GB of the available 32. Pay attention to the highlighted columns; everything is clear from here. In this screenshot, there were about 200 active users (over 60 seconds) in Google Analytics. At this level, about 70% of the child PHP-FPM processes are still idle. This means that PHP-FPM is always set to the maximum available resources of the server regardless of current traffic. An idle process waits for traffic peaks and responds instantly. You don’t have to wait for pm to create child processes and then terminate them when the period of pm.process_idle_timeoutexpires. I set a very high value for pm.max_requests, because this is a working server without memory leaks in PHP. You can set pm.max_requests = 0 with static if you are fully confident in the existing and future PHP scripts. However, it's better to restart scripts over time. Set a high number of requests since we want to avoid unnecessary pm costs. For example, at least pm.max_requests = 1000 — depending on the number pm.max_children and the number of requests per second.

The screenshot shows the command Linux top, filtered by u (user) and PHP-FPM username. Only the first 50 or so processes are shown (not counted exactly), but essentially, top shows top statistics that fit in the terminal window. In this case, sorted by % CPU (%CPU). To view all 100 PHP-FPM processes, execute the command:

top -bn1 | grep php-fpm

When to use pm ondemand and dynamic

If using pm dynamic, similar errors occur:

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

Try changing this parameter, the error won't go away, as described in this post on Serverfault. In this case, the pm.min value was too low, and since web traffic varies greatly, with high peaks and deep troughs, it is hard to adequately set pm dynamic. Typically, pm is used ondemand, as advised in the same post. But this is even worse because ondemand it terminates idle processes to zero when there's either low or no traffic, and ultimately, you'll still struggle with costs during traffic changes. Unless you've set an extremely long timeout. In that case, it's better to use pm.static + a high number pm.max_requests.

PM dynamic and especially ondemand can be useful if you have multiple PHP-FPM pools. For instance, you're hosting several cPanel accounts or multiple websites in different pools. I have a server where, say, there are 100+ cPanel accounts and roughly 200 domains, and pm.static or even dynamic wouldn't save me. Here, only ondemand, as more than two-thirds of websites get little to no traffic, and with ondemand all child processes will drop out, saving us a lot of memory! Fortunately, the cPanel developers noticed this and set the default value ondemand. Previously, when the default value was dynamic, PHP-FPM was not suitable for heavily loaded shared servers. Many used suPHP, because pm dynamic consumed memory even with idle pools and cPanel accounts in PHP-FPM. Most likely, if the traffic is good, you wouldn't be hosting on a server with a large number of PHP-FPM pools (shared hosting).

Conclusion

If you are using PHP-FPM and your traffic is serious, process managers ondemand and dynamic for PHP-FPM will limit throughput due to inherent costs. Study your system and configure PHP-FPM processes according to the server's maximum capacity. First set pm.max_children depending on the maximum usage of pm dynamic or ondemand, then increase this value to a level where memory and CPU operate without excessive overload. You will notice that since pm static, with everything stored in memory, traffic peaks over time will cause fewer spikes for the CPU, and the average server and CPU load will level out. The average size of the PHP-FPM process depends on the web server and requires manual configuration, hence more automated process managers are dynamic and ondemand — more popular. I hope this article was helpful.

UPD A benchmark diagram has been added ab. If PHP-FPM processes are in memory, performance increases due to memory consumption, where they sit and wait. Find the optimal option for you.

Configuring PHP-FPM: using pm static for maximum performance

Source: habr.com

Buy reliable website hosting with DDoS protection, VPS VDS servers 🔥 Buy reliable website hosting with DDoS protection, VPS VDS servers | ProHoster