<!--
  ~ Licensed to the Apache Software Foundation (ASF) under one
  ~ or more contributor license agreements. See the NOTICE file
  ~ distributed with this work for additional information
  ~ regarding copyright ownership. The ASF licenses this file
  ~ to you under the Apache License, Version 2.0 (the
  ~ "License"); you may not use this file except in compliance
  ~ with the License. You may obtain a copy of the License at
  ~
  ~ http://www.apache.org/licenses/LICENSE-2.0
  ~
  ~ Unless required by applicable law or agreed to in writing,
  ~ software distributed under the License is distributed on an
  ~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  ~ KIND, either express or implied. See the License for the
  ~ specific language governing permissions and limitations
  ~ under the License.
  -->

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html lang="en" xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
<meta http-equiv="content-type" content="" />
<title>Axis2 Clustering Support</title>
</head>
<body lang="en" xml:lang="en">

<!-- Introduction Para -->
<h1>Axis2 Clustering Support</h1>
<p>Are you interested in improving Scalability and High Availability of your Web Services?</p>
<p>Axis2 1.4 provides experimental clustering support to add <b><i>Scalability, Failover and High Availability</i></b> to your Web Services.
This guide will explain the extent of clustering support and it's the current limitations.
It also highlights the recommended approaches using examples.</p>
<p>Axis2 clustering support can be used in several scenarios.
However it is important to understand the current limitations and the risks/impacts associated with each scenario.
</p>

<!-- Content menu -->
<h2>Content</h2>
<ul>
<li><a href="#introduction">Introduction</a></li>
<li><a href="#scalability">Scalability</a></li>
<li><a href="#failover">Failover</a></li>
<li><a href="#ha">High Availability</a></li>
<li><a href="#stateless_webservices">Clustering for Stateless Web Services</a></li>
<li><a href="#stateful Web Services">Clustering for Stateful Web Services</a></li>
<li><a href="#config">Configuring Axis2 to add Clustering Support</a></li>

<li><a href="#scalability_stateless_example">Example 1: Scalability and HA with Stateless Web Services</a></li>
<li><a href="#failover_stateful_example">Example 2: Failover for Stateful Web Services</a></li>
<li><a href="#scalability_stateful_example">Example 3: Scalability and HA with Stateful Web Services</a></li>
<li><a href="#summary">Summary</a></li>
<li><a href="#furtherstudy">For Further Study</a></li>
</ul>

<!-- Intro -->
<a name="introduction" id="introduction"></a>
<h2>Introduction</h2>
<p>In the context of Axis2 clustering, a node is defined as a separate process with a unique port number where it listens for requests on a given transport . A physical machine can contain more than one node.</p>

<!-- Scalability -->
<a name="scalability" id="scalability"></a>
<h2>Scalability</h2>
<p>In order to maintain the same level of serviceability (QoS) during an increase in load you need the ability to scale.
Axis2 provides replication support to scale horizontally. That is, you can deploy the same service in more than one node to share the work load, thereby increasing or maintaining the same level of serviceability (throughput etc).</p>

<!-- Failover -->
<a name="failover" id="failover"></a>
<h2>Failover</h2>
<p>Axis2 provides excellent support for Failover by replicating to backup node(s). 
If you deploy your Stateful Web Services in this mode, you can designate 1-2 backups and replicate state. 
In the event the primary node fails, the clients can switch to one of the backups. 
If you use Synapse with the Failover mediator you can provide transparent Failover.</p>

<!-- HA -->
<a name="ha" id="ha"></a>
<h2>High Availability</h2>
<p>You can improve the availability of your Web Service by using the following Axis2 functionality. 
<ul>
<li><b>Failover</b> support will ensure that a client will continued be served, without any interruption due to a node failure.</li>
<li><b>Scalability</b> support will ensure that your services can maintain the same level of serviceability/availability (QoS) in increased load conditions.</li>
<li><b>Hot Deploy</b> feature ensures that you could deploy new services without shutting down your existing services.</li>
</ul>
</p>

<!-- Stateless Web Services -->
<a name="stateless_webservices" id="stateless_webservices"></a>
<h2>Clustering for Stateless Web Services</h2>
<p>This is the simplest use case. 
If your Web Service does not store any state in the context hierarchy then you could deploy your service in "n" number of nodes. To ensure identical configuration for your services, you can load from a central repository using the URLBasedAxisConfigurator. This is not a must, but it makes management of the cluster easy and less error prone.</p>

<p>Since it is stateless no explicit replication is needed. If a node fails any other node in the cluster can take over. You can use a load balancer to direct requests based on a particular algorithm (Ex: Round Robin, Weight based, Affinity based). You can increase the no of nodes to handle scalability (to scale vertically) without worrying about the overhead of replication as the services are stateless</p>

