Configure Apache and Tomcat severs together

The most common way to deploy your application in the production environment is to hide the Tomcat behind Apache. This has good and bad parts but it gives you a lot of flexibility and support from Apache. There are a couple of alternatives to put these two severs together:

Using mod_proxy

Create your own tomcat-httpd.conf file and configure the proxy:

#
# Server will not close the connection after each request allowing the browser to use the same connection
#
KeepAlive On
MaxKeepAliveRequests 100
KeepAliveTimeout 5

#
# Load mod_proxy modules
#
<IfModule !proxy_module>
LoadModule proxy_module modules/mod_proxy.so
</IfModule>

<IfModule !proxy_http_module>
LoadModule proxy_http_module modules/mod_proxy_http.so
</IfModule>

ProxyRequests Off
ProxyPreserveHost On
ProxyTimeout 1000
TimeOut 1000

#
# Configure the mod_proxy
#
ProxyPass / http://127.0.0.1:8080/
ProxyPassReverse / http://127.0.0.1:8080/

Include your configuration into Apache httpd.conf using Include directive:

#load Tomcat proxy configuration
Include /usr/local/tomcat6/conf/tomcat-httpd.conf

Using mod_proxy_ajp

The only difference between mod_proxy and mod_proxy_ajp is that you have to load mod_proxy_ajp and proxy the request to Tomcat using the ajp protocol.

#
# Load mod_proxy modules
#
<IfModule !proxy_module>
LoadModule proxy_module modules/mod_proxy.so
</IfModule>

<IfModule !proxy_http_module>
LoadModule proxy_http_module modules/mod_proxy_http.so
</IfModule>

<IfModule !proxy_ajp_module>
LoadModule proxy_ajp_module modules/mod_proxy_ajp.so
</IfModule>

ProxyRequests Off
ProxyPreserveHost On
ProxyTimeout 1000
TimeOut 1000
#
# Enable the AJP proxy
#
ProxyPass / ajp://localhost:8009/
ProxyPassReverse / ajp://localhost:8009/

Include your configuration into Apache httpd.conf using Include directive:

#load Tomcat proxy configuration
Include /usr/local/tomcat6/conf/tomcat-httpd.conf

Using mod_jk

Edit your tomcat-httpd.conf file and add mod_jk configuration:

