SoftwarePractice.org: Home | Courseware | Wiki | Archive

Optimizing a web server

From SoftwarePractice.org

Here are a collection of things to do to improve the performance and robustness of the new web server. Some of these are simply auxiliary functions that we didn't include the first time around.

Contents

Rebuild PHP

A lot of web applications require or work better with libraries that are optional in the default PHP install.

You could go get them and install by hand (./configure; make; make install). I found, though, that for this stuff the FreeBSD ports system worked better. For example:

cd /usr/ports/graphics/gd
make install

With any luck, that all worked, so now rebuild PHP.

  rm config.status config.cache
  make clean
  ./configure --with-apxs2=/usr/local/apache2/bin/apxs \
              --with-mysql=/usr/local/mysql \
              --with-mysqli=/usr/local/mysql/bin/mysql_config \
              --with-zlib --with-gd=/usr/local --with-freetype-dir=/usr/local \
              --with-gettext --with-pspell
  make
  make install

And restart Apache:

  /usr/local/apache2/bin/apachectl restart

Apache modules

Transfer times are reduced a lot if you have the web server compress output. So, I enabled the following:

  • mod_deflate

Also, it's useful to remove modules that you don't actually need. This does reduce the size of the Apache processes a little. More importantly, it makes sure that you don't inadvertently turn on features that you don't want turned on (you can't, since they aren't enabled). If you are simply running PHP applications, most of the default modules included in Apache are not even necessary. I disabled the following modules:

  • mod_authn_file
  • mod_authz_groupfile
  • mod_authz_user
  • mod_auth_basic
  • mod_include
  • mod_filter
  • mod_env
  • mod_setenvif
  • mod_status
  • mod_asis
  • mod_actions
  • mod_userdir

Before rebuilding Apache, you will want to stop it. So, the sequence looks like this:

/usr/local/apache2/bin/apachectl stop
./configure --enable-so --enable-rewrite \
            --enable-deflate \
            --disable-authn-file \
            --disable-authz-groupfile \
            --disable-authz-user \
            --disable-auth-basic \
            --disable-include \
            --disable-filter \
            --disable-env \
            --disable-setenvif \
            --disable-status \
            --disable-asis \
            --disable-actions \
            --disable-userdir
make
make install
/usr/local/apache2/bin/apachectl start

Now add the following lines to httpd.conf to enable compression of all text delivered by the server. (Images and PDF files are already compressed, there is little point in trying to compress them further.)

# Enable compression of all text output
<IfModule deflate_module>
  AddOutputFilterByType DEFLATE text/html text/plain text/xml
</IfModule>

Some notes:

  • After restarting Apache, you can reload a page that you had previously noted the size of. When I did this, I got a compression ratio of around 8.
  • To see what modules you have compiled into Apache, do this:
  /usr/local/apache2/bin/httpd -l
  • Or, use the PHP function phpinfo().
  • You can of course get the low-down on Apache modules on apache.org.
  • Here is a useful resource: Securing Apache 2.

Other Apache tweaks

  1. On FreeBSD, use this cryptic command. This removes the warning message about the httpready accept filter on Apache startup. Found here. It apparently has a performance benefit.
    kldload accf_http
    
  2. Don't use overrides, and allow symbolic links. In other words, this means that you have this in your httpd.conf:
    <Directory />
        Options FollowSymLinks
        AllowOverride None
    </Directory>
    

    The first means that Apache doesn't have to check if a file is really symbolic link. The second means that if you have any .htaccess files in your web server directories, they won't work. So, what you have to do is take the contents of those file and put them in httpd.conf instead!

    While you are still installing and/or developing, you probably want to have AllowOverride All there instead. But when getting ready a site for production you can move the contents of your .htaccess files into httpd.conf.

Footnote: I haven't benchmarked any of these. To be honest I suspect that the performance gains are not very significant if you're generating the site dynamically with PHP.

Install APC

This is a byte-code cache for PHP. Things go faster.

  1. Go get it
  2. Compile it
      cd APC-3.0.10
      phpize
      ./configure --enable-apc --enable-apc-mmap \
                  --with-apxs=/usr/local/apache2/bin/apxs \
                  --with-php-config=/usr/local/bin/php-config
      make
      make install
    
  3. Now modify /usr/local/lib/php.ini, as follows. The argument to the extension option is what is printed by the 'make install' in the previous step.
    ; APC
      extension="/usr/local/lib/php/extensions/no-debug-non-zts-20050922/apc.so"
      apc.enabled=1
      apc.shm_segments=1
      apc.optimization=0
      apc.shm_size=128
      apc.ttl=7200
      apc.user_ttl=7200
      apc.num_files_hint=1024
      apc.mmap_file_mask=/tmp/apc.XXXXXX
      apc.enable_cli=1
    
  4. Restart Apache.
  5. Reload info.php to check that APC is operating with the expected parameters.
  6. Copy apc.php into your default server public_html and load it. Useful to make that protected -- see Securing a web server.


I did a quick check by loading pages with APC turned off (apc.enabled=0) and on (apc.enabled=1). These pages display the page generation time (I am using SMF). With APC enabled, the page generation (note: not download time) was just over half as long, after the first load. So, nearly double the performance (including MySQL queries), with very little work.

I also played with the optimization parameter, but it seemed to make very little difference to the best page generation time. So either it doesn't do anything, or page generation times are dominated by MySQL queries.

Rotate logs

Unless you do something about it, your server logs will get larger and larger.... ouch!

  • The basic way is this. For each virtual host, replace the CustomLog directive with a line like this:
      CustomLog "|/usr/local/apache2/bin/rotatelogs /usr/www/default/logs/access_log.%Y%m%d 86400" combined
    

    (Wait at least a day to see if it worked.)

  • Here's another way. Get and install Cronolog. Then use eg
      CustomLog "|/usr/local/sbin/cronolog /usr/www/default/logs/access_log.%Y%m%d" combined
    


Thrash it

It's worth running a load testing tool before you go live. I like this one, because it's simple:

(Or get it from the FreeBSD ports collection at /usr/ports/www/http_load.)

I simply created a file with ten URLs selected from around my test application. Then:

http_load -parallel 20 -seconds 60 urls

(Where urls is the file with the URLs in it.)

With APC enabled my machine serves about 10 requests per second; without APC, about 5.5. This is actually a bit disappointing. Bear in mind though these requests are complex PHP pages, with 15 or 20 SQL queries each.

It's also instructive to view top while running http_load.

See also

Securing a web server

Backing up a web server

Personal tools