Apache Performance Notes
Prior to Apache 1.3,
HostnameLookups
defaulted to On. This adds latency to every request because it requires a DNS
lookup to complete before the request is finished. In Apache 1.3 this setting defaults to Off.
If you need to have addresses in your log files resolved to hostnames, use the
logresolve program that comes
with Apache, or one of the numerous log reporting packages which are available.
It is recommended that you do this sort of postprocessing of your log files on some machine
other than the production web server machine, in order that this activity not adversely affect
server performance.
If you use any
Allow
from domain or
Deny
from domain directives (i.e., using a hostname, or a domain name, rather than an IP
address) then you will pay for a double reverse DNS lookup (a reverse, followed by a forward
to make sure that the reverse is not being spoofed). For best performance, therefore, use IP
addresses, rather than names, when using these directives, if possible.
Note that it's possible to scope the directives, such as within a <Location
/server-status> section. In this case the DNS lookups are only performed on requests
matching the criteria. Here's an example which disables lookups except for .html and .cgi
files:
HostnameLookups off
<Files ~ "\.(html|cgi)$">
HostnameLookups on
</Files>
But even still, if you just need DNS names in some CGIs you could consider doing the gethostbyname
call in the specific CGIs that need it.
Wherever in your URL-space you do not have an Options FollowSymLinks, or you
do have an Options SymLinksIfOwnerMatch Apache will have to issue extra system
calls to check up on symlinks. One extra call per filename component. For example, if you had:
DocumentRoot /www/htdocs
<Directory />
Options SymLinksIfOwnerMatch
</Directory>
and a request is made for the URI /index.html. Then Apache will perform lstat(2)
on /www, /www/htdocs, and /www/htdocs/index.html. The
results of these lstats are never cached, so they will occur on every single
request. If you really desire the symlinks security checking you can do something like this:
DocumentRoot /www/htdocs
<Directory />
Options FollowSymLinks
</Directory>
<Directory /www/htdocs>
Options -FollowSymLinks +SymLinksIfOwnerMatch
</Directory>
This at least avoids the extra checks for the DocumentRoot path. Note that
you'll need to add similar sections if you have any Alias or RewriteRule
paths outside of your document root. For highest performance, and no symlink protection, set FollowSymLinks
everywhere, and never set SymLinksIfOwnerMatch.
Wherever in your URL-space you allow overrides (typically .htaccess files)
Apache will attempt to open .htaccess for each filename component. For example,
DocumentRoot /www/htdocs
<Directory />
AllowOverride all
</Directory>
and a request is made for the URI /index.html. Then Apache will attempt to
open /.htaccess, /www/.htaccess, and /www/htdocs/.htaccess.
The solutions are similar to the previous case of Options FollowSymLinks. For
highest performance use AllowOverride None everywhere in your filesystem.
See also the .htaccess tutorial
for further discussion of this.
If at all possible, avoid content-negotiation if you're really interested in every last
ounce of performance. In practice the benefits of negotiation outweigh the performance
penalties. There's one case where you can speed up the server. Instead of using a wildcard
such as:
DirectoryIndex index
Use a complete list of options:
DirectoryIndex index.cgi index.pl index.shtml index.html
where you list the most common choice first.
If your site needs content negotiation, consider using type-map files rather
than the Options MultiViews directive to accomplish the negotiation. See the
Content Negotiation
documentation for a full discussion of the methods of negotiation, and instructions for
creating type-map files.
Prior to Apache 1.3 the
MinSpareServers,
MaxSpareServers,
and StartServers
settings all had drastic effects on benchmark results. In particular, Apache required a
"ramp-up" period in order to reach a number of children sufficient to serve the load
being applied. After the initial spawning of StartServers children, only one
child per second would be created to satisfy the MinSpareServers setting. So a
server being accessed by 100 simultaneous clients, using the default StartServers
of 5 would take on the order 95 seconds to spawn enough children to handle the load. This
works fine in practice on real-life servers, because they aren't restarted frequently. But
results in poor performance on benchmarks, which might only run for ten minutes.
The one-per-second rule was implemented in an effort to avoid swamping the machine with the
startup of new children. If the machine is busy spawning children it can't service requests.
But it has such a drastic effect on the perceived performance of Apache that it had to be
replaced. As of Apache 1.3, the code will relax the one-per-second rule. It will spawn one,
wait a second, then spawn two, wait a second, then spawn four, and it will continue
exponentially until it is spawning 32 children per second. It will stop whenever it satisfies
the MinSpareServers setting.
This appears to be responsive enough that it's almost unnecessary to adjust the MinSpareServers,
MaxSpareServers and StartServers settings. When more than 4 children
are spawned per second, a message will be emitted to the ErrorLog. If you see a
lot of these errors then consider tuning these settings. Use the mod_status
output as a guide.
In particular, you may need to set MinSpareServers higher if traffic on your
site is extremely bursty - that is, if the number of connections to your site fluctuates
radically in short periods of time. This may be the case, for example, if traffic to your site
is highly event-driven, such as sites for major sports events, or other sites where users are
encouraged to visit the site at a particular time.
Related to process creation is process death induced by the MaxRequestsPerChild
setting. By default this is 0, which means that there is no limit to the number of requests
handled per child. If your configuration currently has this set to some very low number, such
as 30, you may want to bump this up significantly. If you are running SunOS or an old version
of Solaris, limit this to 10000 or so because of memory leaks.
When keep-alives are in use, children will be kept busy doing nothing waiting for more
requests on the already open connection. The default KeepAliveTimeout of 15
seconds attempts to minimize this effect. The tradeoff here is between network bandwidth and
server resources. In no event should you raise this above about 60 seconds, as most of the benefits
are lost.
Since memory usage is such an important consideration in performance, you should attempt to
eliminate modules that you are not actually using. If you have built the modules as
DSOs, eliminating modules is a simple matter
of commenting out the associated
AddModule and
LoadModule directives
for that module. This allows you to experiment with removing modules, and seeing if your site
still functions in their absence.
If, on the other hand, you have modules statically linked into your Apache binary, you will
need to recompile Apache in order to remove unwanted modules.
An associated question that arises here is, of course, what modules you need, and which
ones you don't. The answer here will, of course, vary from one web site to another. However,
the minimal list of modules which you can get by with tends to include
mod_mime,
mod_dir, and
mod_log_config. mod_log_config
is, of course, optional, as you can run a web site without log files. This is, however, not
recommended.
Apache comes with a module,
mod_mmap_static,
which is not enabled by default, which allows you to map files into RAM, and serve them
directly from memory rather than from the disc, which should result in substantial performance
improvement for frequently-requests files. Note that when files are modified, you will need to
restart your server in order to serve the latest version of the file, so this is not
appropriate for files which change frequently. See the documentation for this module for more
complete details.
|