Apache Tuning

PHP: fastcgi
- Why:
Fastcgi is optimized to run php-code in a efficient way
fastcgi

Of course every time your php code is loaded it must be compiled before running it (this happens automatically)
To improve this I use eaccelerator
(this will cache the compiled scripts)
(WARNING if you replace some php scripts you should clean-out the cache to prevent core-dumps)
(a +70% boost is possible)

Also a nice reason to switch to mod_fcgi is that you can limit the workers only for php and let apache handle the flat files (like jpg, gif ...)

Apache: Worker
- Why:
Apache-mpm-prefork is good but not good enough
With prefork mode you need to much memory for 1 active connection,
(so when someone is using a 28k line could block 1 connection for a long time and is a wast of memory use)

Apache-mpm-worker is much better in using memory coz it is shared
1 process can handle many active requests using threads
The good thing about this is that you share the memory and you don't need to load it every time(or many times)

Apache: mod_disk_cache
- Why:
There are 2 great way,s of caching with apache
Disk cache and Memory cache

You should think memory cache is the best way, But I don't think so
Cache is something that can grow
Memory cache is gone @ restart
Cleanup memory cache = restart
Cleanup disk cache = just remove what is old (with htcacheclean)

I now memory is much faster then disk, but do the following test

time cat 2M-file > /dev/null 
real	0m0.198s 
user	0m0.004s 
sys	0m0.008s
 time cat 2M-file > /dev/null 
real	0m0.008s 
user	0m0.000s 
sys	0m0.004s

As you can see the second time the file just comes from the memory
So the system-disk cache is used to speed-up this cache
(and it is as fast as mod_mem_cache)

Drupal:
Drupal is heavy in php scripts
To boost Drupal you can add many CPU cores but that is the brute force way (and costs ...)

The other way is caching(you should think)
That is right if you have anonymous users on your site

When only 10% is authenticated you should split-up the anonymous users against the others
and you will have a great boost for 90% of your traffic (cache)(and its worth doing that)

But when 90% is authenticated, it is not a good idea
Then you should use only the build-in cache of Drupal
(that give a great boost in speed)

So now my config for a default Drupal site (using the xen guest, 2cpu 3Ghz and 512MB memory)
Apache-mpm-worker

KeepAlive On 
MaxKeepAliveRequests 50 
KeepAliveTimeout 5

I use keepAlive but set a limit to it (so it will not take all your resources)

 
    StartServers          4 
    MaxClients          400 
    MinSpareThreads     200 
    MaxSpareThreads     250 
    ThreadsPerChild      50 
    MaxRequestsPerChild   100000 

With 4 servers(processes) as default I think it is enough
The ThreadsPerChild can be bigger (depending of your traffic)
The MaxRequestsPerChild Must be calculated to your needs
I mostly guess that this count has been reached on 1 day
(this is just to prevent memory-leaks)(when reached the process will be killed and a new will respawn)

 
  SocketPath /var/lib/apache2/fcgid/sock 
  IPCConnectTimeout 20 
  IPCCommTimeout 20 
  OutputBufferSize 0 
  #MaxRequestsPerProcess 10000 

  IdleTimeout 360 
  BusyTimeout 60 
  IdleScanInterval 30 
  BusyScanInterval 100 
  ZombieScanInterval 13 
  ProcessLifetime 3600 
  MaxProcessCount 40 
  DefaultMaxClassProcessCount 40 

This counters depends of your setup and are not all necessary
The imported one is MaxProcessCount and DefaultMaxClassProcessCount
With those you can limit the count of processes
(every process will take a lot of memory so you need to calculate that you don't take to much memory)
(take in mind that you need also memory free for your disk cache)

Caching:

CacheDirLevels 2 
CacheDirLength 1 
CacheRoot /var/cache/apache2/mod_disk_cache 
CacheEnable disk /images/ 
CacheEnable disk /sites/

Here you can specify what directory's you should cache
You can take all if you wish "CacheEnable disk /"
(Apache is reading the http headers to decide what to include into the cache)

RequestHeader unset Cache-Control early

Unset the RequestHeader for Cache-Control!
This wil ignore the cachecontrol from the clients
If you push F5 in firefox it will send a "max-age=0" in the header
This will force to drop you cache and request a update
Of course this is what you will prevent if you try to cache for performance

SuexecUserGroup mario mario

For security reasons the fcgi will be started as user "mario"
(you must chmod mario:mario /var/www/site/ so that fcgi has rights to use your php scripts)

 
  AddHandler fcgid-script .php 
  Options +ExecCGI 
  FCGIWrapper /var/www/php5-cgi .php 
  AllowOverride all 
  Order allow,deny 
  Allow from all 

Here I specify that .php must be handled by a external tool (fcgi)

cat /var/www/php5-cgi

#!/bin/sh 
exec /usr/bin/php5-cgi "$@"

/var/www/php5-cgi must be owned by the user and group of SuexecUserGroup
(just to let it executed by this user)

Conclusion

With those configurations you can speed-up your php to the max of your hardware
Apache can handle more requests than using prefork(coz of memory)
static files will be cached (this helps a lot, a jpg of 5k without cache 300requests/sec, with cache 3000request/sec)
requesting the frontpage(php) was default 15rqst/sec, after implementing this I had 220rqst/sec
If you really need the power for thousands of users you can even let the fcgi running on other servers to spread the CPU usage

Proxy-ing is not a good idea with Drupal, (well if you only have anonymous users)
The only thing it does is giving a extra latency coz it always must forward the request to the backend.