#
# Load mod_jk is is not loaded already
#
<IfModule !jk_module>
LoadModule jk_module modules/mod_jk.so
</IfModule>
#
#
#
JkWorkersFile /etc/httpd/conf/workers.properties
JkLogFile /var/logs/httpd/mod_jk.log
JkLogLevel info
JkLogStampFormat "[%a %b %d %H:%M:%S %Y] "
JkOptions +ForwardKeySize +ForwardURICompat -ForwardDirectories
JkRequestLogFormat "%w %V %T"
JkMount /test/* worker1

Include your configuration into Apache httpd.conf using Include directive:

#load mod_jk configuration configuration
Include /usr/local/tomcat6/conf/tomcat-httpd.conf

Now edit the workers.properties and configure your worker:

worker.list=worker1
worker.worker1.type=ajp13
worker.worker1.host=localhost
worker.worker1.port=8009
worker.worker1.connection_pool_size=150
worker.worker1.connection_pool_timeout=600
worker.worker1.socket_keepalive=1

Test each configuration using Apache Benchmark tool

Apache benchmark it is a great tool for testing the above configurations. All you need is to create a typical application page that should be hit with the ab tool. This tool takes a single url and makes requests repeatedly in separates threads. The number of threads is controlled by command line arguments. It also supports keep alive connections.

For more details about Apache Benchmark check this page Apache Benchmark

For testing purposes i have created a test war which has a test.jsp page. Because what we test does not influence the processing time overall we don’t need a complete test which includes a database call or working with certain frameworks. In the end all we need is the output of an application and to test how this output reach the browser using one of the three modes explained in the section above.

The test page will include a previous post of mine which is medium size: http://www.bserban.org/2009/05/put-together-struts2-jpa-hibernate-and-spring/. I have right-clicked in the browser, chosen the view source and copy and paste the content into test.jsp. The file has 112Kb in size.


bserban-mac:~ bserban$ ls -la ~/bin/srv/apache-tomcat-5.5.27/webapps/test/test.jsp
-rw-r–r–  1 bserban  staff  113698 Aug  7 09:39 /Users/bserban/bin/srv/apache-tomcat-5.5.27/webapps/test/test.jsp

I am going to hit the Tomcat and the Apache with 10,000 request using 50 threads. The ab command looks like this:


ab -k -n 10000 -c 50 http://localhost/test/test.jsp

To access directly the Tomcat i am going to hit the 8080 port. To preserve the similar enviroment and test conditions I will restart the Apache and Tomcat after each test.

Test results

The table below summarize the results obtained.

Direct mode_proxy mode_proxy_ajp
Throughput 992 reg/s 667 req/s 702 req/s
Average Response Time 50 ms 75 ms 71 ms
90% Response line 75 ms 90 ms 71 ms
100% Response line 207 ms 980 ms 972 ms

As you see, the fastest connecting mode is to connect directly to tomcat using HTTP. Direct HTTP connect will server more request per second that the other modes. The second choice is mode_proxy_ajp followed very closely by the mod_proxy. However the overhead added the the Apache will leverage for real life applications because the application processing time will minimize the impact of using Apache in front of Tomcat. Probably in real world the differences between direct HTTP connect and mod_proxy_ajp will not exceed 5-10% percents in terms of throughput and average time per request. This is the price to pay for the flexibility brought by Apache, because having the Apache in front of the Tomcat will give access to the whole Apache functionality and support.

For those who want to see test results in detail, I included in the post the tests logs.

Test result trace for Tomcat HTTP

bserban-mac:~ bserban$ ab -k -n 10000 -c 50 http://localhost:8080/test/test.jsp
This is ApacheBench, Version 2.3 <$Revision: 655654 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking localhost (be patient)
Completed 1000 requests
Completed 2000 requests
Completed 3000 requests
Completed 4000 requests
Completed 5000 requests
Completed 6000 requests
Completed 7000 requests
Completed 8000 requests
Completed 9000 requests
Completed 10000 requests
Finished 10000 requests

Server Software:        Apache-Coyote/1.1
Server Hostname:        localhost
Server Port:            8080

Document Path:          /test/test.jsp
Document Length:        113678 bytes

Concurrency Level:      50
Time taken for tests:   10.079 seconds
Complete requests:      10000
Failed requests:        0
Write errors:           0
Keep-Alive requests:    0
Total transferred:      1139157786 bytes
HTML transferred:       1137007356 bytes
Requests per second:    992.18 [#/sec] (mean)
Time per request:       50.394 [ms] (mean)
Time per request:       1.008 [ms] (mean, across all concurrent requests)
Transfer rate:          110376.03 [Kbytes/sec] received

Connection Times (ms)
min  mean[+/-sd] median   max
Connect:        0    7   7.3      5      67
Processing:     5   43  22.4     37     182
Waiting:        0   16  19.9     11     161
Total:          7   50  22.4     45     207

Percentage of the requests served within a certain time (ms)
50%     45
66%     52
75%     57
80%     61
90%     75
95%     91
98%    119
99%    147
100%    207 (longest request)

Test result trace for mod_proxy_ajp

bserban-mac:~ bserban$ ab -k -n 10000 -c 50 http://localhost/test/test.jsp
This is ApacheBench, Version 2.3 <$Revision: 655654 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking localhost (be patient)
Completed 1000 requests
Completed 2000 requests
Completed 3000 requests
Completed 4000 requests
Completed 5000 requests
Completed 6000 requests
Completed 7000 requests
Completed 8000 requests
Completed 9000 requests
Completed 10000 requests
Finished 10000 requests

Server Software:
Server Hostname:        localhost
Server Port:            80

Document Path:          /test/test.jsp
Document Length:        113678 bytes

Concurrency Level:      50
Time taken for tests:   14.251 seconds
Complete requests:      10000
Failed requests:        0
Write errors:           0
Keep-Alive requests:    0
Total transferred:      1140884936 bytes
HTML transferred:       1139000800 bytes
Requests per second:    701.70 [#/sec] (mean)
Time per request:       71.256 [ms] (mean)
Time per request:       1.425 [ms] (mean, across all concurrent requests)
Transfer rate:          78179.54 [Kbytes/sec] received

Connection Times (ms)
min  mean[+/-sd] median   max
Connect:        0    7   8.3      5      87
Processing:     6   64  89.8     47     967
Waiting:        0   38  86.9     21     920
Total:          6   71  89.4     52     972

Percentage of the requests served within a certain time (ms)
50%     52
66%     58
75%     64
80%     69
90%     83
95%    115
98%    507
99%    689
100%    972 (longest request)

Test result trace for mod_proxy

bserban-mac:~ bserban$ ab -k -n 10000 -c 50 http://localhost/test/test.jsp
This is ApacheBench, Version 2.3 <$Revision: 655654 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking localhost (be patient)
Completed 1000 requests
Completed 2000 requests
Completed 3000 requests
Completed 4000 requests
Completed 5000 requests
Completed 6000 requests
Completed 7000 requests
Completed 8000 requests
Completed 9000 requests
Completed 10000 requests
Finished 10000 requests

Server Software:        Apache-Coyote/1.1
Server Hostname:        localhost
Server Port:            80

Document Path:          /test/test.jsp
Document Length:        113678 bytes

Concurrency Level:      50
Time taken for tests:   14.985 seconds
Complete requests:      10000
Failed requests:        0
Write errors:           0
Keep-Alive requests:    0
Total transferred:      1140715856 bytes
HTML transferred:       1138561771 bytes
Requests per second:    667.34 [#/sec] (mean)
Time per request:       74.925 [ms] (mean)
Time per request:       1.498 [ms] (mean, across all concurrent requests)
Transfer rate:          74339.90 [Kbytes/sec] received

Connection Times (ms)
min  mean[+/-sd] median   max
Connect:        0    9  10.1      5     123
Processing:     9   66  83.2     52     975
Waiting:        0   41  83.7     27     949
Total:          9   74  82.6     59     980

Percentage of the requests served within a certain time (ms)
50%     59
66%     66
75%     72
80%     76
90%     98
95%    123
98%    192
99%    675
100%    980 (longest request)

Comments

One Response to “Configure Apache and Tomcat severs together”

  1. Marshall Moritomo on November 6th, 2009 5:48 pm

    Thank you very much for providing this information and making it free. I was able to test this and works as stated. After my experience, upgrading from Apache2.0 to Apache2.2 and using proxypass has increased our response times by 30x. Not to mention it is much easy to administer and a lot less configuration files/steps.