|
Starting Tomcat from another directory
By default Tomcat will use TOMCAT_HOME/conf/server.xml for configuration. The default
configuration will use TOMCAT_HOME as it's base for the contexts.
You can change this by using the "-f /path/to/server.xml" option, with a
different server configuration file and setting the home property of
the context manger. You need to set up the required files inside the
home:
- A webapps/ directory (if you created one) - all war files will
be expanded and all subdirectories added as contexts.
- conf/ directory - you can store a special web.xml and other
configuration files.
- logs/ - all logs will go to this directory instead of the main
TOMCAT_HOME/logs/.
- work/ - work directories for the contexts.
If the ContextManager.home property in server.xml is relative, it
will be relative to the current working directory.
web.xml
A detailed description of web.xml and the web application structure
(including directory structure and configuration) is available in
chapters 9, 10 and 14 of the
Servlet API Spec
and we are not going to write about it.
There is however a small Tomcat related "feature" that is related
to web.xml. Tomcat lets the user define default web.xml values for all
context by putting a default web.xml file in the conf directory. When
constructing a new Context, Tomcat uses the default web.xml file as the
base configuration and the application specific web.xml (the one located
in the application's WEB-INF/web.xml), only overwrite these defaults.
Setting Tomcat to cooperate with the Apache web server
Up until now we have not discussed Tomcat as a server add on,
instead we have considered it as a stand-alone container and discussed
how it can be used. There are however a few problems with this
picture:
- Tomcat is not as fast as Apache when it comes to static pages.
- Tomcat is not as configurable as Apache.
- Tomcat is not as robust as Apache.
- There are many sites with long time investment in certain web servers,
for example, sites that are using CGI scripts/Server API modules/perl/php...
We cannot assume that all of them will want to ditch this legacy.
For all these reasons it is recommended that real world sites
use a web server, such as Apache, for serving the static content of
the site, and use Tomcat as a Servlet/JSP add-on.
We are not going to cover the different configuration in
depth, instead we will:
- Cover the fundamental behavior of the web server.
- Explain what configuration is needed.
- Demonstrate this on Apache.
Web server operation
In a nutshell a web server is waiting for client HTTP requests.
When these requests arrive the server does whatever is needed to
serve the requests by providing the necessary content. Adding a
servlet container may somewhat change this behavior. Now the web
server needs also to perform the following:
- Load the servlet container adapter library and initialize it (prior
to serving requests).
- When a request arrives, it needs to check and see if a certain
request belongs to a servlet, if so it needs to let the adapter
take the request and handle it.
The adapter on the other hand needs to know what requests it is
going to serve, usually based on some pattern in the request URL, and to
where to direct these requests.
Things are even more complex when the user wants to set a configuration
that uses virtual hosts, or when they want multiple developers to work
on the same web server but on different servlet container JVMs. We
will cover these two cases in the advanced sections.
What is the needed configuration
The most obvious configuration that one can think of is the identity of the servlet URLs
that are under the responsibility of the servlet container. This is clear; someone must
know what requests to transmit to the servlet container...
Yet there are additional configuration items that we should provide to
the web-server/servlet-container combination:
- We also need to provide configuration regarding the available Tomcat processes
and on which TCP/IP host/port they are listening.
- We need to tell the web server the location of the adapter library (so it
will be able to load it on startup).
- We need to set adapter internal information such as where and how much to log, etc.
All this information must appear either in the web server configuration, or in a private
configuration files used by the adapter. The next section will demonstrate how configuration
can be implemented on Apache.
Making it on Apache
This section shows you how to configure Apache to work with Tomcat;
it tries to provide explanations as well as insight for the
configuration directives that you should use. You can find
additional information in the
jserv install page .
When Tomcat starts up it will automatically generate a configuration
file for Apache in TOMCAT_HOME/conf/tomcat-apache.conf. Most
of the time you don't need to do anything but include this file
(appending "Include TOMCAT_HOME/conf/tomcat-apache.conf") in your
httpd.conf. If you have special needs, for example an AJP port other
the 8007, you can use this file as a base for your customized
configuration and save the results in another file. If you manage
the Apache configuration yourself you'll need to update it whenever
you add a new context.
Tomcat 3.1: you must restart Tomcat and apache after adding
a new context; Apache doesn't support configuration changes without a
restart. Also the file TOMCAT_HOME/conf/tomcat-apache.conf is
generated when Tomcat starts, so you'll need to start Tomcat before
Apache. Tomcat will overwrite TOMCAT_HOME/conf/tomcat-apache.conf
each startup so customized configuration should be kept elsewhere.
The Apache-Tomcat configuration uses Apache core configuration directives
as well as Jserv unique directives so it may confuse you at first, there are
however two things simplifying it:
- In general you can distinguish between the two directive
"families" by noting that all the Jserv unique directives start
with an "Ajp" prefix.
- The entire Tomcat related configuration is concentrated in a
single configuration file named tomcat.conf, or the automatically
generated tomcat-apache.conf, so you can look at a single file.
Let's look now at a sample tomcat.conf file.
A minimalistic Apache-Tomcat configuration
###########################################################
# A minimalistic Apache-Tomcat Configuration File #
###########################################################
# Note: this file should be appended or included into your httpd.conf
# (1) Loading the jserv module that serves as Tomcat's apache adapter.
LoadModule jserv_module libexec/mod_jserv.so
# (1a) Module dependent configuration.
<IfModule mod_jserv.c>
# (2) Meaning, Apache will not try to start Tomcat.
ApJServManual on
# (2a) Meaning, secure communication is off
ApJServSecretKey DISABLED
# (2b) Meaning, when virtual hosts are used, copy the mount
# points from the base server
ApJServMountCopy on
# (2c) Log level for the jserv module.
ApJServLogLevel notice
# (3) Meaning, the default communication protocol is ajpv12
ApJServDefaultProtocol ajpv12
# (3a) Default location for the Tomcat connectors.
# Located on the same host and on port 8007
ApJServDefaultHost localhost
ApJServDefaultPort 8007
# (4)
ApJServMount /examples /root
# Full URL mount
# ApJServMount /examples ajpv12://hostname:port/root
</IfModule>
|
As you can see the configuration process was split into 4 steps
that will now be explained:
- In this step we instruct Apache to load the jserv
shared-object (or the NT world dll). This is a well known Apache
directive. If the loading went well and the module came from a
file named mod_jserv.c (1a) we can start with the rest of the
Jserv-Tomcat configuration.
- This step sets various Jserv internal parameters, these
parameters:
- Instruct jserv not to start the Tomcat process. Automatically
starting Tomcat is not implemented yet.
- Disable the secret key challenge/response between Apache and Tomcat.
Again, the secret key work is not implemented yet.
- Instruct jserv to copy the base server mount points (see next
section) in case of virtual hosting.
- Instruct jserv to use the notice log level. Other log levels
include emerg, alert, crit, error, warn, info and debug.
- This step sets the default communication parameters.
Basically it says that the default protocol used for the communication
is ajpv12 (do not mess with this one) and that the Tomcat process runs on
the same machine and listens on port 8007. If you run Tomcat on a
machine other than the one used
for Apache you should either update your ApJServDefaultHost or use a full
URL when mounting contexts (see next). Also, if you configured the Tomcat
connectors to use a port other then 8007, you should update your
ApJServDefaultPort or use a full URL when mounting contexts.
- This step mounts a context to Tomcat. Basically it says that
all the web server paths that start with /examples go to Tomcat. This
ApJServMount example is a rather simple one, in fact ApJServMount can
also provide information regarding the communication protocol to be used
and the location where the Tomcat process listens, for example:
ApJServMount /examples ajpv12://hostname:port/root
mounts the context /examples to a Tomcat process that runs on host
"hostname" and listens on port number "port".
Now that you understand the different configuration instructions in the sample
file, how can you add it to the Apache configuration? One "simple" method is to
write it's content in the httpd.conf (the Apache configuration file), this however
can be very messy. Instead you should use the Apache include directive. At the end
of the Apache configuration file (httpd.conf) add the following directive:
include <full path to the Tomcat configuration file>
for example:
include /tome/tomcat/conf/tomcat.conf This
will add your Tomcat configuration to Apache, after that you should copy
the jserv module to the Apache libexec (or modules in the Win32 case)
directory and restart (stop+start) Apache. It should now be able to
connect to Tomcat.
Obtaining the Jserv Module (mod_jserv)
As previously stated, we need a web server adapter to sit in Apache and redirect
requests to Tomcat. For Apache, this adapter is a slightly modified version of
mod_jserv.
You may try to look
here and see if there is an already pre-built version of mod_jserv that
suites your OS (Usually there is one for NT), however, being a native library you
should not expect that yet (too many OS's, not enough developers, life
too short...).
Moreover, small variations in the way you built Apache/Your specific UNIX® variant may
result in dynamic linking errors. You should really try to build mod_jserv for your
system (don't panic, it is not that hard!).
Building mod_jserv on UNIX involves the following:
- Download the source distribution of Tomcat from
here.
- Uncompress it into some directory.
- Building the module:
Building mod_jserv for Win32 is less likely (you already have a downloadable dll
for Win32). Yet if you want to build it you should install Visual C++ and
perform the following:
- Download the source distribution of Tomcat from
here.
- Unzip it into some directory.
- Building the module:
- Change directory into jakarta-tomcat\src\native\apache\jserv
- Add Visual C++ into your environment by executing the script
VCVARS32.BAT.
- Execute the build command
nmake -f Makefile.win32
nmake is the Visual C++ make program.
That's it; you have built mod_jserv...
Making Apache serve your context's static files
The previous Apache-Tomcat configuration file was somewhat
inefficient, it instructed Apache to send any request for a resource
that starts with the /examples prefix to be served by
Tomcat. Do we really want that? There are many static files that may
be a part of our servlet context (for example images and static
HTML), why should Tomcat serve these files?
You may actually have reasons for doing that, for example:
- You may want to configure Tomcat based security for these
resources.
- You may want to follow users requests for static resources
using interceptors.
In general however, this is not that case; and making Tomcat save
static files is just a CPU waste. We should instead have Apache serve
these static files and not Tomcat. Lets look now at a sample
tomcat.conf file that does exactly that:
Having Apache serve the static files requires the following:
- Instructing Apache to send all servlet requests to Tomcat.
- Instructing Apache to send all JSP requests to Tomcat.
and leaving Apache to handle the rest. Lets look now at a sample
tomcat.conf file that does exactly that:
Apache-Tomcat configuration where Apache serves the static content
######################################################################
# Apache-Tomcat Smart Context Redirection #
######################################################################
LoadModule jserv_module modules/ApacheModuleJServ.dll
<IfModule mod_jserv.c>
ApJServManual on
ApJServDefaultProtocol ajpv12
ApJServSecretKey DISABLED
ApJServMountCopy on
ApJServLogLevel notice
ApJServDefaultHost localhost
ApJServDefaultPort 8007
#
# Mounting a single smart context:
#
# (1) Make Apache know about the context location.
Alias /examples D:\tomcat\webapps\examples
# (2) Optional, customize Apache context service.
<Directory "D:\tomcat\webapps\examples">
Options Indexes FollowSymLinks
# (2a) No directory indexing for the context root.
# Options -Indexes
# (2b) Set index.jsp to be the directory index file.
# DirectoryIndex index.jsp
</Directory>
# (3) Protect the WEB-INF directory from tampering.
<Location /examples/WEB-INF/>
AllowOverride None
deny from all
</Location>
# (4) Instructing Apache to send all the .jsp files under the context to the
# jserv servlet handler.
<LocationMatch /examples/*.jsp>
SetHandler jserv-servlet
</LocationMatch>
# (5) Direct known servlet URLs to Tomcat.
ApJServMount /examples/servlet /examples
# (6) Optional, direct servlet only contexts to Tomcat.
ApJServMount /servlet /ROOT
</IfModule>
|
As you can see, the beginning of this configuration file is the same
as seen in the previous example. The last step (mounting a context),
however, was replaced in a long series of Apache and Ajp
configuration directives that will now be explained:
- This step informs Apache of the context location and aliases it
to an Apache virtual directory. This way Apache can serve files
from this directory.
- This optional step instructs Apache more about how to serve the
context; for example you can decide if Apache will allow
directory indexing (listing) or set a special index file.
- This step instructs Apache to protect the WEB-INF directory
from client access. For security reasons it is important to
prevent visitors from viewing the content of the WEB-INF
directory, for example web.xml can provide valuable information
for intruders. This step blocks the WEB-INF content from
visitors.
- This step instructs Apache to serve all the jsp locations
within the context using the jserv servlet handler. The servlet
handler redirects these requests based on the default host and
port.
- This step mounts specific servlet URLs to Tomcat. You should
note that you should have as many such mount directives as the
number of specific servlet URLs.
- This last step is an example for the addition of servlet only
context to Tomcat.
It is easy to see that this configuration is much more complex and
error prone then the first example, this however is the price that you
should (for now) pay for improved performance.
Configuring for multiple Tomcat JVMs
Sometimes it is useful to have different contexts handled by
different JVMs, for example:
- When each context serves a different, specific task and runs
on a different machine.
- When we want to have multiple developers work on a private
Tomcat process but use the same web server.
Implementing such schemes where different contexts are served by
different JVMs is very easy and the following configuration file
demonstrates this:
Apache-Tomcat configuration with per context JVM
######################################################################
# Apache-Tomcat with JVM per Context #
######################################################################
LoadModule jserv_module modules/ApacheModuleJServ.dll
<IfModule mod_jserv.c>
ApJServManual on
ApJServDefaultProtocol ajpv12
ApJServSecretKey DISABLED
ApJServMountCopy on
ApJServLogLevel notice
ApJServDefaultHost localhost
ApJServDefaultPort 8007
# Mounting the first context.
ApJServMount /joe ajpv12://joe.corp.com:8007/joe
# Mounting the second context.
ApJServMount /bill ajpv12://bill.corp.com:8007/bill
</IfModule>
|
As you can see in the previous example, using several JVMs (even even
those that run on different machines) can be accomplished easily by
using a full Ajp URL mount. In this full URL we actually specify the
host where the Tomcat process is located and it's port.
Had the two Tomcat processes run on the same machine, we would have to
configure each of them with different connector ports. For example,
assuming that the two JVMs runs on localhost, the Apache-Tomcat
configuration should have something that looks like:
Same machine multiple JVM Apache-Tomcat configuration
######################################################################
# Apache-Tomcat with Same Machine JVM per Context #
######################################################################
LoadModule jserv_module modules/ApacheModuleJServ.dll
<IfModule mod_jserv.c>
ApJServManual on
ApJServDefaultProtocol ajpv12
ApJServSecretKey DISABLED
ApJServMountCopy on
ApJServLogLevel notice
ApJServDefaultHost localhost
ApJServDefaultPort 8007
# Mounting the first context.
ApJServMount /joe ajpv12://localhost:8007/joe
# Mounting the second context.
ApJServMount /bill ajpv12://localhost:8009/bill
</IfModule>
|
Looking at the above file you can see that we have two explicit Ajp
mount points each pointing to a different port on the same machine. It
is clear that this configuration requires support from the configuration
found in the server.xml files. We will need in these files different
<Connector> configurations, for the different Tomcat processes. We
will actually need two different server.xml files (lets call them
server_joe.xml and server_bill.xml) with different <Connector>
entries as shown in the next two samples:
Joe's server.xml file
<?xml version="1.0" encoding="ISO-8859-1"?>
<Server>
<!-- Debug low-level events in XmlMapper startup -->
<xmlmapper:debug level="0" />
<!-- @@@
Note, the log files are suffixed with _joe to distinguish
them from the bill files.
-->
<Logger name="tc_log"
path="logs/tomcat_joe.log"
customOutput="yes" />
<Logger name="servlet_log"
path="logs/servlet_joe.log"
customOutput="yes" />
<Logger name="JASPER_LOG"
path="logs/jasper_joe.log"
verbosityLevel = "INFORMATION" />
<!-- @@@
Note, the work directory is suffixed with _joe to distinguish
it from the bill work directory.
-->
<ContextManager debug="0" workDir="work_joe" >
<!-- Context level Setup -->
<ContextInterceptor
className="org.apache.tomcat.context.AutoSetup" />
<ContextInterceptor
className="org.apache.tomcat.context.DefaultCMSetter" />
<ContextInterceptor
className="org.apache.tomcat.context.WorkDirInterceptor" />
<ContextInterceptor
className="org.apache.tomcat.context.WebXmlReader" />
<ContextInterceptor
className="org.apache.tomcat.context.LoadOnStartupInterceptor" />
<!-- Request processing -->
<RequestInterceptor
className="org.apache.tomcat.request.SimpleMapper" debug="0" />
<RequestInterceptor
className="org.apache.tomcat.request.SessionInterceptor" />
<RequestInterceptor
className="org.apache.tomcat.request.SecurityCheck" />
<RequestInterceptor
className="org.apache.tomcat.request.FixHeaders" />
<!-- @@@ This connector uses port number 8007 for it's ajp communication -->
<Connector
className="org.apache.tomcat.service.SimpleTcpConnector">
<Parameter
name="handler"
value="org.apache.tomcat.service.connector.Ajp12ConnectionHandler"/>
<Parameter name="port" value="8007"/>
</Connector>
<!-- @@@ the /jow context -->
<Context path="/joe" docBase="webapps/joe" debug="0" reloadable="true" >
</Context>
</ContextManager>
</Server>
|
When looking at server_joe.xml you can see that the
<Connector> is configured for port 8007. In server_bill.xml
(see next) on the other hand the <Connector> is configured for
port 8009.
Bill's server.xml file
<?xml version="1.0" encoding="ISO-8859-1"?>
<Server>
<!-- Debug low-level events in XmlMapper startup -->
<xmlmapper:debug level="0" />
<!-- @@@
Note, the log files are suffixed with _bill to distinguish
them from the joe files.
-->
<Logger name="tc_log"
path="logs/tomcat_bill.log"
customOutput="yes" />
<Logger name="servlet_log"
path="logs/servlet_bill.log"
customOutput="yes" />
<Logger name="JASPER_LOG"
path="logs/jasper_bill.log"
verbosityLevel = "INFORMATION" />
<!-- @@@
Note, the work directory is suffixed with _bill to distinguish
it from the joe work directory.
-->
<ContextManager debug="0" workDir="work_bill" >
<!-- Context level Setup -->
<ContextInterceptor
className="org.apache.tomcat.context.AutoSetup" />
<ContextInterceptor
className="org.apache.tomcat.context.DefaultCMSetter" />
<ContextInterceptor
className="org.apache.tomcat.context.WorkDirInterceptor" />
<ContextInterceptor
className="org.apache.tomcat.context.WebXmlReader" />
<ContextInterceptor
className="org.apache.tomcat.context.LoadOnStartupInterceptor" />
<!-- Request processing -->
<RequestInterceptor
className="org.apache.tomcat.request.SimpleMapper" debug="0" />
<RequestInterceptor
className="org.apache.tomcat.request.SessionInterceptor" />
<RequestInterceptor
className="org.apache.tomcat.request.SecurityCheck" />
<RequestInterceptor
className="org.apache.tomcat.request.FixHeaders" />
<!-- @@@ This connector uses port number 8009 for it's ajp communication -->
<Connector className="org.apache.tomcat.service.SimpleTcpConnector">
<Parameter
name="handler"
value="org.apache.tomcat.service.connector.Ajp12ConnectionHandler"/>
<Parameter name="port" value="8009"/>
</Connector>
<!-- @@@ the /bill context -->
<Context path="/bill" docBase="webapps/bill" debug="0" reloadable="true" >
</Context>
</ContextManager>
</Server>
|
The port configuration is not the only place where the joe and bill
configuration differs. We have @@@ marks in the xml files marking
the four places where changes had to be made. As you can see, this
difference is necessary to avoid the two Tomcat processes from
overwriting each other's logs and workspace.
Then we should start the two Tomcat processes using the -f command
line option:
bin\starup -f conf\server_joe.xml
bin\starup -f conf\server_bill.xml
and then access them from Apache based on the different URL path
prefixes.
Configuring virtual hosting
It is possible to support virtual hosts under Tomcat Ver3.1, in fact
the virtual host configuration is very similar to configuring for
multiple JVM (as explained in the previous section) and the reason
is simple; in Tomcat 3.1 each virtual host is implemented by a
different Tomcat process.
With the current (Ver3.1) Tomcat, virtual hosting awareness is
provided by the web server (Apache/Netscape?). The web server
virtual hosting support is used by the Tomcat adapter to
redirect requests belonging to a certain virtual host to the JVM(s)
containing the contexts of this virtual host. This means that if (for
example) we have two virtual hosts (vhost1 and vhost2), we will have
two JVMs: one running the contexts of vhost1 and the other running
the contexts of vhost2. These JVMs are not aware of each others
existence, in fact, they are not aware of the concept of virtual
hosting. All the virtual hosting logic is inside the web-server
adapter. To make things clearer, lets look at the following sample
Apache-Tomcat configuration file:
Apache-Tomcat configuration with virtual hosts support
######################################################################
# Apache Tomcat Virtual Hosts Sample Configuration #
######################################################################
LoadModule jserv_module modules/ApacheModuleJServ.dll
<IfModule mod_jserv.c>
ApJServManual on
ApJServDefaultProtocol ajpv12
ApJServSecretKey DISABLED
ApJServMountCopy on
ApJServLogLevel notice
ApJServDefaultHost localhost
ApJServDefaultPort 8007
# 1 Creating an Apache virtual host configuration
NameVirtualHost 9.148.16.139
# 2 Mounting the first virtual host
<VirtualHost 9.148.16.139>
ServerName www.vhost1.com
ApJServMount /examples ajpv12://localhost:8007/examples
</VirtualHost>
# 3 Mounting the second virtual host
<VirtualHost 9.148.16.139>
ServerName www.vhost2.com
ApJServMount /examples ajpv12://localhost:8009/examples
</VirtualHost>
</IfModule>
|
As can be seen, steps 1,2 and 3 define two Apache virtual hosts and
for each of them, mount the /examples context to a certain ajpv12 URL.
Each such ajpv12 URL points to a JVM that contains the virtual host.
The configuration of the two JVMs is very similar to the one
demonstrated in the previous section, we will need again to use two
different server.xml files (one for each virtual host process) and
we will need to start the Tomcat processes with the -f command line
option. After doing that we will be able to approach Apache, each
time with a different host name, and the adapter will redirect us to
the appropriate JVM.
The need for improved virtual host support
Having each virtual host implemented by a different JVM is a huge
scalability problem. The next versions of Tomcat will make it
possible to support several virtual hosts within the same Tomcat
JVM.
Real world configuration tips
By default the Tomcat distribution comes with a naive configuration
whose main goal is to promote first time user experience and an "out
of the box" operation... This configuration however is not the best
way to deploy Tomcat on real sites. For example, real sites may
require some performance tuning and site-specific settings
(additional path elements for example). This section will try to get
you started by directing you to the first steps that should be taken
before publishing a Tomcat based site.
Modify and customize the batch files
As stated in the previous sections, the startup scripts are here for
your convenient. Yet, sometimes the scripts that are needed for
deployment should be modified:
- To set resource limits such as maximum number of
descriptors.
- To add new CLASSPATH entries (for example, JDBC drivers).
- To add new PATH/LD_LIBRARY_PATH entries (for example, JDBC
drivers DLLs).
- To modify the JVM command line settings.
- Make sure that you are using a specific JVM (out of the two
or three JVMs installed on your machine).
- To switch user from root to some other user using the "su"
UNIX® command.
- Your pet reason.
Some of these changes can be done without explicit changes to
the basic scripts; for example, the Tomcat script can use an
environment variable named TOMCAT_OPTS to set extra command
line parameters to the JVM (such as memory setting etc.).
On UNIX you can also create a file named ".tomcatrc" in
your home directory and Tomcat will take environment information such
as PATH, JAVA_HOME, TOMCAT_HOME and CLASSPATH from this file. On NT
however (and also on UNIX® when the modifications are for something
such as the JVM command line) you are forced to rewrite some of the
startup script... Do not hesitate, just do it.
Modify the default JVM settings
The default JVM settings in the Tomcat script are very naïve;
everything is left for defaults. There are a few things that you
should consider to improve your Tomcat performance:
- Modify your JVM memory configuration. Normally the JVM
allocates an initial size for the Java heap and that's it, if
you need more then this amount of memory you will not get it.
Nevertheless, in loaded sites, giving more memory to the JVM
improves Tomcat's performance. You should use command line
parameters such as -Xms/-Xmx/-ms/-mx to set the minimum/maximum
size of the Java heap (and check to see if the performance was
improved).
- Modify your JVM threading configuration. The SUN JDK1.2.2 for
Linux comes with support for both, green and native threads. In
general native threads are known to provide improved performance
for I/O bound applications, green threads on the other hand put
less stress on the machine. You should experiment with these two
threading models and see which model is better for your site (in
general, native threads are better).
- Select the best JVM for the task. There are several JVM vendors,
for example on Linux there are today (21/03/2000) two product level
JVMs: the SUN JDK1.2.2 and the IBM JDK1.1.8. If your application
does not require a specific JDK functionality, you should
benchmark the two JVMs and select the better one. In my (Gal
Shachor) internal tests I found the IBM JVM significantly faster
than the one created by SUN, you should check that for yourself
and make a calculated decision.
Modify your connectors
The Connectors, as configured in Tomcat's default server.xml
contains two Connectors configured as in the next server.xml
fragment:
The two default connectors in server.xml
<!-- (1) HTTP Connector for stand-alone operation -->
<Connector className="org.apache.tomcat.service.SimpleTcpConnector">
<Parameter
name="handler"
value="org.apache.tomcat.service.http.HttpConnectionHandler"/>
<Parameter
name="port"
value="8080"/>
</Connector>
<!-- (2) AJPV12 Connector for out-of-processs operation -->
<Connector className="org.apache.tomcat.service.SimpleTcpConnector">
<Parameter
name="handler"
value="org.apache.tomcat.service.connector.Ajp12ConnectionHandler"/>
<Parameter
name="port"
value="8007"/>
</Connector>
|
- Is a Connector that listens on port 8080 for incoming HTTP
requests. This connector is needed for stand-alone
operation.
- Is a Connector that listens on port 8007 for incoming AJPV12
requests. This connector is needed for web-server
integration (out-of-process servlet integration).
It is clear that a sane Tomcat deployment will use either an
out-of-process servlet integration or a stand-alone operation,
removing the unnecessary Connector is important.
Use a thread pool in your connectors
Tomcat is a multi-threaded servlet container this means that each
request needs to be executed by some thread. By default when a
request arrives Tomcat creates a new thread, starts it and has it
serve the request. This behavior is problematic for loaded sites
because:
- Starting and stopping a thread for every request puts a
needless burden on the operating system and the JVM.
- It is hard to limit the resource consumption. If 300
requests arrive concurrently Tomcat will open 300
threads to serve them and allocate all the resources needed
to serve all the 300 requests at the same time. This causes
Tomcat to allocate much more resources (CPU, Memory,
Descriptors...) than it should and it can lead to low
performance and even crashes if resources are exhausted.
The solution for these problems is to use a thread pool.
Servlet containers that are using a thread pool relieve themselves
from directly managing their threads. Instead of allocating new
threads; whenever they need a thread they ask for it from the pool,
and when they are done, the thread is returned to the pool. The
thread pool can now be used to implement sophisticated thread
management techniques, such as:
- Keeping threads "open" and reusing them over and over
again. This saves the trouble associated with creating and
destructing threads continuously.
-
Usually the administrator can instruct the pool not to keep
too many idle threads, freeing them if needed.
- Setting an upper bound on the number of threads used
concurrently. This prevents the resources allocation
problem associated with unlimited thread allocation.
-
If the container maxed out to the threads upper limit, and a new
request arrives, the new request will have to wait for
some other (previous) request to finish and free the thread
used to service it.
You can refine the techniques described above in various ways, but
these are only refinements. The main contribution of thread pools is
thread-reuse and having a concurrency upper bound that limits
resource usage.
Using a thread pool in Tomcat is a simple move; all you need to do
is to use a PoolTcpConnector in your <Connector>
configuration. For example the following server.xml fragment defines
ajpv12, pooled Connector:
Pooled ajpv12 connector
<!-- A pooled AJPV12 Connector for out-of-processs operation -->
<Connector className="org.apache.tomcat.service.PoolTcpConnector">
<Parameter
name="handler"
value="org.apache.tomcat.service.connector.Ajp12ConnectionHandler"/>
<Parameter
name="port"
value="8007"/>
</Connector>
|
This fragment is very simple and the (default) pool behaviour
instructed by it is:
- Upper bound for concurrency of 50 threads.
- When the pool has more then 25 threads standing idle it
will start to kill them.
- The pool will start 10 threads on creation, and it will try
to keep 10 vacant threads (as long as the upper bound is
kept).
The default configuration is suitable for medium load sites with an
average of 10-40 concurrent requests. If your site differs you
should modify this configuration (for example reduce the upper
limit). Configuring the pool can be done through the <Connector>
element in server.xml as demonstrated in the next fragment:
Configuring the thread pool
<!-- A pooled AJPV12 Connector for out-of-processs operation -->
<Connector className="org.apache.tomcat.service.PoolTcpConnector">
<Parameter
name="handler"
value="org.apache.tomcat.service.connector.Ajp12ConnectionHandler"/>
<Parameter
name="port"
value="8007"/>
<Parameter
name="max_threads"
value="30"/>
<Parameter
name="max_spare_threads"
value="20"/>
<Parameter
name="min_spare_threads"
value="5" />
</Connector>
|
As can be seen the pool has 3 configuration parametes:
- max_threads - defines the upper bound to the for the
concurrency, the pool will not create more then this number
of threads.
- max_spare_threads - defines the maximum number of threads
that the pool will keep idle. If the number of idle threads
passes the value of max_spare_threads the pool will kill
these threads.
- min_spare_threads - the pool will try to make sure that at
any time there is at least this number of idle threads
waiting for new requests to arrive. min_spare_threads must
be bigger then 0.
You should use the above parameters to adjust the pool behavior to
your needs.
Disable servlet auto-reloading
Servlet auto-reloading is really useful for development time.
However it is very expensive (in performance degradation terms) and
may put your application in strange conflicts when classes that were
loaded by a certain classloader cannot co-operate with classes
loaded by the current classloader.
So, unless you have a real need for class reloading during your
deployment you should turn off the reloadable flag in your contexts.
Start Tomcat from /etc/inittab
Unfortunately the adapters developed for Apache (or for any of the
other servers) cannot start Tomcat yet. On UNIX® however, you can
use the init table to start Tomcat automatically upon machine
startup. FIXME:
Authors
This document was created by: Gal Shachor
With help from (alphabetical ordered):
Jonathan Bnayahu
Fiona Czuczman
Costin Manolache
Copyright ©1999 The Apache Software Foundation
Legal Stuff They Make Us Say
Contact Information
|