Apache Worker models determine how the Apache HTTP Server processes requests in parallel and uses resources - specifically via the MPMs Prefork, Worker and Event. In this article, I will show how the three models differ technically, what effects they have on Performance and scaling and which setup is convincing in real scenarios.
Key points
The following key points will give you a quick overview of the most important differences and decisions surrounding the three MPMs; I will then go into more detail and provide Practical knowledge.
- PreforkProcess-based, high isolation, high RAM requirement.
- WorkerThreads per process, good scaling, sensitive to keep-alive.
- eventEvent loop decouples connection and request, very efficient.
- TuningStartServers, ThreadsPerChild, MaxRequestWorkers specifically.
- HTTP/2: Works sensibly with Worker and Event, not with Prefork.
What MPMs control in Apache
I use the Multi-Processing Modules (MPMs) to determine whether Apache uses processes or threads per request and how the server Parallelism provides. Prefork creates many processes with one thread each, Worker creates a few processes with many threads, Event builds on Worker and decouples connections from the actual processing. This choice has a direct effect on memory, CPU utilization and latencies. I therefore always take sessions, keep-alive, protocols such as HTTP/2 and the modules used into account. If you ignore MPMs, you are giving away measurable Performance and risks bottlenecks.
Prefork: process insulation and compatibility
Prefork focuses on individual processes per request and thus delivers strong Insulation. If one process crashes, others remain unaffected - this increases the fault tolerance for unclean code or old extensions. The price: Each process brings its own overhead, so the RAM consumption per parallel connection increases. With 100 simultaneous requests, 100 processes are created, which I only find acceptable with a low to medium load. I mainly use Prefork when I need to use modules without thread safety or when legacy CGI scripts require high Separation require.
Worker: Threads and high parallelism
In the worker model, individual processes execute multiple threads, which reduces the memory requirement per request. sinks. This architecture allows significantly more concurrency on the same hardware and is suitable for high access numbers. However, long keep-alive connections can tie up threads and thus block capacity. In clean, thread-safe setups - for example with PHP-FPM - I achieve very good RPS values with Worker with moderate RAM usage. I use Worker when I need an efficient, thread-based Scaling and keep-alive is sensibly controlled.
Event: Non-blocking keep-alive strategy
Event is based on the worker model, but eliminates the keep-alive weakness with a Event loop. A thread only processes the actual request; a separate mechanism is responsible for maintaining the connection. This leaves threads free and the machine processes more simultaneous sessions with low latency. Event is particularly impressive for HTTP/2 connections, as multiplexing and long connections run without wasting threads. In modern setups, I start with Event as Standard base and only adapt if modules or legacy requirements conflict with this.
Tabular comparison of the MPMs
The following table summarizes the key differences so that I can see at a glance assess which model suits the load and module situation. Before switching, I always check the thread safety of all modules and the expected connection duration. I then assign MaxRequestWorkers, ThreadsPerChild and other limits to the available resources. The table helps me to make initial assumptions, but does not replace load tests under real conditions. Especially for events, a measurement with long keep-alive phases and HTTP/2 is worthwhile in order to determine the Advantages visible.
| MPM | Processes/threads | RAM consumption | Reliability | Typical use |
|---|---|---|---|---|
| Prefork | 1 thread per process | High | High (good insulation) | Low/medium load, modules without thread safety, classic CGI |
| Worker | Multiple threads per process | Medium | Medium | High load with thread-safe stack, e.g. PHP-FPM |
| event | Threads + event loop | Low | High | Very high load, long connections, HTTP/2 |
I read from the table: Prefork scores with shielding, Worker for efficiency and Event for maximum utilization with simultaneous connections. I use Event for new projects, provided there are no incompatibilities. Prefork can still be useful for stable legacy stacks. Those who are just migrating often achieve significant progress with Worker. In the end, the choice remains a Weighing up from modules, traffic profile and hardware.
Measuring performance: Benchmarks and metrics
Without measurement, every MPM decision remains a Conjecture. In comparative tests, Worker delivers up to around 50 % more requests per second than Prefork under high load; Event also increases, especially during long keep-alive phases. There are clear differences in terms of memory: with around 1000 simultaneous connections, Prefork setups roughly end up with 2-4 GB RAM, Worker with 1-2 GB, Event usually under 1 GB. I not only check RPS, but also time to first byte, 95th/99th percentiles and error rates. The load profile of the application is crucial, because short, fast requests behave differently to streaming or WebSockets.
Tuning parameters explained: StartServers, ThreadsPerChild, MaxRequestWorkers
I start with conservative values and scale up until I achieve the desired Utilization meet. For Prefork, I set MaxRequestWorkers based on the available memory and the process size; for Worker and Event, I plan ThreadsPerChild and the number of processes so that ThreadsPerChild × Processes = MaxRequestWorkers. I make sure there is enough buffer so that load peaks do not lead to 503 errors. A clean StartServers value prevents unnecessary forks under cold start conditions. If you want to delve deeper, you can find background information on the Thread pool optimization, which can be transferred directly to Apache setups.
# Example: Event (Debian/Ubuntu)
a2dismod mpm_prefork mpm_worker
a2enmod mpm_event
systemctl restart apache2
# Utilize worker threading sensibly
# /etc/apache2/mods-available/mpm_event.conf
ServerLimit 16
StartServers 4
ThreadsPerChild 50
MaxRequestWorkers 800
MaxConnectionsPerChild 0
I then check the effect with benchmarks and check whether the CPU is sufficiently work without drowning in context switches. At the same time, I monitor RAM trends, swap activity and open file descriptors. If queues become visibly full, I carefully increase MaxRequestWorkers or reduce keep-alive times. If everything runs smoothly, I back up the configuration and document the Limit values.
Keep-Alive, HTTP/2 and Thread-Contention
Keep-Alive reduces TCP handshakes, but can bind threads - especially with the Worker MPM, which places connections directly on threads. Event solves precisely this effect by establishing the connection via an event loop. unwinds and threads only for active work. For HTTP/2, I therefore use workers or events, because otherwise multiplexing is slowed down. In practice, I like to monitor the queue length and check whether „thread retention“ is noticeable. I have tips on this in the article on Thread-Contention which I use for more in-depth analyses.
I also customize KeepAliveTimeout to the application so that inactive connections do not affect the Capacity do not bind. The ideal setting differs between APIs, classic LAMP pages and HTTP/2-based frontends with many assets. If there is a lot of idle time, I lower the timeout and increase MaxRequestWorkers slightly. If I expect a lot of short requests, I keep Keep-Alive moderate to save TCP overhead. If waiting times occur, I switch to Event or set up additional Instances to.
Practical scenarios and choosing the right model
For legacy apps with risky modules, I use Prefork and benefit from high shielding. With modern PHP-FPM architecture with many simultaneous connections, Worker already delivers very good results. Event further reduces latency and scales cleanly with long sessions, WebSockets and HTTP/2. On shared hostings or with unclear code status, I am safer with Prefork, while I usually prefer Event on VPS and dedicated hardware. If you're considering alternatives to Apache, you can find more information in the compact Web server comparison additional decision-making aids for Nginx and LiteSpeed, which I check depending on the situation.
Events pay off during traffic peaks with burst character, as threads do not run idle. persist. For CPU-heavy apps, I limit MaxRequestWorkers so as not to overbook the machine. If RAM is scarce, I banish Prefork and prioritize Worker/Event. In multi-tenant environments, containers or cgroups separate the services so that workers/events can unfold their potential. In the end, the measurement confirms which model in your own stack has the lowest Latency supplies.
Configuration on Ubuntu/Debian in practice
I activate and deactivate MPMs specifically, test the effect and keep rollback options ready. Under Debian/Ubuntu, I use the known commands and then check the status output. I then tweak the mpm_*.conf files and log versioned changes. Before the go-live, I simulate load peaks in order to detect deadlocks or memory bottlenecks early on. Only when the error counters and percentiles are correct do I take over the Values in production.
# Switch on prefork
a2dismod mpm_worker mpm_event
a2enmod mpm_prefork
systemctl restart apache2
Enable # Worker
a2dismod mpm_prefork mpm_event
a2enmod mpm_worker
systemctl restart apache2
# Enable event
a2dismod mpm_prefork mpm_worker
a2enmod mpm_event
systemctl restart apache2
# Monitoring
apachectl status
htop
journalctl -u apache2 -f
I monitor error logs in parallel to quickly identify thread security issues. Find. For HTTP/2, I check whether the protocol is negotiated correctly and the TLS configuration fits. If there are noticeable latencies, I compare prefork/worker/event alternately and keep an eye on RAM development. If the balance is not right, I adjust KeepAlive, the number of threads and limits. This allows me to achieve reliable response times without Overbooking.
Thread safety and module compatibility
The most important preliminary check before switching from Prefork to Worker/Event is the Thread safety of all modules. Classic: mod_php is historically closely linked to Prefork; in modern stacks I use PHP-FPM via proxy_fcgi instead, so that Apache itself can scale thread-based. Filter and auth modules, self-written modules or integrations (e.g. image processing) must also be considered „thread safe“. I check the loaded modules, evaluate release notes and carry out a crash and race condition test under load. The following applies to HTTP/2: With Prefork, it is practically not an option - workers/events are the Prerequisite, so that multiplexing and prioritization work.
Capacity planning: realistically calculating the storage budget
I do not dimension MaxRequestWorkers „by feel“, but on the basis of measurable process and thread sizes. Procedure:
- Run test load, then measure the resident set size (RSS) per Apache process.
- For workers/events, take into account the additional overhead per thread.
- Schedule buffers for kernel, page cache, TLS session cache, log buffer and upstreams.
# Estimate process size (example)
ps -ylC apache2 --sort:rss | awk '{sum+=$8} END {print "RSS (kB) total:",sum}'
ps -L -p -o pid,tid,psr,stat,rss,cmd
pmap -x | tail -n 1 # Total sum per process
Calculation example: An event process occupies 25 MB, threads require an average of 1 MB. With 16 processes and 50 threads, this roughly results in 16 × 25 MB + 800 × 1 MB ≈ 1.2 GB. I set MaxRequestWorkers = 800, leave 30-40 % RAM free and scale up after measurement. If you use Prefork, simply calculate „Process size × MaxRequestWorkers“ and remain conservative.
Operating system limits, backlogs and descriptors
Apache can only be as fast as the underlying platform. I check three points regularly:
- File descriptors: A thread/process opens sockets, files and pipes. I increase LimitNOFILE via systemd and verify the transfer.
- Accept backlog: For connection bursts, I enlarge ListenBacklog and provide suitable kernel backlogs.
- Socket/timeout tuning: Set RequestReadTimeout, Timeout and KeepAliveTimeout specifically to mitigate „slow clients“.
# systemd override
systemctl edit apache2
[Service]
LimitNOFILE=65536
# Kernel parameters (temporary)
sysctl -w net.core.somaxconn=4096
# Apache: Backlog and timeouts
Listen 0.0.0.0:443
ListenBacklog 1024
Timeout 60
RequestReadTimeout header=10-20,MinRate=1 body=10,MinRate=500
KeepAliveTimeout 5
MaxKeepAliveRequests 100
I prefer to keep timeouts a little stricter and monitor the error rates. If legitimate long uploads are expected, I adjust values specifically per VirtualHost on.
Graceful reloads, deployments and containers
In operation, I prefer reloads without breaking existing connections. apachectl -k graceful or systemctl reload reloads configurations, but lets running requests expire cleanly - for prefork per process, for worker/event per thread. In container environments, I plan smaller ServerLimit/ThreadsPerChild so that pods can be start and terminate. I pay attention to cgroup quotas: If CPU time or RAM are capped, MaxRequestWorkers must be correspondingly lower, otherwise the latency shifts to the 95th/99th percentile.
Correctly dimension proxy/upstream setups
Many Apache instances terminate TLS and then proxy to PHP-FPM, app servers or microservices. I link frontend capacity (MaxRequestWorkers) with the upstream pools: For PHP-FPM, pm.max_children and pm.max_requests are the hard upper limit. I keep the ratio so that Apache does not accept significantly more concurrent requests than upstreams can handle - otherwise queues and Timeouts. I set timeouts explicitly for proxy_fcgi and proxy_http and check whether keep-alive is useful for upstream or only ties up resources.
Monitoring and diagnostics with the scoreboard
The mod_status output reveals how well the selected MPM is working. I pay attention to the proportions of the following statuses: Reading (incoming headers), Sending (answer is transmitted), Keepalive (open connection without work), Waiting (free). High proportions of Keepalive in Worker indicate bound threads - Event eliminates exactly that. Permanent Reading may be due to slow clients or incorrect RequestReadTimeout-values. Many Closing/Logging-States under peak load indicate thread pools that are too small or I/O bottlenecks in logging.
Safety and robustness: Slowloris & Co.
The combination of Event-MPM, tight KeepAliveTimeouts and RequestReadTimeout helps against „Slowloris“-type attack patterns. Although Prefork protects against module crashes through process isolation, it remains susceptible to RAMExhaustion with many connections. I combine limits at web server level with upstream WAF/rate limits so that Apache is not confronted with millions of half-open sessions in the first place. I evaluate logs to 95th/99th percentiles because attacks inflate the distribution tails.
Distribution defaults and typical stumbling blocks
Event is now standard on many Debian/Ubuntu installations. Nevertheless, default values are often conservative (e.g. ThreadsPerChild 25-50). I only increase these after measurement. Frequent errors:
- MaxRequestWorkers higher than the available file descriptors.
- Unsynchronized limits between Apache and PHP-FPM/App servers.
- KeepAlive timeout too high for workers with many mobile clients.
- Missing buffer for log I/O - block rotation jobs short-term.
I document target values (CPU utilization, RAM, RPS, P95) and save a version of the working configuration. Only then is the Roll-out.
Briefly summarized
Prefork delivers strong Insulation for legacy stacks, but costs a lot of memory. Worker offers a good middle ground with threads per process and scales cleanly as long as Keep-Alive does not tie up unnecessarily. Event separates connection and processing, increases utilization and shows its strength with HTTP/2 and long sessions. I measure systematically, adjust limits and choose the MPM that suits the code, traffic profile and hardware. With clean tuning, clear measurement targets and focused monitoring, Apache gets the most out of each of the three models. Performance out.


