Randy Belknap wrote:

> "Craig R. McClanahan" wrote:
> > For example, consider a simple hit counting servlet.  The natural place to
> > store the counter would be an instance variable in the servlet class (suitably
> > initialized in the init() method and saved to disk in the destroy() method).
> > But, if the servlet engine was allowed to create more than one instance, this
> > counter would not be accurate!  As of 2.2, servlet authors can count on what
> > has been standard practice all along -- only one instance of a non-STM servlet
> > will be created in a container.
> >
>
> What would happen to your hit counting servlet in a load balanced
> environment?  Doesn't each app server have its own container with its
> own instance of the class?
>

You're correct -- in a load balanced environment, there will be an instance of the
servlet in each JVM, and using an instance variable in the servlet no longer
maintains your count correctly.  If the data you are trying to maintain was
user-specific, you could maintain the counter in a session and mark your app as
"distributable" (2.2 API), and the server is supposed to copy your user session
information when it moves you to a different server.  But, for the sake of this
example, we've been assuming that a global hit count was what we want, so this
doesn't help.

For maintaining a global shared variable that changes state like this in a
load-balanced environment, you're going to need some external resource container
(EJB, JDBC-accessed database, network-accessed file with suitable locking
primitives, and so on) to store the shared state information, and use appropriate
locking to make sure you don't lose any updates.

For a non-load balanced case, an instance variable would still count correctly,
although you might have concerns in a real life application about saving the
current value if the server crashes, instead of shutting down normally.

>
> I've seen you argue convincingly that using the servlet context is a
> better way of storing application state than singletons.  Wouldn't the
> same apply to instance variables?
>

The key qualifier in my example case was that, "if you do not need the information
outside of this servlet", an instance variable can be used.  You could also use a
servlet context storage of the counter, and make it accessible to other
servlets/JSP pages in your app as well.  Note that this still doesn't solve the
load balanced case -- each JVM has their own instance of your application's servlet
context as well (see below).

Looking back at some apps I've written recently, I initially used instance
variables to store things like resource bundles and connection pools (my app design
uses a single "gateway" servlet that dispatches to various non-servlet action
procedures based on the request parameters).  However, as soon as I added JSP pages
to the mix (which end up being compiled into separate servlets), I had to share
these objects anyway, so I copied references to them into the servlet context.

Can I use a Singleton for this?  Well, it still doesn't solve the load balanced
case, because there's an instance of your Singleton in each JVM along with an
instance of the servlet context and your servlet.  Using singletons (load balanced
or not) also fails in a scenario like this:
* Your app is sharing a servlet engine with my app.
* Both of our apps want to use the same "Hit Counter"
  class, implemented as a singleton.
* The servlet container uses the same class loader for
  both of our apps (if it doesn't, they really are two
  different classes -- but that's a level of complexity
  all its own, that we don't need to get into here).

This is why I prefer using the servlet context for sharing information across
servlets/JSP pages in an application, as opposed to a singleton.  When the spec
gets around to including "application start" and "application end" events (like ASP
has in the global.jsa file), you will also have convenient places to hang your
initialization and finalization code -- I was not a happy camper when this didn't
make the 2.2 version.


>
> Assuming what that each app server does have its own instance, isn't
> this part of the spec setting false expectations for developers?
>

Prior to the 2.2 spec, as I mentioned above, load balancing support was not really
specified. I've studied the 2.2 spec a *lot* so I'm probably not the right one to
ask if it sets false expectations or not.  But I've found the statements related to
what a servlet author can expect regarding this to be pretty clear:

==== BEGIN QUOTE SNIPPETS (August 18, 1999 Version) ===

Section 3.2 -- Number of Instances

    By default, there must be only one instance of a servlet
    class per servlet definition in a container.

    In the case of a servlet that implements the SingleThreadModel
    interface, the servlet container may instantiate multiple
    instances of that servlet so that it can handle a heavy
    request load while still serializing requests to a single
    instance.

    In the case where a servlet is deployed as part of an
    application that is marked in the deployment descriptor
    as distributable, there is one instance of a servlet class
    per servlet definition per VM in a container.  If the servlet
    implements the SingleThreadModel interface as well as is
    part of a distributable web application, the container may
    instantiate multiple instances of that servlet in each VM
    of the container.

Section 4.3.1 -- Context Attributes in a Distributed Container

    Context attributes exist locally to the VM in which they were
    created and placed.  This prevents the ServletContext from
    being used as a distributed shared memory store.  If information
    needs to be shared between servlets running in a distributed
    environment, that information should be placed into a session
    (see Section 7 titled "Sessions on page 35), a database, or
    set in an Enterprise JavaBean.

Section 7.7.2 -- [Sessions in] Distributed Environments

    Within an application that is marked as distributable, all requests
    that are part of a session can only be handled on a single VM
    at any one time.  In addition all objects placed into the session
    must implement the Serializable interface.  The servlet container
    may throw an IllegalArgumentException if a non serializable object
    is placed into the session.

    These restrictions mean that the Developer is ensured that there
    are no additional concurrency issues beyond those encountered
    in a non-distributed container.  In addition, the Container Provider
    can ensure scalability by having the ability to move a session object,
    and its contents, from any active node of the distributed system
    to a different note of the system.

===== END QUOTE SNIPPETS =====

The bottom line -- distributable support in 2.2 helps you for user-specific stuff
that you store in a session, but does not help you maintain shared global state.
The mechanisms proposed (databases, EJBs, etc.) seem like a reasonable approach to
me.  The servlet spec doesn't need to solve all the world's problems :-),
especially when we've got the rest of the Java APIs to take advantage of as well.

As always, there is room above and beyond this specification, or any specification,
to provide value-added features.  It is important for application designers to
first define the kind of support they need for a particular functionality (such as
load balancing), identify the suppliers that can meet that need, and (very
importantly IMHO) understand what is standardized and what is not, so that you do
not unwittingly build in dependencies on a particular vendor's implementation.  The
choice to use non-standard extensions should be a deliberate one.

Craig McClanahan

___________________________________________________________________________
To unsubscribe, send email to [EMAIL PROTECTED] and include in the body
of the message "signoff SERVLET-INTEREST".

Archives: http://archives.java.sun.com/archives/servlet-interest.html
Resources: http://java.sun.com/products/servlet/external-resources.html
LISTSERV Help: http://www.lsoft.com/manuals/user/user.html

Reply via email to