I wrote up a text file about benchmarking and comparing Tomcat-4.0-M5 (pre-release) and Apache 1.3.12. It's attached to this message. I wrote it for anyone who is interested (even non-Java-saavy people) to know how the raw content serving performance of Catalina and its built-in web server compares to that of Apache 1.3.12. It contains lots of information to help people understand some of the important differences between the two servers. Feedback, flames, reproduced test results, etc. are welcome! :) Cheers. -- Jason Brittain Software Engineer, Olliance Inc. http://www.Olliance.com Current Maintainer, Locomotive Project http://www.Locomotive.org
I've just completed some new benchmarks comparing the static content serving performance of Tomcat/Catalina M5 (pre-release from CVS) and Apache 1.3.12. Below I've included information about the benchmark, and the results. About My Apache Server 1.3.12 I downloaded Apache 1.3.12 source release from http://www.apache.org/ , compiled it with gcc, and installed it on my machine. Here is the module signature of my apache httpd: [jason@netninja bin]$ ./httpd -l Compiled-in modules: http_core.c mod_env.c mod_log_config.c mod_mime.c mod_negotiation.c mod_status.c mod_include.c mod_autoindex.c mod_dir.c mod_cgi.c mod_asis.c mod_imap.c mod_actions.c mod_userdir.c mod_alias.c mod_access.c mod_auth.c mod_so.c mod_setenvif.c suexec: disabled; invalid wrapper /usr/local/apache/bin/suexec Here is a description of the only configuration options I changed (in conf/httpd.conf): Configuration Variable Old Value New Value ------------------------------------------------------------------ MaxKeepAliveRequests 100 200 MinSpareServers 5 50 MaxSpareServers 10 250 StartServers 5 50 MaxClients 150 250 I set MaxKeepAliveRequests higher so that the server would not run into a ceiling with keepalive requests (for better performance). I set the SpareServers variables and StartServer to higher numbers so that the server would not have to for lots of new servers at the beginning of the test (which would probably severely degrade the performance -- this is one major scalability problem with Apache 1.3 that Apache 2.0 aims to solve). I also raised MaxClients above the level that it should need to be for my tests, removing another potential ceiling. With this configuration, after running the server, ps shows that Apache has 53 httpd processes running and ready to serve. About Tomcat 4.0 / Catalina M5 I pulled the Tomcat 4.0 M5 pre-release sources from cvs (see http://jakarta.apache.org for information about the source modules. The code was the HEAD revision from CVS available on November 30th), built the source using Sun's JDK 1.3, and installed the package on my machine. The only settings that I changed are in the server.xml file: In the config section that defines the Catalina stand-alone web server's threading settings, here's what the original config said: <!-- Define a non-SSL HTTP/1.1 Connector on port 8080 --> <Connector className="org.apache.catalina.connector.http.HttpConnector" port="8080" minProcessors="5" maxProcessors="75" acceptCount="10" debug="0"/> .. and here's what I changed it to: <!-- Define a non-SSL HTTP/1.1 Connector on port 8080 --> <Connector className="org.apache.catalina.connector.http.HttpConnector" port="8080" minProcessors="100" maxProcessors="210" acceptCount="255" debug="0"/> Plus, I turned off some timestamping of other log files. Here's the diff between the stock server.xml file and my server.xml file: 47,48c47,48 < port="8080" minProcessors="5" maxProcessors="75" < acceptCount="10" debug="0"/> --- > port="8080" minProcessors="100" maxProcessors="210" > acceptCount="255" debug="0"/> 78c78 < timestamp="true"/> --- > timestamp="false"/> 122c122 < timestamp="true"/> --- > timestamp="false"/> 139c139 < timestamp="true"/> --- > timestamp="false"/> Then, I set the CATALINA_OPTS (optional settings to be passed to the JVM) environment variable to a value of "-Xms96m -Xmx96m". What this does is give the server a startup heap of 96M of RAM (all it will need so that it does not need to resize) and a maximum heap size of 96M. This single setting greatly inproved Catalina's performance compared to the same tests without this setting! The Java VM I used for running the test is Sun's J2SE 1.3 HotSpot Client VM for Linux: [jason@netninja conf]$ java -version java version "1.3.0beta_refresh" Java(TM) 2 Runtime Environment, Standard Edition (build 1.3.0beta_refresh-b09) Java HotSpot(TM) Client VM (build 1.3.0beta-b07, mixed mode) Last, I copied the Apache index.html file into the document root for Catalina, so that the test serves the exact same content on both servers. My Machine It's a Dell Inspiron 5000 notebook with a 500Mhz Pentium III Coppermine processor, 256M of RAM. Here is my processor information: [jason@netninja conf]$ cat /proc/cpuinfo processor : 0 vendor_id : GenuineIntel cpu family : 6 model : 8 model name : Pentium III (Coppermine) stepping : 1 cpu MHz : 497.839198 cache size : 128 KB fdiv_bug : no hlt_bug : no sep_bug : no f00f_bug : no coma_bug : no fpu : yes fpu_exception : yes cpuid level : 2 wp : yes flags : fpu vme de pse tsc msr pae mce cx8 sep mtrr pge mca cmov pat pse36 mmx fxsr xmm bogomips : 496.44 Here is information about my hard drive bus, from dmesg: PIIX4: IDE controller on PCI bus 00 dev 39 PIIX4: not 100% native mode: will probe irqs later ide0: BM-DMA at 0x1050-0x1057, BIOS settings: hda:DMA, hdb:pio ide1: BM-DMA at 0x1058-0x105f, BIOS settings: hdc:DMA, hdd:pio hda: IBM-DARA-212000, ATA DISK drive hdc: TOSHIBA CD-ROM XM-7002B, ATAPI CDROM drive hda: IBM-DARA-212000, 11513MB w/418kB Cache, CHS=1559/240/63 hdc: ATAPI 24X CD-ROM drive, 128kB Cache My machine runs RedHat Linux 6.2, with a kernel that I compiled to support some devices on this machine: [jason@netninja conf]$ uname -a Linux netninja.olliance.com 2.2.14-12 #1 Tue Apr 25 13:04:07 EDT 2000 i686 unknown The Test I wanted to benchmark these servers in a way that is similar to real-world web serving, so I chose to benchmark concurrent requests from many clients at once. The client tester tool that I used is ApacheBench ("ab"). It came with the Apache that was pre-installed on my RedHat 6.2 system: [root@netninja /root]# which ab /usr/sbin/ab [root@netninja /root]# ab -h Usage: ab [options] [http://]hostname[:port]/path Options are: -n requests Number of requests to perform -c concurrency Number of multiple requests to make -t timelimit Seconds to max. wait for responses -p postfile File containg data to POST -T content-type Content-type header for POSTing -v verbosity How much troubleshooting info to print -w Print out results in HTML tables -i Use HEAD instead of GET -x attributes String to insert as table attributes -y attributes String to insert as tr attributes -z attributes String to insert as td or th attributes -C attribute Add cookie, eg. 'Apache=1234. (repeatable) -H attribute Add Arbitrary header line, eg. 'Accept-Encoding: zop' Inserted after all normal header lines. (repeatable) -A attribute Add Basic WWW Authentication, the attributes are a colon separated username and password. -p attribute Add Basic Proxy Authentication, the attributes are a colon separated username and password. -V Print version number and exit -k Use HTTP KeepAlive feature -h Display usage information (this message) And, info from the manual page for ab: ab(1) ab(1) NAME ab - Apache HTTP server benchmarking tool SYNOPSIS ab [ -k ] [ -i ] [ -n requests ] [ -t timelimit ] [ -c concurrency ] [ -p POST file ] [ -A Authenticate user name:password ] [ -P Proxy Authenticate username:password ] [ -H Custom header ] [ -C Cookie name=value ] [ -T con tent-type ] [ -v verbosity ] ] [ -w output HTML ] ] [ -x <table> attributes ] ] [ -y <tr> attributes ] ] [ -z <td> attributes ] [http://]hostname[:port]/path ab [ -V ] [ -h ] DESCRIPTION ab is a tool for benchmarking the performance of your Apache HyperText Transfer Protocol (HTTP) server. It does this by giving you an indication of how many requests per second your Apache installation can serve. For my test, I used ab to simulate 60 concurrent clients that make a total of 10,000 requests to the server, completing them as fast as the server is capable of completing them. At the end of each benchmark, ab prints the timed results. I used two sets of switches to ab: one that uses HTTP keepalive connections, and another that doesn't: /usr/sbin/ab -n 10000 -c 60 http://localhost:8080/index.html (no keepalives) /usr/sbin/ab -k -n 10000 -c 60 http://localhost:8080/index.html (keepalives on) Note that these switches tell ab to run 60 concurrent clients, each making requests to the server concurrently, for an overall total number of requests being 10,000. During the tests, I ran either Apache, or Catalina (not both), and I allowed each test to complete without running or shutting down any other processes. Here is output (and benchmark numbers) from the tests: ========= Apache 1.3 Benchmarks =================== [root@netninja /root]# /usr/sbin/ab -k -n 10000 -c 60 http://localhost:80/index.html This is ApacheBench, Version 1.3c <$Revision: 1.38 $> apache-1.3 Copyright (c) 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/ Copyright (c) 1998-1999 The Apache Group, http://www.apache.org/ Benchmarking localhost (be patient)... Server Software: Apache/1.3.12 Server Hostname: localhost Server Port: 80 Document Path: /index.html Document Length: 1358 bytes Concurrency Level: 60 Time taken for tests: 23.978 seconds Complete requests: 10000 Failed requests: 0 Keep-Alive requests: 10043 Total transferred: 18364664 bytes HTML transferred: 13638394 bytes Requests per second: 417.05 Transfer rate: 765.90 kb/s received Connnection Times (ms) min avg max Connect: 0 2 645 Processing: 112 140 7074 Total: 112 142 7719 [root@netninja /root]# /usr/sbin/ab -k -n 10000 -c 60 http://localhost:80/index.html This is ApacheBench, Version 1.3c <$Revision: 1.38 $> apache-1.3 Copyright (c) 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/ Copyright (c) 1998-1999 The Apache Group, http://www.apache.org/ Benchmarking localhost (be patient)... Server Software: Apache/1.3.12 Server Hostname: localhost Server Port: 80 Document Path: /index.html Document Length: 1358 bytes Concurrency Level: 60 Time taken for tests: 23.353 seconds Complete requests: 10000 Failed requests: 0 Keep-Alive requests: 10020 Total transferred: 18322620 bytes HTML transferred: 13607160 bytes Requests per second: 428.21 Transfer rate: 784.59 kb/s received Connnection Times (ms) min avg max Connect: 0 1 365 Processing: 134 137 139 Total: 134 138 504 [root@netninja /root]# /usr/sbin/ab -n 10000 -c 60 http://localhost:80/index.html This is ApacheBench, Version 1.3c <$Revision: 1.38 $> apache-1.3 Copyright (c) 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/ Copyright (c) 1998-1999 The Apache Group, http://www.apache.org/ Benchmarking localhost (be patient)... Server Software: Apache/1.3.12 Server Hostname: localhost Server Port: 80 Document Path: /index.html Document Length: 1358 bytes Concurrency Level: 60 Time taken for tests: 35.188 seconds Complete requests: 10000 Failed requests: 0 Total transferred: 17945820 bytes HTML transferred: 13607160 bytes Requests per second: 284.19 Transfer rate: 510.00 kb/s received Connnection Times (ms) min avg max Connect: 71 102 476 Processing: 133 107 148 Total: 204 209 624 [root@netninja /root]# /usr/sbin/ab -n 10000 -c 60 http://localhost:80/index.html This is ApacheBench, Version 1.3c <$Revision: 1.38 $> apache-1.3 Copyright (c) 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/ Copyright (c) 1998-1999 The Apache Group, http://www.apache.org/ Benchmarking localhost (be patient)... Server Software: Apache/1.3.12 Server Hostname: localhost Server Port: 80 Document Path: /index.html Document Length: 1358 bytes Concurrency Level: 60 Time taken for tests: 34.890 seconds Complete requests: 10000 Failed requests: 0 Total transferred: 17945820 bytes HTML transferred: 13607160 bytes Requests per second: 286.62 Transfer rate: 514.35 kb/s received Connnection Times (ms) min avg max Connect: 71 102 176 Processing: 133 105 97 Total: 204 207 273 ========= Catalina Benchmarks ===================== [jason@netninja jason]$ /usr/sbin/ab -k -n 10000 -c 60 http://localhost:8080/index.html This is ApacheBench, Version 1.3c <$Revision: 1.38 $> apache-1.3 Copyright (c) 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/ Copyright (c) 1998-1999 The Apache Group, http://www.apache.org/ Benchmarking localhost (be patient)... Server Software: Apache Server Hostname: localhost Server Port: 8080 Document Path: /index.html Document Length: 1358 bytes Concurrency Level: 60 Time taken for tests: 46.361 seconds Complete requests: 10000 Failed requests: 0 Keep-Alive requests: 0 Total transferred: 15869538 bytes HTML transferred: 13588148 bytes Requests per second: 215.70 Transfer rate: 342.30 kb/s received Connnection Times (ms) min avg max Connect: 0 80 491 Processing: 19 197 371 Total: 19 277 862 [jason@netninja jason]$ /usr/sbin/ab -k -n 10000 -c 60 http://localhost:8080/index.html This is ApacheBench, Version 1.3c <$Revision: 1.38 $> apache-1.3 Copyright (c) 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/ Copyright (c) 1998-1999 The Apache Group, http://www.apache.org/ Benchmarking localhost (be patient)... Server Software: Apache Server Hostname: localhost Server Port: 8080 Document Path: /index.html Document Length: 1358 bytes Concurrency Level: 60 Time taken for tests: 44.273 seconds Complete requests: 10000 Failed requests: 0 Keep-Alive requests: 0 Total transferred: 15880808 bytes HTML transferred: 13597654 bytes Requests per second: 225.87 Transfer rate: 358.70 kb/s received Connnection Times (ms) min avg max Connect: 0 102 268 Processing: 38 162 324 Total: 38 264 592 [jason@netninja jason]$ /usr/sbin/ab -n 10000 -c 60 http://localhost:8080/index.html This is ApacheBench, Version 1.3c <$Revision: 1.38 $> apache-1.3 Copyright (c) 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/ Copyright (c) 1998-1999 The Apache Group, http://www.apache.org/ Benchmarking localhost (be patient)... Server Software: Apache Server Hostname: localhost Server Port: 8080 Document Path: /index.html Document Length: 3182 bytes Concurrency Level: 60 Time taken for tests: 43.665 seconds Complete requests: 10000 Failed requests: 0 Total transferred: 34168200 bytes HTML transferred: 31883640 bytes Requests per second: 229.02 Transfer rate: 782.51 kb/s received Connnection Times (ms) min avg max Connect: 2 126 271 Processing: 240 134 32 Total: 242 260 303 [jason@netninja jason]$ /usr/sbin/ab -n 10000 -c 60 http://localhost:8080/index.html This is ApacheBench, Version 1.3c <$Revision: 1.38 $> apache-1.3 Copyright (c) 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/ Copyright (c) 1998-1999 The Apache Group, http://www.apache.org/ Benchmarking localhost (be patient)... Server Software: Apache Server Hostname: localhost Server Port: 8080 Document Path: /index.html Document Length: 3182 bytes Concurrency Level: 60 Time taken for tests: 43.818 seconds Complete requests: 10000 Failed requests: 0 Total transferred: 34168200 bytes HTML transferred: 31883640 bytes Requests per second: 228.22 Transfer rate: 779.78 kb/s received Connnection Times (ms) min avg max Connect: 2 122 262 Processing: 230 139 39 Total: 232 261 301 ================================================= Other Notes About The Tests In my tests, the client (ApacheBench) and the server were both run on the same machine (I needed it to be mobile). That means that the system running the server is also busy due to the client's resource needs. I would like to re-run these tests as two separate machines: one for the client and one for the server. That way, the numbers can more closely indicate the performance of the servers on the machine the test was run on. Running the client on the same machine as the server shouldn't be unfair to either server, since the client is the same in both tests. But, to be sure, it's best to eliminate the client and isolate just the server. Also, all tests ran over local loopback network connections, not over ethernet. Something about ab that I noticed was that it does not implement a true HTTP 1.1 client -- only an HTTP 1.0 client that does 1.0 keepalive connections. Also, ab's numbers didn't always make sense. Sometimes the maximum times were smaller than the minimum times.. Sometimes the average times were smaller than the minimum times. I don't have an explanation (other than this is a bug in ab), but in general it did seem to give useful benchmark information. In the benchmark run output of ab, it always says "Server Software: Apache", even if the server isn't Apache. This is another bug in ab. For the Catalina benchmarks, the first test after a fresh run of the server will always be slow, since the Java VM needs a small amount of running time to utilize the VM's runtime optimization features. It natively compiles classes and methods that are deemed to be the busy spots of the code (or the "HotSpots"), and after they're natively compiled the server runs faster. The longer the server runs, the faster it runs, until the point where most everything is natively compiled (at which time, everything runs its fastest). I made no attempt here to compare the memory footprints of these two servers. It may not be easy to determine how much memory Apache uses for its pool of 50 or more httpd processes (it's dynamic). Nowadays, with the low price of RAM, it's usually not a problem to give the servers the memory they need. But, in the case where you are low on RAM, a good comparison between the two memory footprints (and the characteristics of dynamic memory usage choices each offers) is a good idea. Finally, both servers could probably be further optimized for speed. For instance, Apache could be compiled with gcc optimization turned on (it's turned off by default in the stock build files), and the binaries could have been stripped of symbol names, although I'm not sure that helps with compiled C/C++ performance. Catalina could also be compiled without debugging information in the .class files, which does help a bit with performance (that's also turned off by default, since without line numbers it becomes tough to diagnose and fix any problems an administrator might run into. Also by running a class "obfuscator" on the compiled class files, most of the symbol names are reduced to three or four character names, which makes the classes smaller and faster. I will likely run more tests to see if turning all of this on for both will make either of them perform substantially better (I doubt that it will), and I encourage others to try the same. Conclusion The characteristics of each server are quite different. Apache 1.3 handles requests by preforking server processes in a pool of server processes, whereas Catalina uses Java threads all running in one process. Memory usage is different. But, the benchmark numbers show that the performance difference between the two servers (for my tests, anyway) is about 50%, meaning that each request took Catalina an average of about 90 milliseconds longer to serve. That's a difference of less than a tenth of a second. While Catalina's raw performance on static content isn't yet faster than Apache, It's not very far behind, and it's probably more than adequate for most uses. Many people using Tomcat are using it behind Apache (or another third- party web server). This means that they must compile a native code module into Apache (like mod_jserv, mod_jk, or the new mod_webapp) and run both Apache and Catalina simultaneously so that they can serve both static and dynamic content. While this setup is common and functional, it has the following drawbacks: 1) it takes up more memory -- they must run both servers instead of just one. 2) it creates a performance drain due to the inter-server communication that must happen per request. 3) if Catalina is set up on a machine other than the one on which Apache runs, all requests must again go over ethernet to get to Catalina. Even though this may be a fast internal net, it does slow down the request somewhat. This means they may lose most of the advantage of running Apache (for performance reasons) in the first place. 4) it is harder to maintain since you are running two different servers, plus a native code module that may have versioning conflicts and/or incompatibilities between the two servers. So, even though they may gain some features by running Apache as their first-contact web server, they may in fact lose some performance due to running both servers and sending requests over the link between the two. And, there are more drawbacks to this setup that I haven't listed above. More benchmarking would be helpful, especially with a different number of concurrent clients, and even with different kinds of content (both static and dynamic). Special thanks to Roy Wilson who pointed out ApacheBench to all of us on the tomcat-dev list, and also to those who have written all of this great open source software!