PHP-FPM is the FastCGI Process Manager for PHP. On Unix-like operating systems, including Linux and BSD distributions, PHP-FPM is enabled by installing the php5-fpm (Linux) or php56-fpm (FreeBSD 10.1) package.
The problem with PHP-FPM is that the default configuration and that promoted by numerous blogs chews up too much resources – RAM and CPU. The server that powers this blog suffers from the same fate. And that’s because I used the same tutorials available out there that promote inefficient PHP-FPM configuration options.
You’ll find those inefficient configuration options in the pool file or files under the /etc/php5/fpm/pool.d directory. Here, for example, is the set of inefficient configuration options on one of my Cloud servers (not the one that powers this site):
; Choose how the process manager will control the number of child processes. pm = dynamic pm.max_children = 75 pm.start_servers = 10 pm.min_spare_servers = 5 pm.max_spare_servers = 20 pm.max_requests = 500
That particular server is a DigitalOcean Droplet with 512 MB of RAM (that, by the way, is my referral link). It currently hosts one new website and when idle (no traffic whatsoever), only swapping saves it from freezing. The output of top shows the major consumers of RAM on the server.
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 13891 cont 20 0 396944 56596 33416 S 0.0 11.3 0:14.05 php5-fpm 13889 cont 20 0 396480 56316 32916 S 0.0 11.2 0:17.67 php5-fpm 13887 cont 20 0 624212 55088 32008 S 0.0 11.0 0:14.02 php5-fpm 13890 cont 20 0 396384 55032 32312 S 0.0 11.0 0:13.39 php5-fpm 13888 cont 20 0 397056 54972 31988 S 0.0 11.0 0:14.16 php5-fpm 14464 cont 20 0 397020 54696 31832 S 0.0 10.9 0:09.44 php5-fpm 13892 cont 20 0 396640 54704 31936 S 0.0 10.9 0:12.84 php5-fpm 13883 cont 20 0 396864 54692 31940 S 0.0 10.9 0:15.64 php5-fpm 13893 cont 20 0 396860 54628 32004 S 0.0 10.9 0:15.13 php5-fpm 13885 cont 20 0 396852 54412 32116 S 0.0 10.8 0:13.94 php5-fpm 13884 cont 20 0 395164 53916 32364 S 0.0 10.7 0:13.51 php5-fpm 13989 cont 20 0 394960 53548 32108 S 3.7 10.7 0:14.37 php5-fpm 2778 mysql 20 0 1359152 31704 1728 S 0.7 6.3 1:38.80 mysqld 13849 root 20 0 373832 1180 188 S 0.0 0.2 0:03.27 php5-fpm
That output shows 12 php5-fpm child processes (owner cont) spawned from one master process (owner root). And all 12 are just sitting there, doing nothing but consuming more than 10% of RAM each. And those child processes where mostly made possible by the pm = dynamic pool configuration option.
To be honest, the vast majority of Cloud server owners do not know what all those options mean or do. It’s mostly copying and pasting. And I will not pretend that I know what every option in every PHP files means or does. I, too, for the most part, was a victim of copying and pasting.
But I examine resource usage often and always wonder why my servers use up too much RAM and CPU. Here, for another example, is the output of free -mt on this particular server.
total used free shared buffers cached Mem: 490 480 9 31 6 79 -/+ buffers/cache: 393 96 Swap: 2047 491 1556 Total: 2538 971 1566
That’s almost 1 GB of memory usage (actual RAM plus swap) with no traffic. Sure, tuning the pm values would have made a difference, but only slightly; with pm = dynamic, there will still be child processes sitting idle waiting to be called into action.
I became aware of what an alternative configuration would do after reading an article titled A better way to run PHP-FPM. It was written about a year ago, so it’s kinda disappointing that I came across it while searching for a related topic just last night. If you run your own server and use PHP with PHP-FPM, you need to read that article.
After I read it, I changed the pm options in the pool configuration file to these:
; Choose how the process manager will control the number of child processes. pm = ondemand pm.max_children = 75 pm.process_idle_timeout = 10s pm.max_requests = 500
The major change was setting pm = ondemand instead of pm = dynamic. And the impact on resource usage was drastic. Here, for example, is the output of free -mt after reloading php5-fpm:
total used free shared buffers cached Mem: 490 196 293 28 9 70 -/+ buffers/cache: 116 373 Swap: 2047 452 1595 Total: 2538 649 1888
Compared to the output before, that’s more than a 50% drop in RAM usage. And the reason became obvious when I viewed top again:
2778 mysql 20 0 1359152 56708 3384 S 0.0 11.3 2:11.06 mysqld 26896 root 20 0 373828 19000 13532 S 0.0 3.8 0:02.42 php5-fpm 25818 root 20 0 64208 4148 1492 S 0.0 0.8 0:01.88 php5-fpm 25818 root 20 0 64208 4148 1492 S 0.0 0.8 0:01.88 php5-fpm 17385 root 20 0 64208 4068 1416 S 0.0 0.8 0:02.23 php5-fpm 1465 ossec 20 0 15592 2960 480 S 0.0 0.6 0:08.60 ossec-analysisd 1500 root 20 0 6312 2072 328 S 0.0 0.4 0:45.55 ossec-syscheckd 1 root 20 0 33444 1940 812 S 0.0 0.4 0:03.29 init
Did you notice that there are no child processes? What happened to them? That’s what setting pm = ondemand does. A child process is spawned only when needed. After it’s done its job, it remains idle for 10 seconds (pm.process_idle_timeout = 10s) and then dies.
So what I have is a simple modification to the default PHP-FPM settings that saved me more than 50% of RAM. Sure, the server hasn’t come under heavy traffic, but I think it can withstand a reasonably heavy traffic, considering that it only has 512 MB of RAM. And with Nginx microcaching configured, I think it will do very well. There are other aspects of PHP-FPM and Percona MySQL that I’ve not optimized yet, so stay tuned. This was just to pass on a little tip that I found useful.
please comment using your configuration for big server is it work.
I use it and it reduce ram the culpit is php7.2-fpm it eat all ram.
Haven’t done anything with php7.2-fpm, so I’m unable to help with its configuration.
The later part of the original tutorial of having each sub pool conf have it’s own master process I couldn’t get to work, and I followed the instructions exactly… anyone else able to get multiple PHP-FPM masters working?
What was the issue when you tried?
This config suggestion is stinky unless you have a very inactive website. Of course you will limit the memory usage in idle mode with this config, but if you have a highly active website, this config will drain CPU and IO uneccessarily as each PHP environment needs to be loaded to your memory before it actually – and where does the environment come from (a: disk) and who will handle it (a: cpu)? Leaving the process “open” and ready in your memory means that the PHP environment is preloaded in order to handle your visitors requests.
One very powerful option with PHP-FPM is the performance. But this performance depends on having processes preloaded. When switching to on demand you actually kills this idea, and could rather go with something else like the horrible slow suphp.
Suggestion. Do always keep atleast one process alive and swith pm to dynamic, as it would always fall back to “pm.start_servers” in idle periods. If you have memory limits do instead tweak the pm.max_children setting.
Hi, could you explain more about this ” .. Nginx microcaching configured ..” ?
What you fail to mention is that setting it to ondemand means longer response times as the PHP interpreter has to be started from scratch every time it’s needed. Consider leaving it at dynamic and rely on low values for the pm.max_children, pm.max_requests, and pm.process_idle_timeout settings to clear out memory usage.
This is useful, and yes it does work.
However, it is in some ways selling snake oil because you’re not making it any less memory-hungry; instead, you’re just preventing it from pre-allocating a maximum amount of memory, so it’s easier to get bitten on the arse when your server runs out of memory from a traffic spike. Even though PHP-FPM using up 600mb of memory, for instance, when it’s doing nothing, it allows you to work out how much memory everything else will need before the whole thing explodes.
Still, I think this is a good option for smaller sites that don’t get a huge amount of traffic, especially if you limit the max connections. So I will be using it, but people just need to be warned that it will still use the same amount of memory for the same amount of connections- but that sudden RAM spike may come as a shock.
Believe it or not, this tweak reduced my php5-fpm RAM usage by half. Good work Bro.
Thanks for this tweak, just tried it….. since i started using my own server this is the first time php-fpm is over using CPU
Thank you… this helped me a lot
amazing, it reduced RAM usage more than 50% to me 🙂
I have website with 100 to 200 Concurrent Users. 2GB RAM and 2 CPU Cores So what will be good config?
My Current is
pm = dynamic
pm.start_servers = 1
pm.max_children = 5
pm.min_spare_servers = 1
pm.max_spare_servers = 5
What can be good?
I think its important to point out that using less memory is a secondary issue to latency. If the box is spending time spinning up and down workers, that added latency is felt by the consumer.
These settings might work for a small website. I would not recommend it for high usage systems. From my testing, I get the the best performance using static workers as the expense of increased memory usage.
Less memory is not a secondary issue to latency if it’s a small site and other things have to run in the same space. Linode servers give you a gig for the $10/mo option, and you have to make it last…
Found you on google.
Here’s an output of server resources usage on DO:
24069 serverp+ 20 0 490016 99564 70984 S 2.7 9.8 2:35.12 php-fpm
24847 serverp+ 20 0 484932 93696 69316 S 2.7 9.2 1:53.23 php-fpm
24070 serverp+ 20 0 490668 101784 71420 S 2.2 10.0 2:08.30 php-fpm
24072 serverp+ 20 0 489028 100720 71996 S 2.2 9.9 2:06.21 php-fpm
23977 serverp+ 20 0 484444 97488 73492 S 1.8 9.6 2:12.38 php-fpm
23996 serverp+ 20 0 493456 107496 74340 S 1.8 10.6 2:22.87 php-fpm
24231 serverp+ 20 0 488612 100456 72248 S 1.8 9.9 2:07.68 php-fpm
25955 serverp+ 20 0 491272 97948 67044 S 1.8 9.6 1:12.52 php-fpm
serverpilot@server:~$ free -ht
total used free shared buffers cached
Mem: 994M 925M 68M 104M 88M 216M
-/+ buffers/cache: 620M 374M
Swap: 511M 35M 476M
Total: 1.5G 961M 544M
Gonna implement these changes straight away. Thank you.
Can’t edit my comment, but my server runs with DO 1gb package and free serverpilot.io package.
I made some custom config changes here and there, but I’m not a pro either.
In my case, I always have HIGH CPU USAGE and LOW RAM USAGE.
Is there any solution by tuning php5-fom? Or it is just a case of bad PHP/SQL scripts?
I think it’s mostly a case of bad scripts. No matter how much I tweak stuff, I’m still getting higher than expected RAM/CPU usage on the PHP side. I only managed to reduce RAM usage by MySQL simple by disabling performance metrics, though I’m not sure if it has any negative effect that I’m not seeing yet.
If you enable ondemand and timeout, what happens to opcache? Is the cache enable on a per-process basis, and if so does it get wiped when that process times out?
Didn’t look at the effect on opcache, but now that you brought it to my attention, I’ll have to take a look at it.
Opcache was not enabled, but after turning it on and tweaking it, RAM usage dropped even lower. Still trying to see hwo well I can tune it so all works well… Stay tuned!