This recipe will guide you through the basic concepts of clustering ServiceMix using the JMS and competing consumers pattern. Clustering is the process of distributing an application's workload among multiple servers.
Let's assume that your integration solution reads from several sources of messages and then processes them using some custom processing class:
1. public class NonClusteredRoute extends RouteBuilder { 2. 3. public void configure() throws Exception { 4. 5. from("direct:processor").process(new BusinessProcessor()).to("jms:processedMessages"); 6. 7. from("file:/home/myapp/inbox").to("direct:processor"); 8. from("jms:incomingMessages").to("direct:processor"); 9. from("pop3://[email protected]?password=secret"). 10. to("direct:processor"); 11. } 12. 13. }
Lines 5-6 tell Camel to use BusinessProcessor
in order to process messages incoming to the system.
Line 7 defines the File
consumer, which reads data from the local file system and converts it into the messages ready to be consumed by BusinessProcessor
.
Line 8 defines a JMS
consumer reading messages directly from the queue named incomingMessages
.
Lines 9-10 create a POP3 consumer that reads e-mails from the mail.com
server and sends them to the same BusinessProcessor
as the rest of the system does.
The problem with the integration solution above is that whenever BusinessProcessor
processes the messages too slow, reading from the source endpoints will wait idle until our system will process the incoming messages.
What we want to do is to cluster the solution above, so we could split it across many machines. In order to achieve ServiceMix clustering, we will take advantage of the JMS feature called competing consuming.
Create a separated route for each source endpoint (
FileRoute
,MailRoute
,JmsRoute
).Send messages from every source endpoint to the same JMS queue.
Create a fourth route (
BusinessProcessingRoute
) consuming messages from common JMS queue.Deploy each route on a separate physical machine.
To increase the processing capacity of the
BusinessProcessor
, deploy an additional machine withBusinessProcessingRoute
.
At some point of the load, your integration solution will become incapable of processing incoming messages. Or at least incapable of processing incoming messages within the required period of time. Such a scenario happens usually when the Camel consumer endpoints start to receive more messages than the processing part of the solution can handle.
One approach to the load issue is to scale your ServiceMix up. Scaling up means basically the same as scaling vertically, that is, adding more hardware resources to the single ServiceMix instance. Of course, more CPU, additional cores, or some extra memory can make your ServiceMix process incoming messages faster.
But you cannot add additional resources to the same physical machine infinitely. At some point, even the strongest (and most terribly expensive) computer will reach its limits. And this will basically mean that all the money invested into your super-computer will become insufficient.
In practice, software architects rarely scale their solutions up. Instead they scale their architecture out (horizontally). Scaling out means adding more processing nodes to the existing software infrastructure. So how can multiple ServiceMix instances communicate with each other in order to process incoming messages concurrently? We have to split our monolithic route into three smaller consumer routes—each one will read from another message source.
The following route demonstrates how can we read from file system and immediately forward processing to the JMS queue.
1. public class FileRoute extends RouteBuilder { 2. 3. public void configure() throws Exception { 4. from("file:/home/myapp/inbox").to("jms:businessQueue"); 5. } 6. 7. }
In line 4 of the preceding route, we read messages from the file system and then send them to the common JMS queue named businessQueue
.
The following route applies the same logic to the source JMS queue:
public class JmsRoute extends RouteBuilder { public void configure() throws Exception { from("jms:incomingMessages").to("jms:businessQueue"); } }
The fourth line of the above route forwards messages from the source JMS queue (incomingMessages
) to the same common queue as the rest of the source routes (FileRoute
and MailRoute
).
public class MailRoute extends RouteBuilder { public void configure() throws Exception { from("pop3://[email protected]?password=secret").to("jms:businessQueue"); } }
All the source routes (FileRoute
, MailRoute
, and JmsRoute
) delegate the processing logic to the dedicated ServiceMix instances. Messages to be processed are sent to the JMS queue named businessQueue
. The following code listing demonstrates how Camel can be used to read from that queue and process the collected messages:
public class BusinessProcessingRoute extends RouteBuilder { public void configure() throws Exception { from("jms:businessQueue"). process(new BusinessProcessor()). to("jms:processedMessages"); } }
We can deploy any number of BusinessProcessingRoute
classes. JMS will take care of the synchronization of the consumers reading from the queue and guarantee us that each message from the businessQueue
queue will be read only by one consumer (this feature of the JMS is called the competing consumers support).
Instead of having a single ServiceMix instance consuming messages from all possible sources, we created separated routes that read from the various sources independently and delegate processing to the JMS queue (businessQueue
). If at some point of the message's traffic, two BusinessProcessingRoute
routes will not be able to process the messages sufficiently fast, you can start another machine with the additional BusinessProcessingRoute
deployed to it.
The competing JMS consumer is one of the ways to cluster ServiceMix. Keep in mind, however, that load balancing of the ESB highly depends on what kind of services are deployed into it. We decided to focus on the competing consumers model in this book, as this is probably the easiest way to scale the majority of the messaging solutions.
Managing multiple ServiceMix instances may be a tough task. If you want to make it easier, consider using Apache Karaf Cellar or FuseFabric. Cellar (http://karaf.apache.org/index/subprojects/cellar.html) is a subproject of Karaf, dedicated for clustering the latter with Hazelcast (http://www.hazelcast.com). Fabric (http://fuse.fusesource.org/fabric) is another tool for managing multiple ServiceMix instances, however it takes advantage of Apache ZooKeeper (http://zookeeper.apache.org) to organize Karaf nodes.