(read must be enough for most of the cases)
Why? Because most of the cases = one cpu, one disk and one ram. Running more Apache children on such a machine is just a waste of resources. The cpu or disk can not work better than 100%. Only sw developers can do better then 100% becase they have to! ;-)
The "normal" approach is to fork as many mod_perl Apache childs as the ram allows to be able to handle as many requests as possible. This was due to the fakt that Apache was processing the whole request(s) from client. This includes the connect, receive request, process request and send response. If we could strip this to the "process" step then we need just one process keeping busy all the resources of hw.
The way how to outsource the client communication somewhere else is to have a light weight reverse proxy. ba.pm.org is using nginx to deliver all the static content and proxy to Apache the only dynamic part and that is the feedback form submit processing.
What nginx does is that it fetches all the client request (can be big and long lasting in case of file uploads) and only when it is finished passes it to the Apache. Then when Apache is finished it pass the whole response to nginx and then it's ready to process another request. While nginx (slowly) let the client download the response.
Nginx is made lightweight, fast to deliver either static content or proxy for the dynamic one.
Let's have a look at the nginx config of ba.pm.org:
# bratislava.pm.org
server {
listen 80;
server_name ba.pm.org;
access_log /var/log/nginx/bratislava.pm-access.log;
location / {
rewrite ^(.*)$ http://bratislava.pm.org$1 permanent;
}
}
server {
listen 80;
server_name bratislava.pm.org;
access_log /var/log/nginx/bratislava.pm-access.log;
location / {
root /data/www/pm;
index index.html index.htm;
}
location /cgi/cgi-bin/ {
proxy_pass http://internal-hostname:81;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $http_host;
proxy_set_header X-Forwarded-Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
location ~* \.(jpg|jpeg|gif|css|png|js|ico|rdf)$ {
root /data/www/pm;
expires 1h;
}
}
The site is ready to handle 1024 simultaneous connections and to receive a lot of feedback. ;-)
So? If you are not "everyone" and the Perl is doing other things than local IO, one Apache child is not enough. But nginx helps to decrease this number for a low price.
I agree that most people could use just a few backend processes for a web application (applies equally to mod_perl, FastCGI, etc). But 1 is definitely not enough. There are a lot of things that can cause a process to have to wait on something else: reading disk, accessing the network (your db is probably on a different machine), reading and writing to the proxy, etc. If you have a dozen or more, then you can always have something working the CPU, doing disk IO and using the network. You're right that you can't work the CPU or disk more than 100%, but 1 apache child won't be work the CPU and disk and network at 100%.
Each application is different and each will need profiling with your traffic patterns to determine what the best number of procs is, but I can guarantee it's more than 1 :)