Apache Prefork MPM Process Sprawl: Diagnosing and Fixing Uncontrolled httpd Process Growth on Low-Memory WordPress Hosting


2 views

When running WordPress on an EC2 micro instance with limited RAM, you'll often encounter Apache's prefork MPM spawning hundreds of processes that eventually crash your server. These processes frequently get stuck in uninterruptible sleep (D state), indicating I/O wait issues. Let's examine a proper configuration for memory-constrained environments.

The default Apache configuration assumes significant available memory. For a 1GB RAM system running both Apache and MySQL, we need aggressive tuning:

# Recommended settings for 1GB RAM system

    StartServers            2
    MinSpareServers         2
    MaxSpareServers         5
    MaxRequestWorkers       30
    MaxConnectionsPerChild  1000
    KeepAlive               On
    KeepAliveTimeout        2
    MaxKeepAliveRequests    100

WordPress's dynamic nature exacerbates process growth. Implement these adjustments:

# In wp-config.php
define('WP_MEMORY_LIMIT', '64M');
define('WP_MAX_MEMORY_LIMIT', '128M');

# In .htaccess

    RewriteEngine On
    RewriteBase /
    RewriteRule ^index\.php$ - [L]
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteRule . /index.php [L]

When processes get stuck in D state, investigate with:

# Check for disk I/O bottlenecks
iotop -oPa
vmstat 1 10

# Identify blocking processes
cat /proc/[pid]/stack
strace -p [pid]

Combine these settings with PHP-FPM tuning for better resource management:

# In php-fpm.conf
pm = dynamic
pm.max_children = 10
pm.start_servers = 2
pm.min_spare_servers = 1
pm.max_spare_servers = 4
pm.max_requests = 500

# In httpd.conf
Timeout 60
HostnameLookups Off
EnableSendfile Off

For extremely resource-constrained systems, consider:

  • Switching to lighttpd or nginx with PHP-FPM
  • Implementing a reverse proxy cache like Varnish
  • Using a static site generator for low-traffic blogs

When monitoring top or htop, seeing dozens of Apache processes stuck in D-state (uninterruptible sleep) typically indicates blocked I/O operations. On WordPress setups, this often traces back to:

# Common culprits in error logs
tail -f /var/log/httpd/error_log | grep -i "D state"
# Sample output showing blocked processes
[proxy_fcgi:error] (70007)The timeout specified has expired: [client x.x.x.x] AH01075: Error dispatching request to : (interrupted syscall)

Your EC2 micro instance needs aggressive process limits. The commented directives in your config should be activated with these values:

StartServers 2
MinSpareServers 2 
MaxSpareServers 5
MaxRequestWorkers 20  # Lower than your RAM allows
ServerLimit 20
MaxConnectionsPerChild 500  # Kills processes after 500 requests
Timeout 30  # Default 300 is too high
KeepAliveTimeout 2

Add these to wp-config.php to reduce PHP process overhead:

define('WP_MEMORY_LIMIT', '64M');
define('WP_MAX_MEMORY_LIMIT', '128M');
define('WP_CACHE', true); // Enable caching

Use this bash snippet to identify stuck processes:

while true; do 
  date; 
  ps auxf | grep '[h]ttpd' | wc -l; 
  ps auxf | grep '[D] state' | awk '{print $2}' | xargs -r lsof -p; 
  sleep 5; 
done

Consider switching to event MPM if your Apache version supports it:

# In httpd.conf
LoadModule mpm_event_module modules/mod_mpm_event.so

    StartServers 2
    MinSpareThreads 20
    MaxSpareThreads 40 
    ThreadsPerChild 25
    MaxRequestWorkers 100
    MaxConnectionsPerChild 1000