|Oracle9i Application Server Oracle HTTP Server powered by Apache Performance Guide
Release 1 (v22.214.171.124) for AIX-Based Systems, Compaq Tru64 UNIX, HP 9000 Series HP-UX, Linux Intel, and Sun Solaris Intel
Part Number A90444-01
This chapter describes the JServ architecture, and discusses ways you can improve JServ performance. It also includes performance information on OracleJSP pages (the Oracle implementation of Sun Microsystems' JavaServer Pages 1.1.)
Apache JServ is made up of an Apache module called
mod_jserv, which runs in the httpd process, and a servlet engine, which runs in a Java process.
mod_jserv, which is implemented in C, functions as a dispatcher, routing each servlet request to a JServ process for execution.
The servlet engine runs in its own JVM (Java Virtual Machine) and is solely responsible for parsing the request and generating a response. As Figure 5-1 shows, multiple JServs can service requests. The HTTP server process and the JServ process communicate using the Apache JServ Protocol 1.2.
This section discusses strategies for optimizing JServ performance: loading servlets when starting the JVM, and load balancing.
The terms "repository" and "zone" are used in this discussion. Servlets, repositories, and zones are analogous to files, directories and virtual hosts. A servlet is a single unit, a repository is a collection of servlets, and a zone is a collection of repositories.
Apache JServ allows you to load servlet classes when the JVM is started. To do this, put the servlets to load in the
servlets.startup directive in the servlet zone properties file. When the servlet is loaded, its
init()method is called. All other servlets (those not listed in
servlets.startup) are loaded and initialized on first request.
Using this facility increases the start-up time for your JServ process, but improves first-request latency for servlets.
If you are using a JSP as the servlet (your code does not extend
HttpServlet), you will be unable to use this pre-load option, but you could pre-load the JSP runner by including the
If the first-request latency for your initialization routines is really a performance issue, you can achieve some of the results described above by creating a dummy servlet to call your one-time initialization routines in its
init() method. You must add the name of the dummy servlet to
autoreload.classes is set to
true for a zone (the default), then each time one of that zone's servlets is requested, every class that has been loaded from a repository in that zone is checked to see if it has been modified. If one of the classes has changed, then all previously loaded classes from the zone's repositories are unloaded, which means that as the classes are needed, they will be loaded from their class files again.
This is a useful development feature, because you can install new versions or drop in new class files without restarting the server. For optimal performance in production environments, however, you should set both automatic class reloading parameters to false, since there is a performance cost in checking the repositories on every execution of a servlet. Change these parameters in the zone properties file:
It is often beneficial to spread the servlet application load among multiple JServ processes, especially when the application is run on a multiprocessor system or if the servlets and HTTP server are run on separate nodes. Running multiple Apache JServ processes generally results in higher throughput and shorter response time, even on a single-processor host. (See Chapter 3, "Sizing and Configuration" for specific recommendations.)
The mod_oprocmgr module shipped with Release 126.96.36.199 enables you to specify a `auto' setting in
jserv.conf for the ApJServManual directive. mod_oprocmgr provides automatic load balancing and death detection for JServ processes. See Using mod_oprocmgr with mod_jserv in the Oracle9i Application Server documentation library for instructions on using this module.
This section explains how to balance incoming requests between two JServ processes running on the same host as the HTTP server. Examples from the
jserv.properties files are included with the procedures; substitute your own port numbers and directory locations where needed.
With this method of load balancing, you must start and stop processes manually, because JServ cannot automatically start and stop more than one JServ process. (Sample scripts for starting and stopping the JServ processes and the Oracle HTTP Server are included in the
directory.) This means that if a process terminates for any reason, JServ will not restart it. To prevent processes from terminating due to memory shortage, ensure that you have a sufficient maximum heap size set for your JServ processes. See "Determining Java Heap Size".
Each JServ process in your load balancing scheme must be configured to listen on its own port and to log to its own file. If you have a
jserv.properties file containing the parameters needed to run your application, you can duplicate it to create a properties file for each JServ process.
If your HTTP server will be running on a different host than the JServ processes, you must also add the IP address of the host running the HTTP server to the
To start and stop the processes and the web server, it is convenient to use scripts. Samples are included in the
$ORACLE_HOME/Apache/Apache/bin/ directory (
If the user requests
/servlets/testServlet, the ApJServMount directive above will execute
testServlet in the zone called
balance://Jserv_set/rootand then add the ApJServBalance, ApJServHost, ApJservRoute directives for each process sharing the load, as shown below:
ApJServMount /servlets balance://JServ_set/root ApJServBalance JServ_set JServ1 ApJServBalance JServ_set JServ2 2 ApJServHost JServ1 ajpv12://127.0.0.1:8001 ApJServHost JServ2 ajpv12://127.0.0.1:8002 ApJServRoute JS1 JServ1 ApJServRoute JS2 JServ2 ApJServShmFile /usr/local/apache/logs/jserv_shm
/servlets balance://JServ_set/root, now balances requests for servlets in
JServ2as the processes that share the load. The '
JServ2is a weight value. It specifies that twice as many requests will be sent to
JServ2as would be otherwise, i.e., that
JServ2will get about 2/3 of all incoming requests. See "Distribution of JServ Requests" below for details.
ApJServHostdirective identifies the host and port on which the processes are listening.
ApJServRoutedirective associates JServ processes with sessions. JServ uses this information to keep all of a session's requests together in one process. The JServ session mechanism sends the process route information back to the user (generally in a cookie). You need only modify it if your application uses sessions.
ApJServShmFiledirective specifies a shared memory file that the httpd processes may use to track the state of the JServ processes.
The following process explains how
mod_jserv selects the JServ engine to handle a request:
mod_jservcreates a list of available JServs, with extra entries for JServs with a weight value greater than
1(for example, JServ2 in the example above, as specified by
ApJServBalance Jserv_set JServ2 2).
mod_jservselects the JServ engine that will handle the request.
mod_jservchecks to see if the request is part of a current session. If so, it uses the
ApJServRoutedirectives to find the JServ that handled the other requests for that session.
mod_jservselects an engine based on the process ID of the httpd process and the number of entries in the list of available JServs, as follows:
JServ_id to handle the request = httpd_pid % (modulo) number of JServs in the list
This method dibstributes requests across the available JServ engines fairly evenly.
Oracle recommends that you write your servlets to implement the SingleThreadModel (STM) interface. An application that was modified to implement the STM interface demonstrated a 25% improvement in response time.
It is also much easier to manage database connections with STM servlets. The database connection can be set up in the
init() method of the servlet, and closed in the
destroy() method. When executing the servlet's
service() method, you need not be concerned with obtaining a database connection. You can also manage database connections with JDBC connection caching.
There are three parameters in the
zone.properties file that impact the performance of STM servlets in particular. These govern:
Because it is very costly to generate instances while the system is running, Oracle recommends that you set your minimum to equal your maximum value. The optimum value depends somewhat on how many connections your database server can handle. This should be split among the JServ processes, as follows:
Total DB connections / Number of JServ processes =
Number of STM servlet instances per process
See Chapter 3, "Sizing and Configuration" for suggestions on determining the right number of JServ processes for your application, and "How to Perform Load Balancing" for the steps to configure them. Suppose you've determined that you want 10 servlet instances per process. The capacity settings in the
zone.properties file would be:
singleThreadModelServlet.initialCapacity = 10 singleThreadModelServlet.incrementCapacity = 0 singleThreadModelServlet.maximumCapacity = 10
The value for
OracleJSP 188.8.131.52 is Oracle's implementation of the Sun Microsystems JavaServer Pages 1.1 specification. Some of the additional features it includes are custom JavaBeans for accessing Oracle databases, SQL support, and extended data types. See the Oracle9i Application Server Overview Guide in the Oracle9i Application Server documentation library for detailed descriptions of the features.
This section explains how you can improve OracleJSP pages' performance.
In general, sessions add performance overhead; they consume about 0.5 KB of resident memory. You must turn off sessions if you do not want a new session to be created with each request. By default, sessions are enabled in OracleJSP pages, so if they are not being used, turn them off by including the following line at the top of the page:
If you are going to use sessions, ensure that you explicitly close them. If you don't, they will linger until they time out (the default value for session timeout is 30 minutes). To close a session manually, use the
See the OracleJSP Developer's Guide and Reference in the Oracle9i Application Server documentation library for more information on configuring OracleJSP pages.
Another parameter that has a significant effect on performance is developer mode. It is a useful feature for debugging during development, but it degrades performance. The default value is true, so you will need to set it to false in the
jserv.properties file as follows:
With developer mode set to true, OracleJSP and the servlet engine examines every request to determine whether to reload or retranslate the page or application. With developer mode off, only the first request is examined.
In a test using JDK 1.2 with 50 users, 128 MB heap, and the default TCP settings, the performance gains with developer mode off were 14% in throughput, and 28% in average response time.
If an OracleJSP page is not using any features that do not require resetting the buffer (such as error pages,
contextType settings, forwards, etc.), disabling the JSP page buffer will improve performance. This is because memory will not be used in creating the buffer, and the output can go directly to the browser. Use this page directive to disable buffering:
The configuration actions below can enhance the performance of your OracleJSP pages.
Since the performance cost of creating database connections is high, it is more performant to use a cache of connections. If you use a cache of database connections, then the OracleJSP application can get a connection from the cache and return it when it is finished.
The JDBC driver accumulates a number of execution requests (the batch value) and passes them to the database to be processed at the same time. You can configure the batch value to control how frequently processing occurs.
Cache executable statements that are repeatedly used, to avoid re-parsing, statement object re-creation, and recalculation of parameter size definitions.
During a query, pre-fetch multiple rows into the client to reduce round trips between the database and the server.
Cache small sets of data that are accessed frequently and do not change often. This is not as beneficial for large data sets, since they consume more memory.
To invoke static includes, use the page directive:
Static include creates a copy of the file in the JSP, thereby affecting its page size. This is useful in avoiding trips to the request dispatcher (unlike dynamic includes, which must go through the request dispatcher each time). However, file sizes should be small to avoid exceeding the 64 KB limit of the service method of the generated page implementation class.
To invoke dynamic includes, use the page directive
This directive is analogous to a function call, and therefore does not increase the page size of the JSP. However, a dynamic include increases the processing overhead since it must go through the request dispatcher. Dynamic includes are useful for including other pages without increasing page size.