In a PHP-FPM pool, how do pm = static, pm = dynamic and pm = ondemand differ, and when would you choose each?
answer
- fixed vs elastic vs zero at start
- pm.max_children caps all three
- spare servers only for dynamic
- process_idle_timeout 10s for ondemand
- first request forks under ondemand
basics
~20 sstatic keeps exactly pm.max_children workers alive; dynamic starts pm.start_servers and keeps idle workers between the min and max spare counts; ondemand starts none and forks per demand, killing workers idle past pm.process_idle_timeout (10s). pm.max_children caps all three.
solid answer
~40 sThe `pm` directive picks how the FPM master manages a pool's worker processes. `static` forks exactly `pm.max_children` workers at start and keeps them: no spawning latency, fully predictable memory, suited to a dedicated server with steady traffic. `dynamic` forks `pm.start_servers` workers, then once a second adds workers when idle ones drop below `pm.min_spare_servers` and kills one when idle ones exceed `pm.max_spare_servers`, never above `pm.max_children`: the usual general-purpose choice. `ondemand` starts with no workers, forks one when a connection arrives and none is idle, and kills workers idle longer than `pm.process_idle_timeout` (default 10s): it saves memory for rarely used pools, such as many small sites on one host, at the price of a fork before the first request after a quiet spell.
code
ini · 13 lines; /etc/php/8.5/fpm/pool.d/app.conf (excerpt)
[app]
pm = dynamic
pm.max_children = 40
pm.start_servers = 10
pm.min_spare_servers = 5
pm.max_spare_servers = 15
; a rarely used admin pool on the same host
[admin]
pm = ondemand
pm.max_children = 4
pm.process_idle_timeout = 30sgo deeper
Recall the three pm values, that each worker handles one request at a time, and that pm.max_children is the ceiling for all of them.
Explain how dynamic uses start_servers and the spare counts, how ondemand forks and reaps with process_idle_timeout, and what each costs in memory and latency.
Pick the style from the host and traffic: static for a dedicated steady server, dynamic for variable load, ondemand for many idle pools, all bounded by RAM.
Frame the choice as a trade between committed memory and burst latency across all pools on a host, not a per-pool preference.
## What the process manager does **PHP-FPM** (FastCGI Process Manager) runs PHP for web servers as a **master process** plus a set of **worker processes** (children) per **pool**. Each worker handles **one request at a time**, so the number of workers is the number of PHP requests the pool can run concurrently. The pool directive `pm` chooses how the master decides how many workers exist. It is mandatory, and the value is one of three styles. | | `static` | `dynamic` | `ondemand` | |---|---|---|---| | Workers at start | `pm.max_children` | `pm.start_servers` | 0 | | Grows with load | No (already at the cap) | Yes, towards `pm.max_children` | Yes, one fork per waiting connection | | Shrinks when quiet | No | To `pm.max_spare_servers` idle | To 0, after `pm.process_idle_timeout` | | Memory use | Constant, highest | Follows load, with a floor | Lowest when idle | | Latency at a burst | None | Short, while spawning | A fork before each new worker's first request | `pm.max_children` applies to all three: it is the pool's hard ceiling on live workers, and therefore on simultaneous PHP requests. ## pm = static The master forks exactly `pm.max_children` workers at startup and replaces any that exit. There is no spawning or killing logic. - **Pros:** zero spawn latency, and memory is predictable because it is always at its maximum — you find out on day one whether the server can hold it. - **Cons:** memory is committed even at 3 a.m.; on a shared host, idle pools still occupy RAM. - **Fits:** a dedicated application server with steady traffic, sized with care. ## pm = dynamic The master forks `pm.start_servers` workers at startup (if it is not set, FPM computes `min_spare + (max_spare - min_spare) / 2` and logs a notice). About **once a second** it counts idle workers: 1. More idle than `pm.max_spare_servers` → it kills one idle worker. 2. Fewer idle than `pm.min_spare_servers` → it forks more, starting with one and doubling each second the shortage persists, up to `pm.max_spawn_rate` (default 32), and never past `pm.max_children`. - **Pros:** tracks daily traffic while keeping a few warm, idle workers ready for a burst. - **Cons:** more knobs, and a sudden spike still waits for spawning when the spare pool is too small. - **Fits:** most single-application servers; it is the sample `www.conf` default (`pm = dynamic` with `max_children = 5`, `start_servers = 2`, `min_spare_servers = 1`, `max_spare_servers = 3` — values meant for a very small machine). ## pm = ondemand No workers exist at startup. When a connection arrives and no idle worker is available, the master forks one, up to `pm.max_children`. Once a second it checks the idle workers and kills one whose last request finished more than `pm.process_idle_timeout` ago (default `10s`; units `s`, `m`, `h`, `d`). - **Pros:** an unused pool costs no workers at all, which lets one host carry many pools. - **Cons:** the first request after an idle period waits for a fork; bursts pay it repeatedly; per-process state such as persistent database connections keeps being thrown away. - **Fits:** many low-traffic sites or admin tools on one host, development boxes, pools that serve a cron-style trickle. ## Choosing in practice - Start from **memory**: `pm.max_children` must fit the RAM left for PHP whatever style you choose. - Choose **static** when the server exists for this one pool and traffic is steady or latency-sensitive. - Choose **dynamic** when traffic varies and you want warm spare workers without holding the peak all day. - Choose **ondemand** when many pools share a host and most are idle most of the time. - Remember that a style changes *when* memory is used, not *how much* each worker uses; a pool that is too large for the machine swaps or gets killed under peak load in every mode. Changing `pm` or any `pm.*` value needs a reload of PHP-FPM, which replaces the workers.
- Does pm = static make PHP keep application state between requests?No. Static only fixes how many worker processes exist. Each worker still runs PHP's request lifecycle, so variables and objects are freed at the end of every request; only process-level things such as OPcache's shared memory or persistent connections outlive a request, and they do so under every `pm` style.
- Why can an ondemand pool feel slow right after a quiet period?Under `pm = ondemand` idle workers are killed after `pm.process_idle_timeout` (10s by default), so after a quiet spell the pool may have none. The next request makes the master fork a worker before it can be served, and a burst makes it fork several, one per waiting connection, up to `pm.max_children`.
saying these in an interview costs you the question
- pm.max_children only applies to static pools
- ondemand creates pm.start_servers workers at startup
- A dynamic pool can grow past pm.max_children during a spike
- Choosing static makes each worker use less memory
- One FPM worker serves many requests concurrently