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.
- zlib (for zip/unzip support)
- gettext (internationalization)
- FreeType (font rendering)
- GD (graphics library)
- aspell (spell checker)
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
- 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
- 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.
- Go get it
- 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 -
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
- Restart Apache.
- Reload info.php to check that APC is operating with the expected parameters.
- 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.