<!-- Stateful Web Services -->
<a name="stateful_webservices" id="stateful_webservices"></a>
<h2>Clustering for Stateful Web Services</h2>
<p>This is a more complicated use case where your Web Service needs to store state in the context hierarchy. Each Web Service instance (deployed in separate nodes) will need to share state among themselves. Axis2 provides replication to support sharing of state among services.</p>

<p>However, if more than one node tries to update the same state in the context hierarchy, conflicts will arise and the integrity of your data will be compromised. Now your cluster will have inconsistent state. This can be avoided using a locking mechanism. However Axis2 currently does not support it yet.</p>

<p>If this shared state is read more frequently and updated rarely the probability of conflicts decrease. You may use Axis2 in the above use case for Stateful Web Services based on your discretion. However it's important to remember that there can be conflicts.<i><b>If you have frequent writes it is not advisable to use Axis2 until we introduce locking support</b></i></p>

<p>Please note this warning is only applicable to the following use cases.
<ul>
<li>Your Service is deployed in Application Scope</li>
<li>You store information in the ServiceGroupContext (irrespective of your scope)</li>
</ul>
</p>

<p>You may safely use services in "soapsession" scope provided you <i><b>don't modify (or modify at all) state in ServiceGroupContext frequently</b></i>. In soap-session the service context is exclusive to the client who owns the session. Therefore only that client can modify state. A conflict might arise if the same client tries to access the same service in two different nodes simultaneously which happens to modify the same state. However this is rare, but might arise due to an error in the load balancer or the client. If you use Sticky sessions, it will ensure that state will be changed in one node only by directing all requests by the same client to the same node. This is the safest way to use Axis2 clustering support for Stateful Web Services to acheive scalability.
</p>

<!-- Configuring Axis2 to add Clustering support -->

<a name="config" id="config"></a>
<h2>Configuring Axis2 to add Clustering Support</h2>
<p>You need to add the following snippet to your axis2.xml</p>
<pre>
   &lt;cluster class=&quot;org.apache.axis2.clustering.tribes.TribesClusterManager&quot;&gt;
     &lt;contextManager class=&quot;org.apache.axis2.clustering.context.DefaultContextManager&quot;&gt;
        &lt;listener class=&quot;org.apache.axis2.clustering.context.DefaultContextManagerListener&quot;/&gt;
        &lt;replication&gt;
            &lt;defaults&gt;
                &lt;exclude name=&quot;local_*&quot;/&gt;
                &lt;exclude name=&quot;LOCAL_*&quot;/&gt;
            &lt;/defaults&gt;
            &lt;context class=&quot;org.apache.axis2.context.ConfigurationContext&quot;&gt;
                &lt;exclude name=&quot;SequencePropertyBeanMap&quot;/&gt;
                &lt;exclude name=&quot;NextMsgBeanMap&quot;/&gt;
                &lt;exclude name=&quot;RetransmitterBeanMap&quot;/&gt;
                &lt;exclude name=&quot;StorageMapBeanMap&quot;/&gt;
                &lt;exclude name=&quot;CreateSequenceBeanMap&quot;/&gt;
                &lt;exclude name=&quot;ConfigContextTimeoutInterval&quot;/&gt;
                &lt;exclude name=&quot;ContainerManaged&quot;/&gt;
            &lt;/context&gt;
            &lt;context class=&quot;org.apache.axis2.context.ServiceGroupContext&quot;&gt;
                &lt;exclude name=&quot;my.sandesha.*&quot;/&gt;
            &lt;/context&gt;
            &lt;context class=&quot;org.apache.axis2.context.ServiceContext&quot;&gt;
                &lt;exclude name=&quot;my.sandesha.*&quot;/&gt;
            &lt;/context&gt;
        &lt;/replication&gt;
     &lt;/contextManager&gt;
   &lt;/cluster&gt;
</pre>
<p>The exclude tag tells the system to avoid replicating that particular property. This is a useful
feature as you would need to have properties that is node specific only. 
The default config in axis2 will have all properties the axis2 system doesn't want to replicate. Web Service developers can also use this to filter out properties that should be local only.
</p>

<!-- Example1 Scalability & HA with Stateless Web Service -->
<a name="scalability_stateless_example" id="scalability_stateless_example"></a>
<h2>Example 1: Scalability and HA with Stateless Web Services</h2>
<p>The following is a good example for deploying a Stateless Web Service for Scalability and High Availability.
The following service can be deployed in "application" scope in "n" nodes using a central repository. 
Once state is loaded by a particular node it will be shared by other nodes as the config context will replicate the data.
Even if two nodes load the data at the same time, there want be any conflicts as it is the same set of data.
(All nodes should synchronize their clocks using a time server to avoid loading different sets of data)</p>

<p>For the sake of this example we assume replication is cheaper than querying the database.
So once queried it will be replicated to the cluster</p>
<pre>
/**
 * This Service is responsible for providing the top 5
 * stocks for the day, week or quarter
 */
