Oracle 9i Application Server Oracle HTTP Server powered by Apache Performance Guide Release 1.0.2 for Windows NT Part Number A86676-01 |
| Library | Contents | Index

# 5
Optimizing Apache JServ

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.)

- Overview of JServ

- Optimizing Servlet Performance

- What is OracleJSP?

- Tuning OracleJSP Pages for Performance

## Overview of JServ

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.

#### Figure 5-1 Apache JServ components

Text description of the illustration modjserv.gif

## Optimizing Servlet Performance

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.

### Loading Servlet Classes

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.

#### Pre-Loading with JSPs

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 `oracle.jsp.jspServlet` in `servlets.startup`.

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 `servlets.startup`.

### Reloading Servlet Classes Automatically

If `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:

    autoreload.classes=false
    autoreload.file=false

### How to Perform Load Balancing

It is often beneficial to spread the servlet application load among multiple JServ processes, especially when the application is run on a multiprocessor 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.)

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.

If you use 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 `$ORACLE_HOME/Apache/Apache/bin/` 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".

#### Configuring the JServ processes

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.

1. Create a properties file for each JServ process.

       	copy jserv.properties jserv1.properties
       	copy jserv.properties jserv2.properties

2. Edit `jserv1.properties` as follows:

       	port=8001
       	log.file=/usr/local/jserv/logs/jserv1.log

3. Edit `jserv2.properties` as follows:

       	port=8002
       	log.file=/usr/local/jserv/logs/jserv2.log

   Note:: 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 `security.allowedAddresses` parameter in each `jserv.properties` file.

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 (`startJServ.bat` and `stopJServ.bat`).

#### Modifying jserv.conf to distribute the load

1. Set the flag to start processes manually.

       	ApJServManual on

2. Indicate where the servlet request is to be sent.

   1. Locate the ApJServMount directive.

          	ApJServMount /servlets /root

      If the user requests `http://`your.server.com`/servlets/`testServlet, the ApJServMount directive above will execute `testServlet` in the zone called `/root`.

   2. Change the zone identifier from `/root` to `balance://set/root` and then add the directives needed to describe the processes sharing the load:

          	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

      - The `ApJServMount` directive, with `/servlets balance://set/root`, now balances requests for servlets in `/servlets` between `JServ1` and `JServ2`.

      - The `ApJServBalance` directive identifies `JServ1` and `JServ2` as the processes that share the load. The '`2`' following `JServ2` is a weight value. It specifies that twice as many requests will be sent to `JServ2` as would be otherwise, i.e., that `JServ2` will get about 2/3 of all incoming requests. See "Distribution of JServ Requests" below for details.

      - The `ApJServHost` directive identifies the host and port on which the processes are listening.

      - The `ApJServRoute` directive 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.

      - The `ApJServShmFile` directive specifies a shared memory file that the httpd processes may use to track the state of the JServ processes.

#### Distribution of JServ Requests

The following process explains how `mod_jserv` selects the JServ engine to handle a request:

1. The httpd process is started.

2. `mod_jserv` creates 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 set JServ2 2`).

3. The httpd daemon receives a servlet request and hands it to `mod_jserv`.

4. `mod_jserv` selects the JServ engine that will handle the request.

   1. `mod_jserv` checks to see if the request is part of a current session. If so, it uses the `ApJServRoute` directives to find the JServ that handled the other requests for that session.

   2. If the request is not part of a session, `mod_jserv` selects the next JServ process in its list (round robin request distribution).

### Using Single Thread Model Servlets

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 `doGet()` or`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:

- The minimum number of servlet object instances that will be generated and available after the servlet class is loaded

- The maximum number that can be generated

- The number that should be generated if the available instances are insufficient

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

Warning: The value for `singleThreadModelServlet.maximumCapacity` in the zone properties file must be at least as large as the value for security.maxConnections in the jserv.properties file. If it is not, and the number of requests sent to the JServ process exceeds the maximum capacity, requests will fail.

## What is OracleJSP?

OracleJSP 1.1.0.0 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.

## Tuning OracleJSP Pages for Performance

This section explains how you can improve OracleJSP pages' performance.

### Impact of Session Management

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:

    <%@ page session="false" %>

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 `session.invalidate()` method.

See the OracleJSP Developer's Guide and Reference in the Oracle9i Application Server documentation library for more information on configuring OracleJSP pages.

### Developer Mode

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:

    servlet.oracle.jsp.JspServlet.initArgs=developer_mode=false

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.

### Buffering

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:

    <%@ page buffer="none" %>

    The default size of an OracleJSP page buffer is 8 KB.

### OracleJSP Performance Tips

The configuration actions below can enhance the performance of your OracleJSP pages.

#### Caching database connections

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.

#### Configuring the statement batch value

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.

#### Caching JDBC statements

Cache executable statements that are repeatedly used, to avoid re-parsing, statement object re-creation, and recalculation of parameter size definitions.

#### Pre-fetching rows

During a query, pre-fetch multiple rows into the client to reduce round trips between the database and the server.

#### Caching rowsets from the database

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.

#### Invoking static includes

To invoke static includes, use the page directive:

    <%@ include file="/jsp/filename.jsp" %>

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.

#### Invoking Dynamic Includes

To invoke dynamic includes, use the page directive

    <jsp:include page="/jsp/filename.jsp" flush="true" />

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.

| Copyright © 2000 Oracle Corporation. All Rights Reserved. |
| Library | Contents | Index