Apache's Multi-Processing Modules (MPMs) fundamentally differ in their process handling approaches:
# Prefork MPM uses multiple child processes with one thread each
StartServers 5
MinSpareServers 5
MaxSpareServers 10
MaxClients 150
MaxRequestsPerChild 0
# Worker MPM uses multiple child processes with multiple threads each
StartServers 2
MaxClients 150
MinSpareThreads 25
MaxSpareThreads 75
ThreadsPerChild 25
MaxRequestsPerChild 0
Prefork MPM:
- Memory-intensive (each connection = separate process)
- More stable for PHP applications (no shared memory issues)
- Better isolation between requests
Worker MPM:
- Lower memory footprint (threads share memory space)
- Higher concurrent connection capacity
- Potential threading issues with non-thread-safe libraries
Prefork is preferable when:
- Running PHP with mod_php (not thread-safe)
- Using older Apache modules not optimized for threading
- Stability is more critical than raw performance
Worker shines when:
- Serving static content at high volumes
- Using event-driven architectures
- Running thread-safe applications (like Python WSGI)
Optimizing Prefork for memory-heavy applications:
<IfModule mpm_prefork_module>
StartServers 8
MinSpareServers 5
MaxSpareServers 20
ServerLimit 256
MaxClients 256
MaxRequestsPerChild 4000
</IfModule>
Tuning Worker for high-throughput scenarios:
<IfModule mpm_worker_module>
StartServers 4
MaxClients 300
MinSpareThreads 25
MaxSpareThreads 75
ThreadsPerChild 25
MaxRequestsPerChild 0
</IfModule>
When switching between MPMs, always:
- Back up current configuration
- Verify module dependencies (e.g., php-zts for threaded PHP)
- Test with production-like traffic patterns
- Monitor memory usage during transition
Worker MPM problems often manifest as:
- Segmentation faults in non-thread-safe libraries
- Memory leaks in long-running threads
- Race conditions in shared resources
Prefork issues typically include:
- High RAM consumption under load
- Slower response times during traffic spikes
- Process creation overhead
The fundamental distinction lies in their process/thread handling:
- Prefork MPM: Uses multiple child processes with one thread each
- Worker MPM: Uses multiple child processes with multiple threads each
# Sample configuration differences
# Prefork MPM
<IfModule mpm_prefork_module>
StartServers 5
MinSpareServers 5
MaxSpareServers 10
MaxClients 150
MaxRequestsPerChild 0
</IfModule>
# Worker MPM
<IfModule mpm_worker_module>
StartServers 2
MinSpareThreads 25
MaxSpareThreads 75
ThreadLimit 64
ThreadsPerChild 25
MaxClients 150
MaxRequestsPerChild 0
</IfModule>
Benchmark data shows:
Metric | Prefork | Worker |
---|---|---|
Memory Usage | Higher (20-30MB per process) | Lower (shared memory between threads) |
Concurrent Connections | Limited by RAM | Handles more efficiently |
Static Content | Faster (~5% benchmarks) | Slower due to threading overhead |
Choose Prefork when:
- Running PHP with mod_php (not thread-safe)
- Using non-thread-safe libraries
- Memory isn't a constraint
Choose Worker when:
- Using FastCGI (PHP-FPM)
- Need better scaling for many concurrent connections
- Running on memory-constrained servers
Switching from Prefork to Worker:
# Stop Apache
sudo service apache2 stop
# Install Worker MPM
sudo apt-get install apache2-mpm-worker
# Verify active MPM
apache2ctl -V | grep -i mpm
# Adjust thread settings in /etc/apache2/mods-available/mpm_worker.conf
ThreadsPerChild 25
MaxRequestWorkers 150
# Restart
sudo service apache2 start
Prefork success case: Legacy application using mod_php with custom extensions that aren't thread-safe. Memory usage stayed under 4GB on a dedicated server.
Worker success case: High-traffic WordPress site using PHP-FPM, handling 2,000+ concurrent users on a 8GB VPS with optimized thread settings.
Common Worker MPM issues and solutions:
# Debug threading issues
strace -f -p $(pgrep apache2)
# Check for memory leaks
watch -n 1 "ps -ylC apache2 --sort:rss"
# Monitor thread activity
apachetop -f /var/log/apache2/access.log
For Worker MPM tuning:
# Calculate optimal ThreadsPerChild
Total RAM - OS overhead = Available RAM
Available RAM / Process size = MaxClients
MaxClients / ThreadsPerChild = ServerLimit
Example for 8GB server:
8GB - 1GB = 7GB available
7GB / 20MB per process = 350 MaxClients
350 / 25 threads = 14 ServerLimit