Load Balancing in Cluster
Pramati Cluster provides a pluggable load balancer architecture. Different load balancing algorithms can be used by the cluster. By default, Pramati Server ships with a Weighted Round Robin Load Balancer Algorithm.
Web nodes
Load balancing from web nodes happens to different EJB nodes in the cluster at every new
InitialContext() creation on the web node. When a new InitialContext is created, the context will connect to the next node in the cluster returned by the load balancer algorithm.
Java clients
Every Java client that connects to an EJB node in Pramati Cluster is load balanced with another EJB node, depending on the load balancer algorithm. However, when Java client connects to a node, all requests are directed to the same node; except in the case of a failover.
Load Balancer Algorithm
Pramati Server ships with a Weighted Round Robin Load Balancer Algorithm. When configuring a Cluster, the default weight is “1”. However, the weight on each node can be changed while
configuring the Cluster.
For example, if Machine A hosting a node is twice as powerful as Machine B hosting another node, then Machine A is weighted “2” while Machine B is weighted “1”. Consequently, out of three requests, two will be directed to Machine A and one to Machine B. The load balancer algorithm calculates the ratios of the weights and connects clients accordingly.
Weighted Round Robin
Special cases of the Weighted Round Robin Algorithm:
• Round Robin (this is the default when a cluster is configured. All nodes have weight as 1). • Hot Backup: Setting the weight of a node to 0 makes it a Hot Backup node. Such a node will not
receive any request till all nodes with non-zero weights have failed in the Cluster. Such a node will stop receiving requests once a weighted node re-joins the Cluster.
Setting Load Balancing Properties
The com.pramati.naming.distributeload takes the values of: • VM
When a new InitialContext() is created for the first time in a VM, the client context attaches itself to one of the nodes in the cluster. (depending on LoadBalancer). Once attached, all subsequent InitialContext() will be directed to the same node.
• IC
This implies per InitialContext(). In contrast to the first option, multiple InitialContext() (within a VM) will be directed to different EJB nodes using round robin algorithm.
Note: The load balancer that runs in the cluster node is different. The client-based load balancer distributes IC's in a round robin fashion.
• LOOKUP
This implies that per each lookup IC based lookup is a subset of this option. Apart from alternating nodes per each new InitialContext() each lookup of a EJBHome will be rotated.
Customizing Load Balancer
To include the custom load balancer, configure the Cluster with the fully qualified load balancer class name.
For example, in the sample shown above, try.sample.lba.SampleLBA. This class should be in the classpath of the Pramati Server and is added to the NODE_CLASSPATH property in the following file:
<install_dir>/nodes/Cluster/[node]/config/env.props This must be done for every node in the Cluster.
Writing the application for load balancing
The goal of load balancing is to evenly distribute workload between multiple Servers. Deploying an application on a Cluster from the Console is identical to deploying on a Standalone Server.
Balancing application request loads, or load balancing requires you to place one or more copies of an application component on multiple Servers. Each Server is configured as a Node of the same Cluster, allowing it to find application components on other servers.
The Console hides from the user the underlying mechanisms that drive load balancing and fail over. The Cluster handles these transparently. However, when you deploy an application, you must decide if you want to configure the application for load balancing and, if so, how you will configure it.
The web nodes to distribute the EJB load among the available EJB nodes do load balancing. This is done by the Naming service that runs on the Web node. The naming service on a Web node is cluster-aware and keeps track of all EJB nodes in the Cluster.
When a new InitialContext is requested, the naming service will loadbalance on the available EJB nodes and attach the context with the target EJB node. All requests (or look-ups) made on that instance of InitialContext will be routed to that node.
It the target EJB node for the context instance fails, a new target node is selected through load balancing. The InitialContext instance gets attached to the new node.
You can use this intelligently in your code to control load balancing in your JSP pages. For example:
Context ic = new InitialContext(); Object someBean =
ic.lookup("java:comp/env/ejbs/Mybean1"); Object someOtherBean =
ic.lookup("java:comp/env/ejbs/Mybean2");
In the above case the EJBs someBean and someOtherBean are retrieved from the same EJB node. However, if you wrote the code as:
Context ic = new InitialContext(); Object someBean =
ic.lookup("java:comp/env/ejbs/Mybean1"); ic = new InitialContext();
Object someOtherBean =
ic.lookup("java:comp/env/ejbs/Mybean2");
The two beans may not come from the same EJB node. You must not distribute the beans within a single session, because if all the beans come from the same node then the inter-bean calls can use the Fast RMI optimization.
Also, usually beans constituting a single session are most likely to participate in a transaction. If the beans are distributed, the transaction too is distributed, becoming more expensive and more resources-hungry.
Distributed transactions should be avoided wherever possible. Therefore it is important a single session uses a single instance of the InitialContext. For example:
HttpSession ssn = request.getSession(); Context ic = (Context)ssn.getValue("mycontext"); if(ic == null){ ic = new InitialContext(); ssn.putValue("mycontext", ic); } ic.lookup(...) ...
Concurrency Control
The Server manages all complexity of concurrency control in multiple VMs, transparent to the application. Hence, there are no additional programming constraints imposed on an application for achieving this control.
Session beans
Since session beans are not shared objects there is no additional requirement for controlling the concurrency in a cluster.
Entity beans
Entity beans make use of the Remote Lock Server (RLS) to maintain concurrency across nodes. This acts as a central repository for beans to acquire and release locks on Entity Beans.
By interacting with the local lock service, the RLS ensures that only one node acquires a lock on an Entity Bean at one time. The Local Lock Service (LLS) communicates with the RLS on behalf of the node and coordinates the acquiring and freeing of locks, when asked to do so by the RLS.
Once a lock on a bean is acquired from RLS by a node for a particular bean it is not released back to RLS after the execution of the business method. Instead, the node through the Local Lock Service maintains it. This is because usually a client session is likely to work with a definite set of beans, which is likely to be exclusive with other sets of beans interfacing with other clients. In such conditions, it is more efficient to maintain the locks acquired by the node locally because the client session attached to this node is likely to make further use these beans.
For locks that are maintained locally, the node does not communicate with the RLS and hence processes the request faster.
Failover Mechanism
The Servers use intelligent wrappers around regular stubs to provide failover capability. These wrappers contain information required to facilitate smooth failover. The wrappers are completely transparent to the client and require no special programming on the client side. Since the wrappers use normal stubs, no special RMI complier too is required.
Stateless Session beans
For stateless session beans the Wrapper simply recreates a new instance of the bean on a new EJB node and executes the call on that bean instance.
Stateful Session beans
For stateful session beans, failover is achieved with the help of a database. During the deployment of the application, for stateful session beans, the Deployer can specify the methods of the bean that change state. This information is used by the EJB Container to persist the state of the bean, at the end of specified methods, to a database. The database information is taken at the time of configuring the cluster.
All nodes of the cluster use the single database/table for persisting the stateful session beans. When an EJB node on which a stateful session bean is created goes down, the Wrapper creates a new instance of the stateful session bean on a different EJB node. It also attaches the passivated bean instance to the created stateful session bean.
Stateful beans are always persisted after they are created. The ejbCreate is always treated as a method that changes the state of the bean. Before persisting the state of the bean, the Container passivates the bean instance (making it serializable) and after persistence, ejbActivate is called. The bean must ensure that it is in a serializable state, after a call to the ejbPassivate and must bring itself back to working state after an ejbActivate call.
Entity beans
For entity beans, the Wrapper recreates a new instance of the bean on a different node through an ejbFindByPrimaryKey call on the new node. The last committed data is loaded into the bean is returned back to the client for use.
Redeployment Issues
Each deployment of an application on the Pramati Server creates a class loader for that deployment. So when the application is redeployed, a new class loader loads all application classes again.
Therefore, attempts to use the classes from old deployment together with the ones from new deployment results in ClassCastException. This happens where web clients are connected while redeploying, since these clients may have application object instances stored in their HttpSessions. All new clients get the classes from the new deployment.