A site that is fine at ten in the morning and unresponsive at eight in the evening, with a database that looks idle and CPU that never climbs, is usually a pool that ran out of workers. PHP-FPM will tell you so, but the status page is off by default and nothing else in the stack reports it.
; /etc/php5/fpm/pool.d/www.conf
pm = dynamic
pm.max_children = 25
pm.start_servers = 5
pm.status_path = /fpm-status
# /etc/nginx/sites-available/app — keep it off the public internet
location = /fpm-status {
allow 127.0.0.1;
deny all;
fastcgi_pass unix:/var/run/php5-fpm.sock;
include fastcgi_params;
}
# curl -s localhost/fpm-status
# listen queue: 0
# max listen queue: 34
# active processes: 3
# max children reached: 6
active processes at the instant you looked is close to useless; the two counters that accumulate are what to read. max children reached above zero means the pool ran dry and requests waited for a worker, and max listen queue is the deepest the backlog ever got — so a non-zero value on a server that currently looks idle says it has already happened. The obvious response, raising pm.max_children, is only right if there is memory for it: each child holds 30 to 60MB once a framework is loaded, so 25 is already about a gigabyte, and a box that starts swapping is slower than one that queues. If the workers are blocked on a slow query rather than on CPU, adding more of them makes the database worse and the site no faster.