Configure and Troubleshoot PHP-FPM
PHP-FPM usually comes with a particular setting that's set too low. This results in Gateway errors when you get too much traffic, often before the server even runs out of resources.
Let's see what that setting is, and how to rectify it.
What is PHP-FPM
PHP-FPM is an application gateway. It sits between Nginx (the web server) and your code base. Nginx will get an HTTP request, and is then configured to "proxy" the requests off to PHP-FPM using the fast CGI protocol.
When PHP-FPM receives a request from Nginx, it spins up a process (if one isn't already running), which runs an instance of your PHP application (call the index.php
file, or whatever, with all the needed data - $_SERVER
, $_GET
, $_POST
, body of the request, all that good stuff).
The Problem with PHP-FPM
The "problem" (if we want to call it that), is that PHP-FPM has a setting max_children
. This is the number of processes it's will to spin up. Since each child process handles a single HTTP request at a time, in serial, the only way to handle concurrent requests is by spinning up more processes. Eventually we can hit the max number of processes configured (max_children
), leading to Gateway errors (PHP-FPM refuses to handle the request, nor does it queue the request).
This can happen prematurely - before the server is actually out of resources (RAM, CPU). However it often coincides with your database being overloaded. In that case, requests may not respond in a timely manner, causing a pile-up of pending HTTP requests, eventually leading to max_children
being hit and the dreaded Gateway error.
This has always bugged me - it sometimes is self-limited (when max_children
is set too low) and other times is disguising a real issue (e.g. database overload).
Debugging PHP-FPM Issues
If you hit a Gateway error, the place to look to see what's happening is in the PHP-FPM log. This is often in /var/log
on your linux server. On Debian/Ubuntu servers, it's the /var/log/php8.2-fpm.log
(adjust that as needed for your PHP version).
You'll see errors saying "You're going to hit your max limit soon", and perhaps errors like "max_children reached". If you see those, you know you should probably increase your PHP-FPM's configured max_children
.
How to Configure PHP-FPM
To configure the correct number of max_children
, you need to know how many concurrent requests your server can handle.
I typically do a calculation like this:
floor(RAM available / RAM used per request)
If I have a 4gb RAM server, I'll perhaps allocate 3gb of that to the web server. If each PHP web request takes 100mb, that's 3072 / 50
or roughly 30 concurrent requests that I'll allow the server to handle. That means I can set max_children
to 30
!
The amount of free RAM goes down a lot when you're competing for resources within the server. If your database is on the same server, then you should allocate less RAM to PHP for serving web requests.
One Important Tip
The best tip I can give you for optimizing this is to get your database off of your web server, and into it's own dedicated server. This gives your database more resources that it likely needs, and frees up your web server to dedicate a LOT more resources to serving web requests.