public class Top5StockService
{
	public String[] getTop5StocksForToday()
	{
		// If cache is null or invalid fetch it from data base
		ConfigurationContext configContext =
            MessageContext.getCurrentMessageContext().getConfigurationContext();
		
		String[]  symbols = (String[])configContext.getProperty(TOP5_TODAY);
		if (!checkValidity(configContext.getProperty(TOP5_TODAY_LOAD_TIME)))
                {
		    symbols = loadFromDatabase(TOP5_TODAY);
                    configContext.setProperty(TOP5_TODAY,symbols);
		    configContext.setProperty(TOP5_TODAY_LOAD_TIME,new java.util.Date()); 	 
                } 
		
		return symbols;
	}
	
	public String[] getTop5StocksForTheWeek()
	{
		 // If cache is null or invalid fetch it from data base
		.............
	}
	
	public String[] getTop5StocksForTheQuarter()
	{
		// If cache is null or invalid fetch it from data base
                ............
	}
}
</pre>

<!-- Example2 Failover for Stateful Web Service -->
<a name="failover_stateful_example" id="failover_stateful_example"></a>
<h2>Example 2: Failover for Stateful Web Services</h2>
<p>The following example demonstrates Failover support by replicating state in a service deployed in "soapsession" scope.
You can deploy the service in 2 nodes. Then point a client to the first node and add a few items to the shopping cart.
Assuming the primary node has crashed, point the client to the backup node. You should be able to checkout the cart with the items you added in the first node.</p>

<pre>
public class ShoppingCart
{	
	public final static String SHOPPING_CART = "SHOPPING_CART";
	public final static String DISCOUNT = "DISCOUNT";
	
	public void createSession()
	{
		List&lt;Item&gt; cart = new ArrayList&lt;Item&gt;();
		ServiceContext serviceContext =
            MessageContext.getCurrentMessageContext().getServiceContext();
		serviceContext.setProperty(SHOPPING_CART, cart);
	}
	
	public void addItem(Item item)
	{
		ServiceContext serviceContext =
            MessageContext.getCurrentMessageContext().getServiceContext();
		List&lt;Item&gt; cart = (List&lt;Item&gt;)serviceContext.getProperty(SHOPPING_CART);
		cart.add(item);
	}
	
	public void removeItem(Item item)
	{
		ServiceContext serviceContext =
            MessageContext.getCurrentMessageContext().getServiceContext();
		List&lt;Item&gt; cart = (List&lt;Item&gt;)serviceContext.getProperty(SHOPPING_CART);
		cart.remove(item);
	}
	
	public double checkout()
	{
		ServiceContext serviceContext =
            MessageContext.getCurrentMessageContext().getServiceContext();
		List&lt;Item&gt; cart = (List&lt;Item&gt;)serviceContext.getProperty(SHOPPING_CART);
		
		double discount = (Double)serviceContext.getServiceGroupContext().getProperty(DISCOUNT);
		
		double total = 0;
		for (Item i : cart)
		{
			total = total + i.getPrice();
		}
		
		total = total - total * (discount/100);
		
		return total;
	}	
}
</pre>

<!-- Example 3 Scalability & HA with Stateful Web Services -->
<a name="scalability_stateful_example" id="scalability_stateful_example"></a>
<h2>Example3: Scalability and HA with Stateful Web Services</h2>
<p>You can deploy the the above Shopping Cart service in several active nodes (with a backup(s) for each node). 
You only replicate to your backup nodes for Failover. The load balancer should ensure sticky sessions. 
 The strategy is to partition your load between the active nodes to achieve scalability and replication to the backups to achieve Failover. These in turn will increase the high availability of your services. Since the above example doesn't use Service Group Context to write any state there want be any conflicts.</p>

<p>For the sake of this example we assume that all read only properties for the Service Group Context is loaded at initialization
 <b><i>Please note this is the recommended approach for Stateful Web Services due to the current limitations</i></b>
</p>


<a name="summary" id="summary"></a>
<h2>Summary</h2>
<p>Apache Axis2 provides experimental support for clustering to improve the following properties of your Web Services.
<ul>
<li>Scalability</li>
<li>Failover</li>
<li>High Availability</li>
</ul>
It is important to understand the current limitations when leveraging clustering support.
</p>


<a name="furtherstudy" id="furtherstudy"></a>
<h2>For Further Study</h2>
<p><a href="../index.html">Apache Axis2</a></p>
<p><a href="Axis2ArchitectureGuide.html">Axis2 Architecture</a></p>
<p>Introduction to Apache Axis2-<a href=
"http://www.redhat.com/magazine/021jul06/features/apache_axis2/">http://www.redhat.com/magazine/021jul06/features/apache_axis2/</a></p>
</body>
</html>
