HomeDigital EditionSys-Con RadioSearch Java Cd
Advanced Java AWT Book Reviews/Excerpts Client Server Corba Editorials Embedded Java Enterprise Java IDE's Industry Watch Integration Interviews Java Applet Java & Databases Java & Web Services Java Fundamentals Java Native Interface Java Servlets Java Beans J2ME Libraries .NET Object Orientation Observations/IMHO Product Reviews Scalability & Performance Security Server Side Source Code Straight Talking Swing Threads Using Java with others Wireless XML
 

There are several books and articles out there on dynamic-content generation technologies such as CGI, NSAPI, server-parsed HTML, server-side JavaScript, Active Server Pages and ColdFusion. Recently, Java Servlets and JavaServer Pages (JSPs) have emerged as a very popular technology and a lot of material has been written about them. Most of the articles focus on programming model features, ease-of-development issues and integration with tools. However, an increasing concern of Web site developers is to develop sites that can scale to a large number of hits. This is especially true of corporate software developers and those building the brand-name dot.com sites of tomorrow. This article focuses on how Web developers can design their server-side applications for scalability and performance using Java Servlets and JSPs.

Java Servlets and JSPs
The Java Servlet API was designed to be a basic Web server extension mechanism in Java. It was modeled after NSAPI and ISAPI (which are the C/C++ extension mechanisms for the Netscape and Microsoft Web servers) and originally it was just the native plug-in API of the Java Web Server. It's a simple API that supports a request-response model, thus mirroring the nature of HTTP protocol. The simplest servlet is one that just returns a page saying "Hello world" to the client (see Listing 1). In the listing the servlet also checks for a form parameter called "name." If the name is supplied by the client, "Hello name" is printed instead. The functionality of the servlet is implemented by simply overriding the doGet method of HttpServlet.

In addition to request parameters, the servlet API can give the server plug-in developer the ability to manipulate most of the HTTP protocol-specific information in the server. This functionality is exposed through request and response objects (for HTTP request and response processing), and session objects (for handling HTTP sessions).

JSP technology was created to further simplify Web application development by separating the logic of the application from its content. This allows less sophisticated Web developers to take advantage of the latest Java technologies. JSPs provide developers with capabilities to embed the code logic directly into HTML pages. Another important feature is the ability to instantiate and use JavaBeans in a natural manner. This feature allows task partitioning between content developers and application logic developers. Listing 2 contains the same program written as a JSP.

A JSP is a document in a specialized markup language (with fragments of Java code); a servlet is a Java program. While there's overlap between the functionality of servlets and JSPs, typically the content and presentation logic belong in a JSP and the back-end code and programming logic belong in servlets.

How to Measure Performance
In order to design high-performance, scalable Web sites, it's essential to first understand the metrics by which they're measured. This section focuses on various metrics used to measure the performance of server software or a Web site. Since we're focusing on Web servers, the discussion is specific to the HTTP protocol.

  • Latency: The amount of time the Web server takes to process a request. This is an important metric, as you don't want customers of your Web site to wait too long for a request to be processed, especially when they're likely to hit the "Reload" button to further increase the load on the site. It's important to keep both the average and the maximum latencies as low as possible. If you see high latencies with low CPU utilization, you may want to investigate if there's a lock contention somewhere in your Web applications. Typically measured in milliseconds.

  • Throughput: The quantity of data the Web server running a particular application is able to push through per unit of time. This is important, especially for dynamic content applications that are generating rich content (including multimedia content). Typically measured in kilobytes per second.
  • Connection rate: The number of new connections the Web server is capable of accepting per unit of time. This metric gives an idea about how well your Web site will scale to large numbers of client accesses. The maximum feasible connection rate is usually measured by increasing the load until average latencies rise considerably and/or CPU utilization reaches 100%. Typically measured in connections per second.
  • Request rate: Number of HTTP requests the Web server is capable of processing per unit of time, given any reasonable mix of client behavior (HTTP 1.0, HTTP 1.1, pipelined requests, keep-alive requests). Note that this is different from the connection rate because multiple HTTP requests may be served on the same connection. However, the measurement technique is similar to the connection rate.
While latency and throughput are performance metrics, connection rate and request rate are metrics of scalability. To judge your Web site's performance and scalability, it's important to use anecdotal evidence of speed, but it's also important to measure scientifically, based on typical client accesses.

Session Management
HTTP protocol, as a model of communication between the client (a Web browser) and the server, is stateless in principle. While this makes it easy to implement, it certainly makes it harder for a meaningful Web application that preserves state or session information to be developed. A typical example of a session-aware Web application is a shopping cart in which to store selected items for checkout at some point in the future.

The need to maintain reliable session information for Web applications actually sparked a whole new class of software called Web application servers (e.g., Netscape Application Server, NetDynamics, WebLogic). These products, in addition to their legacy-integration capabilities, introduced a whole host of features that reliably enabled maintenance of state on the server side. However, the use of server-side session management facilities may cause degradation in scalability because:

  • There may be lock contention while synchronizing on session objects.
  • Maintaining the remote state across multiple server processes may introduce further overhead due to interprocess communication.
