JaVa
   

Web-Tier Session Management

Regardless of which MVC framework we use, our approach to session management can have a big impact on performance and scalability. By holding server-side state on behalf of users we can simplify app code and may improve performance by caching data that may be used later in a user session. However, there is a tradeoff involved as holding server-side state can reduce scalability. When we need to maintain session state, there are basically two options:

Let's consider each in turn.

Session State Managed by the J2EE Server

The Servlet API provides a simple means of holding state in a javax.servlet.http.HttpSession object. An HttpSession is essentially a map of name-value pairs, with the setAttribute() and getAttribute() methods analogous to a Map's get() and put() methods. A web container will hide the details of session object lookup, holding a unique key for a session in a cookie or special request parameter.

Clustering and Replication

In an app that runs on a single server, there is no problem in holding session state in an HttpSession object, managed transparently by the web container; the benefits in code simplification and performance come without any cost attached. As we noted in , this approach is usually preferable to using a stateful session EJB.

However, when we have a cluster of servers, such session state will need to be replicated by the server to ensure failover and to minimize server affinity. Replicated session state data is often stored in a database to ensure robust persistence: a major performance hit. This also means that all objects placed in an HttpSession must be serializable, to allow the server to store them in a database or file system.

Simple Optimizations

Due to the potential load of state replication, it's important to apply the following optimizations when using server-managed state:

None of these optimizations compromises app design. Let's consider each optimization in turn.

Don't Create Session State Unless Necessary

It's important to avoid the creation of session state (and hence the need to replicate it in a cluster) until it's necessary. For example, in the sample app, it's only during the tutorialing process that we need to hold session state for users. The majority of user activity will involve browsing genre, performance, and show information and availability, so by creating session state only when users attempt to tutorial we can avoid unnecessary state replication. When we use JSP as the view technology, we must beware of a trap here. By default, every JSP creates a new HttpSession object if none exists, in case there is a JSP bean with session scope bound on the page. This is often undesirable behavior. We can override the default with the following JSP directive:

 <%@ page session= "false" %>


I recommend the use of this directive on every JSP. Views shouldn't access or manipulate session state; a controller component should make all data available to the JSP with request scope. A controller can copy session attributes to the data model as necessary, to make them accessible to JSP pages that aren't session-aware.

Important 

Always switch off default JSP session creation with a page directive. This avoids needless creation of session state, and avoids the risk of JSP pages accessing and manipulating session state, which is inappropriate for views.

Another reason to avoid JSP pages accessing session objects is that it breaks the important rule that views should only work with data included in the model. Many views (such as XSLT views) may be unable to access session state. However, if necessary session state is included in the model, any view can access it like other model data, and view substitutability is preserved.

Minimize the Volume of Data Held in Server-side Session State

It's important to minimize the volume of data held in a user session. Holding unnecessary data will slow replication and will waste resources on the server. If too much session data is held in memory, the server will need to swap session data into a persistent store, resulting in a large performance hit when passivated sessions are reactivated.

Reference data that can be shared between users should always be held at app level. Data that is unlikely to be reused should probably just be retrieved again if it's ever needed. For example, a primary key might be held instead of a large volume of data retrieved from a database; this is a good sacrifice of performance in rare cases for a real benefit in scalability.

Use Fine-grained, Rather than Large Monolithic, Session State Objects

It's usually best to break session state into a number of smaller objects than one large, composite object. This means that only those objects that have changed will need replication in a cluster.

As there's no easy way to establish whether the state of a Java object has changed, some servers, such as WebLogic, only replicate session state in a cluster when an object is rebound in an HttpSession, although the Servlet 2.3 specification doesn't specify what behavior is expected here. (The Servlet 2.4 specification may define standard semantics for session replication.) Such selective replication can deliver a big performance gain when objects stored in a session are updated at varying rates. Thus, to ensure correct replication behavior, always rebind a session attribute when the session data is changed. This won't pose a problem in any server.

Consider Optimizing the Serialization of Session Data

Sometimes by overriding the default serialization behavior, we can greatly improve the performance and reduce the size of serialized objects. This is a specialized optimization that is rarely necessary. We'll discuss serialization optimization in .

Session State Held in the Browser

Some session state must always be held in the user's browser. As HTTP is a stateless protocol, a J2EE server can only retrieve a user's session object if it finds a cookie or a special request parameter containing a unique key for that user's session. By holding session state in the browser, we lose the advantage of transparent server management of session state, but can achieve greater scalability and simplify clustering.

Session State Management with Cookies

In this approach, we use cookies to hold session state. The Servlet API makes it easy to set cookies, although we must be aware of the restrictions on the characters allowed in cookie values. The advantage of this approach is that it allows us to make an app's web tier stateless, which has the potential to improve scalability dramatically and simplify clustering. However, there are several disadvantages that often rule out this approach in practice:

Sometimes this approach can be used with good results. In one real app, I successfully used cookies in place of session state where user information consisted of three string values (none longer than 100 characters) and three Boolean values. This approach delivered business value because the app needed to run on several geographically dispersed servers, ruling out replication of server-managed session state. I used an infrastructure class to extract property values from the session object using reflection and generate an acceptable ASCII-encoded cookie value.

Session State Management with Hidden Form Fields

Another time-honored approach to session state management, which also isn't J2EE-specific, involves an app trailing hidden form fields from page to page containing session state. I don't recommend this approach. It has several serious disadvantages:

Important 

In some apps, session state can be held in cookies. However, when we need session state it's usually safer - and much simpler - to rely on the web container to manage HttpSession objects, ensuring that we do all we can to ensure efficient replication of session state in a clustered environment.

JaVa
   
Comments