How to Speed Up Apache

From Voxel dot Net - Knowledge Base

Apache, in the typical default configuration, is slow. Unfortunately this is because people whine that they want features. Features consume resources. CPU time, system call time, memory, network bandwidth. Turn on all the features, and guess what? SLOW. SLOW. SLOW. However, by following these tips, you can make it perform better.

Contents

[edit] Disable atime updates

While atime updates are a handy feature, they tend to generate a lot of unnecessary disk write activity. If you can put the web content on a separate filesystem, do that. Otherwise, the whole root FS is fine. Determine the mountpoint for the filesystem the files reside on, and then do:

mount -o remount,noatime [mountpoint]

Also, add the noatime option to the appropriate entry in /etc/fstab.

[edit] Optimize Logging

If you're dealing with a site that does a lot of logging, you're going to see the performance drop. Apache has to sit there and wait while those logs get written out. That takes time, and makes Apache slower.

The best thing to do is use Apache features to filter out irrelevant log material. In the site definition, do something like this:

# Don't log the loading of images.
SetEnvIfNoCase Request_URI "\.jpg$" dontlog
SetEnvIfNoCase Request_URI "\.jpeg$" dontlog
SetEnvIfNoCase Request_URI "\.png$" dontlog
SetEnvIfNoCase Request_URI "\.gif$" dontlog
SetEnvIfNoCase Request_URI "\.ico$" dontlog
# Same for JavaScript scripts.
SetEnvIfNoCase Request_URI "\.js$" dontlog
# Stylesheets are also a good candidate to not log.
SetEnvIfNoCase Request_URI "\.css$" dontlog
# Add filters for other file types that aren't necessary, or specific subdirectories.
CustomLog /var/log/httpd/access.log combined env=!dontlog

[edit] Check error logs

A lot of developers ignore the error logs. When a site is not very busy, that won't have much of an effect on its performance. However, if the site emits warnings/errors regularly, the higher the activity level gets, the more disk I/O will be expended writing out crap in the error log. Insist that the developers look at the errors mentioned in them. If necessary, direct error logging to /dev/null for the site - it'll be a lot faster than having it actually going to disk.

[edit] Disable .htaccess

Don't believe me? Here is what the Apache developers have to say about why you maybe shouldn't use .htaccess files. Searching for them wastes time, and those stat() calls don't get cached. Reading and parsing that text takes time. Applying the configuration settings therein takes time, and so does rolling them back. There's no reason HTTP auth settings have to be applied in .htaccess - in fact, the Apache developers discourage it. (And with good reason.)

Also, if the customer is using mod_rewrite rules, the performance will be particularly bad. Apache will use compiled regular expressions - but since .htaccess files have to get reprocessed for *every* file served, the performance benefit of compiled regular expressions is lost. This can be substantial.

Therefore, change all AllowOverride directives to AllowOverride None.

[edit] Enable symlinks - but with a qualifier

Explicitly disabling symlink evaluation costs - because every directory in every path has to be lstat()'d to verify that it's not a symlink. Make sure that the FollowSymLinks option is always enabled, to remove the need for this extraneous checking. However, the SymLinksIfOwnerMatch option adds more checking requirements. As long as it's not a shared box - and all the files in the site directory aren't owned by the Apache user - SymLinksIfOwnerMatch is best left off.

[edit] Disable unused modules

Apache has a lot of modules, and most modern distros do us the service of building pretty much every one as a shared object (.so) file. Unfortunately they also do us the disservice of turning a lot of them on that aren't necessary in a lot of configurations.

[edit] Apache on Debian

While it does enable somewhat less of them, it does very much the same thing with regard to enabling unnecessary modules. Run the following to disable them:

a2dismod userdir cgid

[edit] Apache on CentOS/RHEL (?)

Edit /etc/httpd/conf/httpd.conf, and find the lines which start with LoadModule. Comment out the lines for modules which aren't being used on the machine in question. Modules which it's generally a good idea to disable, unless you know the customer is using them:

  • mod_authn_dbm
  • mod_authz_dbm
  • mod_ldap
  • mod_authnz_ldap
  • mod_usertrack
  • mod_dav
  • mod_dav_fs
  • mod_userdir
  • mod_speling
  • mod_proxy
  • mod_proxy_balancer
  • mod_proxy_ftp
  • mod_proxy_http
  • mod_proxy_connect
  • mod_cache
  • mod_suexec
  • mod_disk_cache
  • mod_mem_cache
  • mod_file_cache
  • mod_cgi