Don't use server-side state or session objects unless you absolutely have to. In many cases all the information can be transmitted between the client and the server via cookies or URL rewriting. This is especially true of nontransactional applications in which the reliability and integrity of the session is not as critical. Listing 3 gives code fragments where request parameters may be used instead of server-side state management to maintain the client's session.

Application Partitioning
With the advent of multitier programming models on the server, it's typical for Web sites to be architected with most of the programming logic residing in Web and application servers while the data resides in databases. A typical architecture is for Web servers to talk HTTP with clients, with an application server being the middle tier that talks to the database. The Web and application server usually run in different process spaces, and communicate using a proprietary or standard protocol. The Web and application servers are often distributed across multiple boxes.

In light of this, it's critical to partition your Web application in an appropriate manner. An ideal practice is to place stateless or light-state objects (which don't need to carry a reliable state) onto the front-end Web server, while keeping more complex objects on the application server of your choice. This often translates into keeping static HTML, content files and JSPs on the Web server, and transactional applications on the application server. For intermediate-sized applications there are trade-offs to keeping them on either the Web or application server. By implementing such a partitioning, the content, presentation and simple applications of your Web site enjoy low latency and high request rates (by virtue of running on the Web server), while the more critical applications enjoy reliable state maintenance and transactional semantics (by virtue of running on the application server).

Custom Session Management
Since most nontrivial Web applications implemented using servlets and JSP will make heavy use of HTTP sessions, it's critical to select a platform that implements them efficiently. The most common implementation provided by Web servers today is in-memory session managers, which are very fast but may not provide the reliability or scalability desired for a high-end Web site. Other implementation strategies such as database-resident or shared-memory session managers may be considered. Often the best session manager will depend on the characteristics of the Web application being developed.

It's important therefore to choose an application deployment platform that enables the use of custom session managers through a plug-in API. When we were designing iPlanet Web Server 4.0 (formerly Netscape Enterprise Server), we decided to provide and support a session manager API within the servlet engine.

We believe this will provide advanced users and third-party vendors with the capability to create their own custom session management solutions.

When to use custom session management? Consider, for example, when you already have a very efficient and proven architecture deployed to store and retrieve data efficiently across the network: the plug-in API for session manager will enable you to use this existing back-end solution to effectively store and retrieve session information just by implementing a few helper classes.

HTTP Protocol and JVM Issues
When choosing the appropriate platform for Web applications, one should always keep in mind how well HTTP protocol itself is implemented and integrated with the rest of the system. Since HTTP protocol is the way browsers speak to Web servers, the choice of the Web server platform is very important. The following features of HTTP 1.1 increase the overall performance of the system tremendously, and it's critical to select a Web server that implements them well.

  • Pipelining: Modern browsers are capable of sending requests without waiting for the response from the server for each one of them. As you can see from Table 1, HelloWorldServlet has almost double the request rate when both the client and server support HTTP pipelining. The latency also decreases about 40%. The performance difference with a complex example, WASPServlet, that exercises most of the Servlet API isn't as drastic but is still noticeable.

    Table 1

  • Chunked encoding: This is the HTTP 1.1 protocol feature that enables Web servers to send responses to the clients in chunks while keeping the connection alive. Consider, for example, a server-parsed HTML file (SHTML), which calls a servlet and a CGI. We expect the SHTML file to be preparsed by the Web server and cached. The servlet and CGI will be executed for each request.

Since the servlet and CGI don't know about each other, they may both attempt to set the Content-Length header. To maximize the performance, the Web server could buffer the output and adjust the Content-Length header appropriately, or use chunked encoding so the connection between the browser and the Web server remains open.

One of the reasons we chose an in-process architecture for the servlet engine in iPlanet Web Server 4.0 was to be able to take advantage of the advanced HTTP 1.1 features of the Web server, such as pipelining and chunked encoding.

It's also important to select a JVM that has optimal performance characteristics. Ideally, your Web server allows you to plug in any JVM of your choice, and its plug-in layer is designed so as not to introduce additional overheads. For example, iPlanet Web Server 4.0 allows any JNI-compliant JVM/JDK/JRE to be plugged in (JDK 1.1 or Java 2). It also employs a number of advanced techniques to minimize the effect of the JVM on the rest of the system. For example, you can allocate a separate thread pool to run Java applications. Request threads allocated from that pool will be attached to the JVM only once, thereby decreasing the overall overhead. On the other hand, when the garbage collector decides to suspend these threads, it will have no effect on the rest of the system.

