Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

How to Load Balance RESTful Web Services Using CXF and Apache Camel

DZone's Guide to

How to Load Balance RESTful Web Services Using CXF and Apache Camel

This article shows you two approaches to load balance JAXRS web services without an Apache or a hardware load balancer.

· Integration Zone
Free Resource

Migrating from On-Prem to Cloud Middleware? Here’s what Aberdeen Group says leading companies should be considering. Brought to you in partnershp with Liaison Technologies

In this article I am going to show you two approaches to load balance JAXRS web services without an Apache or a hardware load balancer. The full code is available on GitHub. CXF provides clustering strategies which can be used for configuring a load balancer which has already been discussed here. However, load balancing the JAXRS requires a little more effort, which I have described in this article.

Below are the two approaches to load balance JAXRS services using CXF and Apache Camel.

1. Using CXF Clustering With Apache Camel

In this approach, we leverage the CXF clustering and Camel to load balance the JAXRS web service. Following are the components used for achieving the load balancing:

  •  Proxy JAXRS Service

<cxf:rsServer id="LBRSServer" address="/rest"
serviceClass="com.milan.cxf.jaxrs.PersonLBService">
    <cxf:providers>
        <beans:bean class="org.codehaus.jackson.jaxrs.JacksonJsonProvider" />
        <beans:bean
class="com.milan.cxf.jaxrs.exception.ApplicationExceptionMapper" />
        <beans:bean class="com.milan.cxf.jaxrs.exception.GenericExceptionMapper" />
    </cxf:providers>
</cxf:rsServer>

This JAXRS service serves as the proxy for actual JAXRS service implementation which is hosted on multiple servers.

  •  JAXRS Client

<cxf:rsClient id="personRSServiceClient" address="/xyz"
serviceClass="com.milan.cxf.jaxrs.client.PersonRSServiceClient"
inheritHeaders="true">
    <cxf:features>
        <clustering:loadDistributor>
            <clustering:strategy>
                <beans:ref bean="sequentialStrategy" />
            </clustering:strategy>
        </clustering:loadDistributor>
    </cxf:features>
    <cxf:headers>
        <beans:entry key="Accept" value="text/xml" />
    </cxf:headers>
</cxf:rsClient>

This is a simple JAXRS client using CXF clustering feature to load balance the two servers hosting the actual JAXRS service. This can be used with Sequential or RandomStrategy to schedule the calling pattern of the two servers.Here I have used sequentialStrategy for load balancing as detailed below:

<util:list id="addressList" value-type="java.lang.String">
    <beans:value>${server1}</beans:value>
    <beans:value>${server2}</beans:value>
</util:list>
<beans:bean id="sequentialStrategy"
class="org.apache.cxf.clustering.SequentialStrategy">
    <beans:property name="alternateAddresses">
        <beans:ref bean="addressList" />
    </beans:property>
</beans:bean>

The number of servers in the addressList can be anything. In the above code, this server list is coming from config.properties file as shown below:

server1 = http://localhost:8080/CXFRS/services/rest
server2 = http://localhost:8081/CXFRS/services/rest
  • Camel Route

public class CXFLBRoute extends RouteBuilder{

    @Override
    public void configure() throws Exception
    {
        from("cxfrs:bean:LBRSServer").routeId("CXFLBRoute").autoStartup(true).log("${body}").to("cxfrs:bean:personRSServiceClient");
    }
}

This is a simple camel route which takes the request from the proxy JAXRS service and passes the message to JAXRS client which calls either of the hosted JAXRS service in the addressList based on the scheduling strategy.

2.Using Apache Camel Load Balancer Pattern

  •  Proxy JAXRS service

<cxf:rsServer id="LBRSServer" address="/rest"
serviceClass="com.milan.cxf.jaxrs.PersonLBService">
    <cxf:providers>
        <beans:bean class="org.codehaus.jackson.jaxrs.JacksonJsonProvider" />
        <beans:bean
            class="com.milan.cxf.jaxrs.exception.ApplicationExceptionMapper" />
        <beans:bean class="com.milan.cxf.jaxrs.exception.GenericExceptionMapper" />
    </cxf:providers>
</cxf:rsServer>

This JAXRS service serves as the proxy server for actual JAXRS service which is hosted on multiple servers. This is same as in Approach 1.

  •  Camel Route Using Load Balancer Pattern

public class CamelLoadBalancerRoute extends RouteBuilder{

    @Override
    public void configure() throws Exception
    {
        from("cxfrs:bean:LBRSServer").routeId("CamelLBRoute").autoStartup(true).log("${body}").process(new Processor(){
            public void process(Exchange exchange)
            {
                Map<String,Object> headerMap = exchange.getIn().getHeaders();
                String camelHttpPath = headerMap.get("CamelHttpPath").toString();
                Message message = exchange.getOut();
                message.setHeader(Exchange.HTTP_PATH, camelHttpPath);
            }
        }).convertBodyTo(InputStream.class)
    .loadBalance().roundRobin().to("{{server1}}","{{server2}}");
    }
}

This is a simple camel route which takes the request from the proxy JAXRS service, converts the body to InputStream and passes the message to one of the servers in the load balancer list. The server list is being populated into Camel PropertiesComponent in the applicationContext.xml as detailed below:

<beans:bean id="properties"
    class="org.apache.camel.component.properties.PropertiesComponent">
    <beans:property name="location"
        value="classpath:/config/config.properties" />
</beans:bean>

Using any of the above two approaches gives us a simple REST URL which we can hit and get a response directly hiding the load balancer implementation completely. Both the approaches can be used for Failover and Circuit Breaker configurations as well.

The code comprises of two Gradle projects:

1. CXLB: This is a load balancer application.This needs to be deployed on one of the nodes in our cluster. Update the con/config.xml file with the JAXRS server list where CXFRS is deployed to make it function correctly.

2. CXFRS: JAXRS web service code. This needs to be deployed on as many nodes as we want in our cluster.

We just need to do Gradle clean build the two projects and deploy the wars on different servers.

Try load-balancing JAXRS web services using this example!

Is iPaaS solving the right problems? Not knowing the fundamental difference between iPaaS and iPaaS+ could cost you down the road. Brought to you in partnership with Liaison Technologies.

Topics:
cxf ,apache camel ,spring ,jaxrs ,java ,xml

Opinions expressed by DZone contributors are their own.

THE DZONE NEWSLETTER

Dev Resources & Solutions Straight to Your Inbox

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.

X

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}