Debugging PHP-FPM Child Processes Exiting After Hundreds of Seconds: Causes and Solutions


2 views

The log entries showing child processes exiting after exactly 200-300 seconds indicate a systematic behavior rather than random performance issues. The key observations:

[03-Sep-2013 09:25:23] NOTICE: [pool www] child 23999 exited with code 0 after 321.832329 seconds from start
[03-Sep-2013 09:25:41] NOTICE: [pool www] child 24032 exited with code 0 after 259.247887 seconds from start

The current FPM pool configuration shows several parameters that might contribute to this behavior:

pm = dynamic
pm.max_children = 50
pm.start_servers = 20
pm.min_spare_servers = 5
pm.max_spare_servers = 35
pm.max_requests = 100

The most likely explanations for this pattern include:

  • Process reaching pm.max_requests limit (though your config shows 100)
  • PHP script execution timeouts (check max_execution_time in php.ini)
  • Idle process cleanup (especially with process_idle_timeout setting)
  • System-level process killers (OOM killer, systemd watchdogs)

To identify the exact cause, run these diagnostic commands while monitoring the logs:

# Check PHP-FPM process status
sudo systemctl status php-fpm

# Monitor process lifecycle
watch -n 1 'ps aux | grep php-fpm | grep -v grep'

# Check system logs for OOM events
sudo grep -i kill /var/log/syslog

Adjust these parameters in your pool configuration:

; Recommended adjustments
pm.max_requests = 500  ; Increase if processes are recycling too quickly
request_terminate_timeout = 300s ; Explicit timeout setting
request_slowlog_timeout = 10s    ; Log slow requests
process_idle_timeout = 10s       ; If using ondemand pm

Consider these additional optimizations:

; Enable status page for monitoring
pm.status_path = /status

; Enable slow log for troubleshooting
slowlog = /var/log/php-fpm/slow.log

; Adjust process manager settings
pm.max_spare_servers = 20 ; Reduce if experiencing frequent recycling
pm.process_idle_timeout = 30s ; For dynamic/ondemand PM

For deeper analysis, implement this monitoring script:

#!/bin/bash
while true; do
    DATE=$(date +%Y-%m-%d\ %H:%M:%S)
    PROCESS_COUNT=$(pgrep -c php-fpm)
    MEM_USAGE=$(ps -o rss= -p $(pgrep php-fpm) | awk '{sum+=$1} END {print sum/1024}')
    echo "[$DATE] Processes: $PROCESS_COUNT | Memory: ${MEM_USAGE}MB"
    sleep 5
done

When examining PHP-FPM logs with entries like:

[03-Sep-2013 09:25:23] NOTICE: [pool www] child 23999 exited with code 0 after 321.832329 seconds from start

The "seconds from start" value represents the total lifetime of a PHP-FPM child process before it terminated gracefully (exit code 0). This indicates process recycling behavior.

The provided configuration shows:

pm = dynamic
pm.max_children = 50
pm.start_servers = 20
pm.min_spare_servers = 5
pm.max_spare_servers = 35
pm.max_requests = 100

Key factors affecting process lifetime:

  • pm.max_requests: Process terminates after serving 100 requests
  • Process manager may recycle idle workers based on spare server settings

Several scenarios can cause this behavior:

// Example of problematic PHP code that might cause long process lifetimes
function heavy_processing() {
    // Memory-intensive operation
    $large_array = array_fill(0, 1000000, 'data');
    
    // Long-running operation
    for ($i = 0; $i < 1000000; $i++) {
        // Complex calculations
    }
}

Adjust PHP-FPM settings to control process lifetime:

; Recommended adjustments for production
pm.max_requests = 500  ; Balance between stability and performance
pm.process_idle_timeout = 60s  ; Kill idle workers after 60 seconds
request_terminate_timeout = 120s  ; Maximum execution time

Use these commands to monitor PHP-FPM:

# Show process status
sudo systemctl status php-fpm

# Real-time monitoring
sudo watch -n 1 "ps aux | grep php-fpm"

# Detailed process information
sudo strace -p <php-fpm-pid>

Consider these additional optimizations:

; php.ini adjustments
opcache.enable=1
opcache.memory_consumption=128
opcache.max_accelerated_files=4000
realpath_cache_size=4096K
realpath_cache_ttl=600

For Nginx integration:

location ~ \.php$ {
    fastcgi_pass unix:/var/run/php-fpm.sock;
    fastcgi_read_timeout 60;
    fastcgi_send_timeout 60;
    fastcgi_connect_timeout 60;
}