Sizing pm.max_children

Sizing pm.max_children from Memory and Latency

pm.max_children is how many requests the pool runs at once; the next one waits in the socket queue. Size it twice and take the smaller answer. Memory first: measure workers after they have served real pages, and use PSS, which splits shared pages (OPcache, the binary) between processes, not RSS, which counts them in full for every worker:

Output of 247
$ for p in $(pgrep -f 'php-fpm: pool shop'); do
>   pss=$(awk '/^Pss:/{print $2}' /proc/$p/smaps_rollup)
>   echo "pid $p rss $(ps -o rss= -p $p) kB  pss $pss kB"
> done
pid 249847 rss 42972 kB  pss 11037 kB
pid 249848 rss 42248 kB  pss 10313 kB

With 2 GB for PHP, RSS suggests 48 workers and PSS 186, but one heavy report can take a worker to its memory_limit, so budget (RAM for PHP) / (PSS + typical request peak). Latency second. By Little's law, throughput = workers / time per request, so a page that waits 50 ms on MySQL 524 (usleep(50_000) here) serves 20 requests per second per worker. With 64 clients:

An I/O-bound 50 ms page under 64 clients (8 and 32 workers fell in line)
pm.max_children Requests/s p50 p99
4 71 810 ms 1.53 s
16 307 203 ms 315 ms
64 1,237 51 ms 53 ms

Waiting workers use no CPU, so throughput tracked the worker count. CPU-bound pages top out at the core count instead. Raise max_children until max children reached (FPM Timeouts and Status) stops rising.