A WebLogic Cluster is a group of servers that work together to provide a more powerful, more reliable application platform. A cluster appears to its clients as a single server but is in fact a group of servers acting as one. It provides two key features above a single server:
WebLogic Clusters are designed to bring scalability and high-availability to J2EE applications. They provide these features in a way that is transparent to the application writer. It is important, however, for application programmers and administrators to understand the issues inherent in clustering in order maximize the scalability and availability of their applications.
A clustered service is one that is available on multiple servers in the cluster. EJBs can be clustered simply by deploying them on multiple servers. Servlet, JSPs and Web Applications can be clustered in the same way. If a service is clustered, the client has a choice about which instance of the service to call. In this discussion, we will refer to each instance of service as a replica. Each clustered service is represented by a replica-aware stub. The stub appears to the caller as a normal RMI stub but instead of representing a single object, the stub represents a collection of replicas. On each call, the stub employs a load algorithm to choose which replica to call. This provides load-balancing across the cluster in a way that is transparent to the caller. If a failure occurs during the call, the stub intercepts the exception and retries the call on another replica. This provides fail-over that is also transparent to the caller.
In order for a cluster to be scalable, it must ensure that each server is fully utilized. The standard technique for accomplishing this is load-balancing. The basic idea behind is that by distributing the load proportionally among all the servers in the cluster, the servers can each be run at full capacity. The trick to load-balancing is coming up with a technique that is simple yet sufficient. If all servers in the cluster are the same power and offer the same services, it's possible to use a very simple algorithm that requires no knowledge of the servers. If the servers vary in power or in the kind of services they deploy, the algorithm must take into account these differences. WebLogic Clusters support several algorithms to address this range of requirements.
This algorithm chooses the next replica at random. This will tend to distribute calls evenly among the replicas. It is only recommended in a homogeneous cluster (i.e., where each server has the same power and the same services). The advantages are that it is simple and relatively cheap. The primary disadvantages are that it is difficult to predict, there is a small cost to generating a random number on every request, and there is a slight probability that the load will not be evenly balanced over a small number or runs.
This algorithm cycles through the list of replicas in order. When it reaches the end of the list, it starts again at the beginning. The starting point for each replica-aware stub is chosen at random to ensure that all stubs do not begin with the same replica. This algorithm will tend to distribute the load evenly among the replicas. It is only recommended in a homogeneous cluster. The advantages of this algorithm are that it is simple, cheap and very predictable. The primary disadvantage is that there is some chance of convoying. Convoying occurs when one server is significantly slower than the others. Because each the replica-aware stubs are all going after the servers in the same order, one slow server can cause all stubs to eventually back up behind that server and then fall into lockstep.
This algorithm improves on the round-robin algorithm by taking into account a pre-assigned weight for each server. Each server in the cluster is assigned a weight in the range (0-100) using the property weblogic.system.weight. This is a declaration of what proportion of the load it will bear relative to other servers. If all servers have either the default weight (100) or the same weight, they will each bear an equal proportion of the load. If one server has weight 50 and all other servers have weight 100, the 50-weight server will bear half as much as any other server. This algorithm makes it possible to apply the advantages of the round-robin algorithm to clusters that are not homogeneous.
It is also possible to gain finer grain control over load-balancing. Any clustered object can be assigned a CallRouter. This is a plug-in that is called before each invocation with the parameters of the call. The CallRouter is free to examine the parameters and return the name server to which the call should be routed.
In order for a cluster to provide high availability it must be able to recover from service failures. This is accomplished by doing fail-over in the replica-aware stub. When a client makes a call through a replica-aware stub to a service that fails, the stub detects the failure and retries the call on another replica.
Automatic fail-over can only occur in cases where there is no chance that a retry will produce an incorrect result. It is always safe to retry a call if the stub can determine that the failed call never reached the server. If, however the stub cannot determine this, it may not be safe to retry. In this case there is a possibility that a retry will result in the service being called twice.
Consider a shopping cart service call addItem() that adds an item to a shopping cart. Suppose a client C invokes this call on a replica on server S1. After the S1 receives the call, but before it successfully returns to C, S1 crashes. At this point the item has been added to the shopping cart, but the replica-aware stub has received an exception. If the stub were to retry the method on server S2, the item would be added a second time to the shopping cart. Because of this, replica-aware stubs will not, by default, attempt to retry a method that fails after the request is sent but before it returns. This behavior can be overridden by marking a service idempotent. A service is idempotent if any method can be called multiple times with no different effect than calling the method once. This is always true for methods that have no side-effects. Methods that do have side effects have to be written specially with idempotence in mind.
One approach to making addItem() idempotent is to add a sequence number as an extra parameter. Whenever a new item is added to the cart, it is accompanied by a sequence number. No item with the same sequence number can be added twice. If the addItem() call fails on S1, the replica-aware stub can now retry on S2. Since the retry sends the same sequence number, the service will only add the item if it hasn't already been added. Otherwise it will ignore the call.
Cluster-Wide Naming Service
Clients access the services provided by a WebLogic server through a JNDI compliant naming service. This naming service contains all of the public services offered by that server. A server offers a new service by binding a stub representing that service into the tree. A client obtains the stub by connecting to the server and looking it up by name.
WebLogic Clusters extend the naming service for a single server to one that contains all of the services provided by the cluster. Each server simply binds the stubs that it provides into the cluster-wide naming service. Clients simply connect to the service and look up the desired stub. From the application point of view, this all looks the same as the single server case. Beneath the covers, however, a great deal has changed.
The cluster-wide naming tree may contain stubs that refer to any one of the servers the cluster. It may also contain replica-aware stubs which represent services that are clustered across multiple servers.
The cluster-wide naming service is itself replicated to ensure that it remains available in the face of server failures. Each server in the cluster hosts a replica. When a client connects to the naming service, it may connect to any one of servers. From the client's perspective, it has connected to the cluster. In reality it has connected to one of the servers in the cluster. Each Context stub is replica-aware. If a failure occurs while making a call to the name service, the stub will automatically fail-over to another replica.
See ... for more information on the Cluster-wide naming service.
All EJBs are clusterable. If an EJB is deployed on multiple servers in the cluster, each of these servers will be able to host instances of the bean. This does not necessarily mean, however, that the bean instances are clustered.
All bean homes are clusterable. When a bean is deployed on a server, its home is bound into the cluster-wide naming service. Because homes are clusterable, each server can bind an instance of the home under the same name. When a client looks up this home, it gets a replica-aware stub that has a reference to the home on each server that deployed the bean. When create() or find() is called, the replica-aware stub routes the call to one of the replicas. The home replica that receives the finds or creates an instance of the bean on its server.
When a home creates a stateless bean, it returns a replica-aware stub that can route to any server on which the bean is deployed. Because a stateless bean holds no state on behalf of the client, the stub is free to route any call to any server that hosts the bean. Also, because the bean is clustered, the stub can automatically fail over in the event of a failure. The stub does not automatically treat the bean as idempotent, so it will not recover automatically from all failures. If the bean has been written with idempotent methods, this can be noted in the deployment descriptor and automatic fail-over will be enabled in all cases.
When a home creates a stateful bean, it returns a stub that is pinned to the server hosting the home. Because this bean holds state on behalf of the client, all calls must be routed to the single instance. So in the case of a stateful bean, load-balancing and fail-over only occur during calls to the home. Once the stateful bean has been created, all calls for it must go to the same server. If a failure occurs, the client code must catch the remote exception and retry by creating a new instance using the clustered home.
There are two flavors of entity beans to consider: read-write entities and read-only entities.
When a home finds or creates a read-write entity bean, it obtains an instance on the local server and returns a stub pinned to that server. As with a stateful bean, load-balancing and fail-over only occur at the home level. Because it is possible for multiple instances of entity to exist in the cluster, each instance must read from the database before each transaction and write on commit.
When a home finds or creates a read-only entity bean, it returns a replica-aware stub. This stub load-balances on every call and will automatically fail-over in the event of any recoverable call failure. Read-only beans are also cached on every server to avoid database reads.
For more information about using EJBs in a cluster, please read The WebLogic Server EJB Container.
WebLogic RMI provides special extensions for building clustered remote objects. These are the extensions used to build the replica-aware stubs described in the EJB section. For more information about using RMI in WebLogic Server Clusters please read Using WebLogic RMI.
Servlets are also clusterable. If a servlet, JSP or web application is deployed on multiple servers it is clustered across those servers. For servelts, the replica-aware stub is replaced by a replica-aware proxy. This proxy fields the request on the web server and forwards it to one of the servers in the cluster. The proxy load-balances requests across the cluster and handles recovery when requests fail. The proxy also works with the cluster to maintain session state, even in the event of failure. When a new session is initiated, the proxy employs a load balancing algorithm to chose a server to host the session. From that point forward, all requests associated with that session will be forwarded to the same server. To avoid the single point of failure introduced by pinning, the session can be replicated. When replication is enabled, each change to the session is copied to a secondary. If the primary fails, the proxy will reroute to the secondary, the secondary will become the primary, and a new secondary will be chosen.
See Setting up WebLogic as an HTTP server for more information on clustered Servlets.
Copyright © 2000 BEA Systems, Inc. All rights reserved.