[edit] DirectoryIndex directive

Don't abuse the DirectoryIndex directive. Make sure as few filenames are listed with this directive as is feasible for the customer's installation. If you list a lot of possible filenames, every time a directory is specified in a URL, each of the filenames must be lstat()'d for; this is expensive. Also, order them in the sequence so that the most commonly-used index file name appears first; this is a simple optimization that can save a lot of unnecessary lstat() lookups.

[edit] Apache worker MPM

If possible, the Apache worker MPM can do a lot better than the now-aged prefork MPM can. Memory use is less (since it uses threads, which share memory, a lot less memory is needed), and it can use special inter-thread signaling methods that are faster than what can be done with prefork.

[edit] worker on Debian

On Debian, the worker MPM is in a separate package, apache2-mpm-worker. Simply install it.

[edit] worker on CentOS/RHEL (?)

On CentOS, the worker MPM is included in the httpd package, but you need to edit /etc/sysconfig/httpd and uncomment the line that reads:

HTTPD=/usr/sbin/httpd.worker

Then the worker MPM will be used.

[edit] mod_fcgid

However, if the customer is using PHP, this presents an immediate problem. PHP (or most topically, many of the libraries which it leverages) are NOT thread-safe. There is a solution to the problem. Specifically, the component is mod_fcgid. It is a high-performance FastCGI module for Apache.

Note that code caches like eAccelerator and APC work just fine with PHP run via FastCGI; since it uses a persistent-process model, the code caching they apply is just as effective as with the PHP loadable in Apache.

[edit] mod_fcgid on Debian

On Debian, install the libapache2-mod-fcgid and php5-cgi packages. Then run:

a2enmod fcgid

to add the necessary configuration material.

(to be completed)

[edit] mod_fcgid on CentOS/RHEL (?)

If the machine is running CentOS, though, it requires that an external component be built, as there aren't packages available for it.

yum -y install httpd-devel php-cli make
cd /root
wget http://internap.dl.sourceforge.net/sourceforge/mod-fcgid/mod_fcgid.2.2.tgz
tar zxf mod_fcgid.2.2.tgz
cd mod_fcgid.2.2
sed -i -r -e 's/^(top_dir[[:space:]]+=).*$/\1 \/usr\/lib'$(if [ "$(uname -m)" = "x86_64" ] ; \
  then echo "64" ; fi)'\/httpd/' ./Makefile
make
make install
mv /etc/httpd/conf.d/php.conf{,.dontuse}
echo "cgi.fix_pathinfo = 1" >> /etc/php.ini
cat > /etc/httpd/conf.d/fcgid.conf <<_EOT_
LoadModule fcgid_module modules/mod_fcgid.so
AddHandler fcgid-script .php
FCGIWrapper /usr/bin/php-cgi .php
IPCCommTimeout 300
DefaultInitEnv PHP_FCGI_CHILDREN 5
DefaultInitEnv PHP_FCGI_MAX_REQUESTS 10000
PHP_Fix_Pathinfo_Enable 1
MaxProcessCount 4
SocketPath /var/tmp
DirectoryIndex index.php
_EOT_

Then make sure to add the ExecCGI option for all virtual hosts that should be allowed to run PHP scripts. Finally, restart Apache.

[edit] Serving from NFS

There are certain optimizations which are enabled by default in Apache, which work well for local files, but if you're serving content from an NFS share, they have a somewhat opposite effect. Two settings in particular should be disabled:

  • EnableMMAP - Turned on by default. Bad for NFS performance. Make sure to uncomment or add EnableMMAP off in the Apache server configuration.
  • EnableSendfile - Same. Uncomment or add EnableSendfile off in the Apache server configuration as well.

[edit] Extra services

One thing which can also contribute to poor performance is extra services. CentOS/RHEL in particular are notorious for running these. They don't do anything useful for a typical server configuration, they eat up memory and CPU time, and present additional security risks. However, for certain configs they are needed - not generally the configs we're deploying, though. Debian tends to be more bare-bones by default, fortunately. For CentOS, I recommend running the following command to remove useless default services:

yum remove xorg-x11-xfs avahi autofs pcsc-lite bluez-utils irda-utils isdn4k-utils ypbind cups

Also, if the machine isn't mounting any NFS exports, you can run:

yum remove portmap

which will remove all the NFS client daemons.

Personal tools