Note: this article was from a series running on PerlMonth from 1999. PerlMonth.com seems to have disappeared, so this article is reposted with some slight modifications to make it current for recent releases of Apache::ASP ( versions >= 2.29 ).
Last month, we used Apache::ASP to build a simple MyBookmarks web application. Now we are going to tune the Apache::ASP web application and Apache web server, taking a mild mannered web app running at 250,000 pages per day, and boosting it up 4 times to a 1,000,000 pages per day powerhouse.
Are you ready? Let's Tune!
The application is run on a Solaris x86 box, PII300 512K cache with 2 4G 7200 RPM SCSI drives in a software RAID 1 configuration. The following numbers are not meant to be compared against other web application environments, or systems, but show relative performance improvements when tuning Apache::ASP and Apache on this particular system.
The web server software being tested is apache 1.3.4, with the testing client ab, or ApacheBench, run locally on the server. Because ApacheBench does not support cookies, a new Apache::ASP $Session is created in StateDir for every request, so that the benchmark numbers are worse than what you would see in a production setting. Obviously testing locally does not take into account many slow client connections over the internet, which would likely be offset by a reverse proxy accelerator in production (see mod_perl guide).
The ab program was run with 5 concurrent clients for 30 seconds with the following command:
ab -c 5 -t 30 http:// $HOST /bookmarks/index.asp
The trick then is to relocate the StateDir to a fast cached file system. On Solaris, this happens to be /tmp/... by default, but on Linux and WinNT, the file systems seem to be cached automatically, so you may not need to do anything except locate StateDir to a secure, non-browsable, location. Using a cached or RAM file system will also spare your disk, which is good as it is often the first thing to go on your box.
Hits/sec | Before | After |
+116% | 6.5 h/s | 14.1 h/s |
Configuration | ||
AP.htaccess | yes | yes |
APMaxClients | 5 | 5 |
APMaxRequestsPerChild | 50 | 50 |
Debug | 1 | 1 |
Global | . | . |
GlobalPackage | My::Bookmarks | My::Bookmarks |
SessionSerialize | 0 | 0 |
SessionTimeout | 15 | 15 |
StateDir | .state | /tmp/bookmarks |
Comments | Disk i/o activity takes 50% of the time, because the StateDir is pointed at a non-caching file system. | Disk i/o activity is nearly 0%, with roughly 75% of the time spent in the user space, and 25% in the kernel |
Legend | Configuration items that start with AP are Apache configuration options, the rest are Apache::ASP. The .htaccess one means that configurations are stored in the .htaccess if yes, if no in a configuration file. The configuration changes between benchmarks are highlighted in pink. |
Hits/sec | Before | After |
+12% | 14.1 h/s | 15.8 h/s |
Configuration | ||
AP.htaccess | yes | yes |
APMaxClients | 5 | 5 |
APMaxRequestsPerChild | 50 | 50 |
Debug | 1 | 0 |
Global | . | . |
GlobalPackage | My::Bookmarks | My::Bookmarks |
SessionSerialize | 0 | 0 |
SessionTimeout | 15 | 15 |
StateDir | /tmp/bookmarks | /tmp/bookmarks |
Comments | Disk i/o activity is nearly 0%, with roughly 75% of the time spent in the user space, and 25% in the kernel | |
Legend | Configuration items that start with AP are Apache configuration options, the rest are Apache::ASP. The .htaccess one means that configurations are stored in the .htaccess if yes, if no in a configuration file. The configuration changes between benchmarks are highlighted in pink. |
AllowOverride Nonewherever your Apache::ASP application is located.
Hits/sec | Before | After |
+9% | 15.8 h/s | 17.3 h/s |
Configuration | ||
AP.htaccess | yes | no |
APMaxClients | 5 | 5 |
APMaxRequestsPerChild | 50 | 50 |
Debug | 0 | 0 |
Global | . | . |
GlobalPackage | My::Bookmarks | My::Bookmarks |
SessionSerialize | 0 | 0 |
SessionTimeout | 15 | 15 |
StateDir | /tmp/bookmarks | /tmp/bookmarks |
Comments | Couldn't believe my eyes when I saw there to be so little difference when not using .htaccess. My guess is that the Apache people optimized this at some point. | |
Legend | Configuration items that start with AP are Apache configuration options, the rest are Apache::ASP. The .htaccess one means that configurations are stored in the .htaccess if yes, if no in a configuration file. The configuration changes between benchmarks are highlighted in pink. |
We had the MaxRequestsPerChild pretty low before at 50 but we up it now to 500 which should be fine for production. You don't want to set this too high, or the mod_perl httpds will often take up too much memory because of leaks, and shared forked code becoming unshared as it gets dirtied.
Hits/sec | Before | After |
+31% | 17.3 h/s | 22.8 h/s |
Configuration | ||
AP.htaccess | no | no |
APMaxClients | 5 | 5 |
APMaxRequestsPerChild | 50 | 500 |
Debug | 0 | 0 |
Global | . | . |
GlobalPackage | My::Bookmarks | My::Bookmarks |
SessionSerialize | 0 | 0 |
SessionTimeout | 15 | 15 |
StateDir | /tmp/bookmarks | /tmp/bookmarks |
Comments | Couldn't believe my eyes when I saw there to be so little difference when not using .htaccess. My guess is that the Apache people optimized this at some point. | This bench only had 684 requests, so there was no parent httpd forking during this time, whereas before there may have been reforking every few seconds during the 30 second bench. |
Legend | Configuration items that start with AP are Apache configuration options, the rest are Apache::ASP. The .htaccess one means that configurations are stored in the .htaccess if yes, if no in a configuration file. The configuration changes between benchmarks are highlighted in pink. |
The reason why SessionSerialize is not enabled by default is that one could easily deny service to a user with a long running script, such that no other scripts for that same user $Session could be run, and this requires some expertise. Also SessionSerialize is probably not a good thing for framed sites, where there is greater concurrency for the same $Session.
Hits/sec | Before | After |
+12% | 22.8 h/s | 25.74 h/s |
Configuration | ||
AP.htaccess | no | no |
APMaxClients | 5 | 5 |
APMaxRequestsPerChild | 500 | 500 |
Debug | 0 | 0 |
Global | . | . |
GlobalPackage | My::Bookmarks | My::Bookmarks |
SessionSerialize | 0 | 1 |
SessionTimeout | 15 | 15 |
StateDir | /tmp/bookmarks | /tmp/bookmarks |
Comments | This bench only had 684 requests, so there was no parent httpd forking during this time, whereas before there may have been reforking every few seconds during the 30 second bench. | |
Legend | Configuration items that start with AP are Apache configuration options, the rest are Apache::ASP. The .htaccess one means that configurations are stored in the .htaccess if yes, if no in a configuration file. The configuration changes between benchmarks are highlighted in pink. |
Hits/sec | Before | After |
+296% | 6.5 h/s | 25.74 h/s |
Configuration | ||
AP.htaccess | yes | no |
APMaxClients | 5 | 5 |
APMaxRequestsPerChild | 50 | 500 |
Debug | 1 | 0 |
Global | . | . |
GlobalPackage | My::Bookmarks | My::Bookmarks |
SessionSerialize | 0 | 1 |
SessionTimeout | 15 | 15 |
StateDir | .state | /tmp/bookmarks |
Comments | Disk i/o activity takes 50% of the time, because the StateDir is pointed at a non-caching file system. | |
Legend | Configuration items that start with AP are Apache configuration options, the rest are Apache::ASP. The .htaccess one means that configurations are stored in the .htaccess if yes, if no in a configuration file. The configuration changes between benchmarks are highlighted in pink. |