Tuesday, October 26, 2010

Weighted Round-Robin and Random Load balancing further simplified in Camel

I have further simplified the weighted round-robin and random load balancing support in Camel 2.6 based on comments and feedback from Claus Ibsen (http://davsclaus.blogspot.com/).

The changes are primarily in 2 areas

1> In Camel 2.5, in the case where the distributionRatio did not match the number
     of specified load balancing processors, I had opted to use best effort load balancing
     at runtime along with log warnings. In Camel 2.6, this behavior has now been
     changed to throw an exception during route startup to indicate that the
     distributionRatio does not match the number of processors.

2> In Camel 2.5 , the distributionRatio was passed to DSL or Spring XML as a List 
     as shown in
         a> http://opensourceknowledge.blogspot.com/2010/10/added-support-for-weighted-round-robin.html
         b> Camel Documentation (http://camel.apache.org/load-balancer.html).
               I have modified this in Camel 2.6 based on Claus' recommendation and made 

               it easier for the user by changing the distribution ratio to a String that expects
               an input of integer weights separated by a delimiter. The delimiter can also be
               influenced using distributionRatioDelimiter String (the default delimiter being ",").

Given below are examples of how this simplifies the DSL for Camel 2.6

public void testRoundRobin() throws Exception {

        x.expectedMessageCount(5);
        y.expectedMessageCount(2);
        z.expectedMessageCount(1);

        context.addRoutes(new RouteBuilder() {
            public void configure() {
                
                // START SNIPPET: example
                from("direct:start").loadBalance().
                weighted(true, "4,2,1").to("mock:x", "mock:y", "mock:z");
                // END SNIPPET: example
            }
        });
        context.start();
        
        sendMessages(1, 2, 3, 4, 5, 6, 7, 8);
        
        assertMockEndpointsSatisfied();
        x.expectedBodiesReceived(1, 4, 6, 7, 8);
        y.expectedBodiesReceived(2, 5);
        z.expectedBodiesReceived(3);
    }

For Spring XML examples, please check out the following links

weightedRoundRobinLoadBalance.xml
weightedRandomLoadBalance.xml

Thursday, October 14, 2010

Added support for Weighted Round-Robin and Weighted Random Load balancing in Camel

I have just added a new capability in Camel 2.5, to offer Weighted Round-Robin and Weighted Random Load Balancer support.

Camel currently offers several different Load Balancing policies out of the box such as
  • Round-Robin
  • Random
  • Sticky
  • Topic Based and
  • Fail-over
However, in many enterprise environments where server nodes of unequal processing power & performance characteristics are utilized to host services and processing endpoints, it is frequently necessary to distribute processing load based on their individual server capabilities so that some endpoints are not unfairly burdened with requests. Obviously simple round-robin or random load balancing do not alleviate problems of this nature. A Weighted Round-Robin and/or Weighted Random load balancer is invaluable in this regard.

The weighted load balancing policy allows you to specify a processing load distribution ratio for each server with respect to others. You can specify this as a positive processing weight for each server. A larger number indicates that the server can handle a larger load. The weight is utilized to determine the payload distribution ratio to different processing endpoints with respect to others.

In addition to the weight, endpoint selection is then further refined based on an algorithm (round-robin/random).

Weighted Round Robin Load Balancing

Given below is a Camel example of the weighted round-robin capability in action. Note that there are 3 mock camel endpoints (mock:x, mock:y and mock:z). The important thing is to associate a distribution ratio (list of server weights) and wire it into a load balancer on the route  along with a boolean value (specifying whether the distribution algorithm is round-robin (true in this case).

In the example below we expect endpoints mock:x, mock:y and mock:z to receive 4, 2 and 1 messages  out of every 7 messages respectively. In addition we expect each endpoint to receive messages in strict round-robin order until its weight no longer permits further delivery of messages until the next cycle.

public void testRoundRobin() throws Exception {

        x.expectedMessageCount(5);
        y.expectedMessageCount(2);
        z.expectedMessageCount(1);

        context.addRoutes(new RouteBuilder() {
            public void configure() {
                ArrayList distributionRatio = new ArrayList();
                distributionRatio.add(4);
                distributionRatio.add(2);
                distributionRatio.add(1);
                
                // START SNIPPET: example
                from("direct:start").loadBalance().
                weighted(true, distributionRatio).to("mock:x", "mock:y", "mock:z");
                // END SNIPPET: example
            }
        });
        context.start();
        
        sendMessages(1, 2, 3, 4, 5, 6, 7, 8);
        
        assertMockEndpointsSatisfied();
        x.expectedBodiesReceived(1, 4, 6, 7, 8);
        y.expectedBodiesReceived(2, 5);
        z.expectedBodiesReceived(3);
    }

Weighted Random Load Balancing

Given below is a Camel example of the weighted round-robin capability in action. Note that there are 3 mock camel endpoints (mock:x, mock:y and mock:z). Again in this case, the important thing is to associate a distribution ratio (list of server weights) and wire it into a load balancer on the route  along with a boolean value (specifying whether the distribution algorithm is round-robin (false in this case).

In the example below we expect endpoints mock:x, mock:y and mock:z to receive 4, 2 and 1 messages out of every 7 messages respectively. In addition we expect each endpoint to receive messages in a random order until its weight no longer permits further delivery of messages until the next cycle.

public void testRandom() throws Exception {

        x.expectedMessageCount(4);
        y.expectedMessageCount(2);
        z.expectedMessageCount(1);

        context.addRoutes(new RouteBuilder() {
            public void configure() {
                ArrayList distributionRatio = new ArrayList();
                distributionRatio.add(4);
                distributionRatio.add(2);
                distributionRatio.add(1);
                
                // START SNIPPET: example
                from("direct:start").loadBalance().
                weighted(false, distributionRatio).to("mock:x", "mock:y", "mock:z");
                // END SNIPPET: example
            }
        });
        context.start();
        
        sendMessages(1, 2, 3, 4, 5, 6, 7);
        
        assertMockEndpointsSatisfied();
    }

Complete Examples
WeightedRoundRobinLoadBalanceTest
WeightedRandomLoadBalanceTest

Further Details
https://issues.apache.org/activemq/browse/CAMEL-3197