Where's my memory?! Nginx + PHP-FPM front end webserver slows to a crawl

In case anyone else suffers this.

We have just experienced the same issue. A memory leak in php5-fpm. The RAM is used up with every page request and eventually maxed out. Then the CPU goes into overdrive with the KSWAP process running the swap disk.

the only thing that fixed, although not the ideal setup was to change our www.conf pool file

pm = dynamic

to

pm = ondemand

memory now seems stable.


Here's two things to check:

  1. Most likely you have a memory leak. pm.max_requests will kill/restart the php-fpm child process after it's handled this many requests. Since it takes about a day for your box to slow to a crawl, try setting this to a number to causes each child process to be respawned every 20 minutes or so. So if you get 200 requests a minute, and you have 5 processes, set pm.max_requests to 800. If you don't want to do the math, a setting between 500-1000 might work. Play around with it to find a balance between wasting time respawning processes vs wasting RAM on the memory leak.

  2. Php-FPM may be creating too many child processes when a traffic spike happens, causing it to run out of RAM and start swapping to disk. Decide how much total RAM to allocate to php-fpm, then divide that by how much memory each child process takes. For Wordpress and PHP-based forums, I often see each child process requiring 30-45MB. If you're only using one php-fpm pool, set pm.max_children to that number.

If you've only got a single php-fpm pool, you'll see a speed boost from setting pm.type = static.

If you've got multiple php-fpm pools, possibly because you're hosting multiple apps and wish to isolate them for security reasons, you'll want to set pm.type = dynamic and play around with start_servers, min_spare_servers, and max_spare_servers. Just be sure the cumulative max_children across all pools isn't more than your box can handle.

If you've got a high number of low-traffic apps, each with its own php-fpm pool, it's better to set pm.type=ondemand so that each app is only taking up resources when it's actually being used. Also set pm.max_children reasonably low so that no one app can completely overwhelm the box.