Programming Practices
Perhaps the most overlooked aspect of developing high-performance plug-ins is the need to write good Java code. Some suggestions:

  • Try to scope all your references carefully so the garbage collector can take care of them easily (i.e., don't generate excessive garbage if you don't need to).
  • Pool expensive resources (threads, database connections, etc.) instead of trying to construct them on every request. Listing 4 shows a code fragment in which an expensive object is managed by creating a pool for it in the servlet init method rather than by creating a new one on every request.

  • Be extremely careful with synchronized methods as they may result in a lock contention. Try to make critical sections as short as possible. You may consider using third-party or your own locking mechanisms to avoid inefficiencies of Java language (such as an absence of reader-writer locks) or Java libraries (for example, many Java collection classes, such as java.util.Hashtable, are inefficient, even in modern JVMs).
  • Keep in mind that garbage collection can have an adverse effect on all threads that the JVM knows about (they can be arbitrarily suspended by the garbage collector). This can change the timing characteristics of your application.
Conclusions
Web site developers today have a wide variety of programming languages, models and tools to select from. While designing their Web applications for high performance and scalability, they need to keep in mind the following points:
  • Measure the performance using well-understood metrics such as latency and request rate.
  • Avoid server-based state management for nontransactional parts of the application.
  • Partition the application across the Web and application servers, keeping the transactional components on the application server.
  • Use a custom session manager if necessary.
  • Deploy on a Web server that supports the HTTP 1.1 protocol correctly as well as the use of modern JVMs.
  • Write good Java code, use pooling of expensive resources and avoid excessive synchronization and poor scoping practices.

Author's Bios
Ruslan Belkin, lead engineer and architect of Java Servlet and JSP support in iPlanet Web Server 4.0 (formerly Netscape Enterprise Server), has over 10 years of experience in the industry and is a member of the Servlet API expert group. Ruslan has worked on Java, CORBA, distributed objects, component models and scripting languages, with. special focus on high-performance implementations of standards. He can be reached at: [email protected].

Viswanath Ramachandran is a researcher working on JSP and JavaScript support in the iPlanet Web server group. A member of the JSP expert group, he holds a Ph.D. in computer science from Brown University in the field of programming languages. Current research interests include JavaScript performance, compilers and Web protocols. He can be reached at: [email protected].

	

Listing 1: HelloWorldServlet.java 

import java.io.*; 
import javax.servlet.*; 
import javax.servlet.http.*; 
  

public class HelloWorldServlet extends HttpServlet { 
  

public void doGet (HttpServletRequest req, HttpServletResponse res) 
    throws ServletException, IOException 
    { 
            res.setContentType("text/html"); 
               String name = req.getParameter 
("name"); 
               If (name == null) 
                 name = "world"; 
  

               PrintWriter out = res.getWriter(); 
               out.print("<html>"); 
               out.print("<head><title>Hello 
World</title></head>"); 
               out.print("<body>"); 
               out.print("<h1>Hello " + name + 
"</h1>"); 
               out.print("</body></html>"); 
    } 
} 

Listing 2: HelloWorld.jsp 

<html> 
<head><title>Hello World</title></head> 
<body> 
<% String name=request.get parameter ("name"); 
if (name == null) 
     name = "world"; 
%> 
<h1>Hello <%= name %> </h1> 
</body> 
</html> 

 
Listing 3: ServerSessionServlet.java and ClientParameterServlets.java 
  
public class ServerSessionServlet extends HttpServlet { 

public void doGet (HttpServletRequest req, HttpServletRe- sponse res) 
throws ServletException, IOException 
            { 
    HttpSession session = req.getSession (); 
    -- 
    UserInfo info = search4user (session.getValue 
    ("username")); 
    } 
} 
   public class ClientParametersServlet extends HttpServlet { 
  
   public void doGet (HttpServletRequest req, HttpServletResponse res) 
   throws ServletException, IOException 
   { 
   String username = req.getParameter ("username"); 
  
   UserInfo info = search4user (username); 
   } 
} 
  
  

Listing 4: Pooling of resources (UnpooledServlet.java and PooledServlet.java 
  

 public class UnpooledServlet extends HttpServlet { 
  
 public void doGet (HttpServletRequest req, HttpServletRe- sponse res) 
 throws ServletException, IOException 
 { 
  res.setContentType("text/html"); 
 .... 
 ExpensiveObject o = new ExpensiveObject ( .... ); 
 .... 
 } 
} 

 public class PooledServlet extends HttpServlet { 
  
  public void init (ServletConfig config) 
   { 
    super.init (config); 
 expensiveObjectPool = new ExpensiveObjectPool(); 
 for (int i = 0; i < l0; i++) 
 expensiveObjectPool.add (new ExpensiveObject ( ....)); 
 } 
  
 public void doGet (HttpServletRequest req, HttpServletResponse res) 
  
 throws ServletException, IOException 
  { res.setContentType("text/html"); 
 ... 
 ExpensiveObject o = expensiveObjectPool.get (); 
 ... 
 expensiveObjectPool.recycle (o); 
  
 } 
} 



 

All Rights Reserved
Copyright ©  2004 SYS-CON Media, Inc.
  E-mail: [email protected]

Java and Java-based marks are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries. SYS-CON Publications, Inc. is independent of Sun Microsystems, Inc.