在此示例中,我们将向您展示如何使用Apache Camel作为系统的负载平衡器。 在计算机世界中,负载均衡器是一种充当反向代理并在许多服务器之间分配网络或应用程序流量的设备。 负载平衡器用于增加容量(并发用户)和应用程序的可靠性。 借助Camel,我们可以立即制作自己的软件负载平衡器。 享受骑行!
负载均衡不是《企业集成模式》一书中的单独模式(就像克劳斯·易卜生所说的那样,如果本书有第二版的话),但是骆驼把它当作另一个EIP对待。 尽管Camel语法使负载平衡看起来非常容易,但这仍然是一个复杂的话题,您应该花一些时间在设计阶段规划合适的策略。 Camel带有许多内置的负载平衡策略。 在此示例中,我们介绍了其中一些更常用的方法。
本文的代码使用Maven 3.3.9,Eclipse Mars 4.5.0和Apache Camel 2.17.1。 请注意,自2.15版本以来,负载平衡器API有所更改,如果您要使用Camel的早期版本,请查阅文档。 此示例源代码中的所有类都使用@Test带注释的方法,因此您必须将它们作为JUnit测试运行,并希望看到绿色的条。
1.创建基础项目
在继续编写实际代码之前,首先要在Eclipse中创建一个Maven项目。 首先选择File-> New…-> new project。 键入maven并选择Maven项目。
在下一个窗口中,检查创建简单项目选项,然后单击下一步:
最后添加以下配置,然后单击完成:
现在编辑pom.xml文件,如下所示:
pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.javacodegeeks</groupId>
<artifactId>camelLoadBalancer</artifactId>
<version>1.0.0-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-core</artifactId>
<version>2.17.1</version>
</dependency>
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-test</artifactId>
<version>2.17.1</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
</dependencies>
</project>
2.负载均衡
我们提到了骆驼支持的不同政策,但是什么是政策? 策略定义工作负载如何在不同的接收方(处理器,消费者服务…)之间分配。 在本文中,我们播出了随机,轮循及其加权对应项和主题策略的示例。 最后,我们向您展示如何制定自己的政策。
随机
负载平衡策略的最简单形式是随机的。 顾名思义,您只需定义应处理负载的端点,然后Camel即可随机决定使用哪个端点。 这是实现随机策略的代码。 m1,m2和m3是处理消息的端点。 终结点始终会收到该消息,但是每次运行该类时,都会使用上述终结点之一。 这种选择是完全随机的,您可以通过添加自己的断言来检查这种随机性。
RandomLoadBalance.java
package com.jcg;
import org.apache.camel.EndpointInject;
import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.component.mock.MockEndpoint;
import org.apache.camel.test.junit4.CamelTestSupport;
import org.junit.Test;
public class RandomLoadBalance extends CamelTestSupport{
@EndpointInject(uri="mock:m1")
MockEndpoint m1;
@EndpointInject(uri="mock:m2")
MockEndpoint m2;
@EndpointInject(uri="mock:m3")
MockEndpoint m3;
@EndpointInject(uri="mock:end")
MockEndpoint end;
@Override
protected RouteBuilder createRouteBuilder() throws Exception{
return new RouteBuilder(){
@Override
public void configure() throws Exception {
from("direct:start").loadBalance().random().to(m1,m2,m3).end().to(end);
}
};
}
@Test
public void testSending() throws Exception{
end.expectedMessageCount(1);
template.sendBody("direct:start", "");
end.assertIsSatisfied();
}
}
轮巡
轮询是负载平衡的另一种简单类型。 在此策略中,依次依次使用端点。 在示例代码中,您会看到消息通过m1,m2,m3并再次通过m1。
RoundRobinLoadBalance.java
package com.jcg;
import javax.naming.Context;
import org.apache.camel.EndpointInject;
import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.component.dataset.SimpleDataSet;
import org.apache.camel.component.mock.MockEndpoint;
import org.apache.camel.test.junit4.CamelTestSupport;
import org.junit.Test;
public class RoundRobinLoadBalance extends CamelTestSupport{
@EndpointInject(uri="mock:m1")
MockEndpoint m1;
@EndpointInject(uri="mock:m2")
MockEndpoint m2;
@EndpointInject(uri="mock:m3")
MockEndpoint m3;
@EndpointInject(uri="mock:end")
MockEndpoint end;
@Override
protected RouteBuilder createRouteBuilder() throws Exception{
return new RouteBuilder(){
@Override
public void configure() throws Exception {
from("dataset:start").loadBalance().roundRobin().to(m1,m2,m3).end().to(end);
}
};
}
@Override
protected Context createJndiContext() throws Exception{
SimpleDataSet sds = new SimpleDataSet();
sds.setSize(4);
Context context = super.createJndiContext();
context.bind("start", sds);
return context;
}
@Test
public void testSending() throws Exception{
m1.expectedMessageCount(2);
m2.expectedMessageCount(1);
m3.expectedMessageCount(1);
end.expectedMessageCount(4);
template.sendBody("dataset:start", "");
m1.assertIsSatisfied();
m2.assertIsSatisfied();
m3.assertIsSatisfied();
end.assertIsSatisfied();
}
}
加权轮循
在现实世界中,很少有相同的计算机可以满足您的请求。 因此,拥有一台可能更强大的机器比其他机器做更多的工作有意义。 加权轮询和加权随机分别是轮询策略和随机策略的更复杂对应物。 使用加权轮询(或随机轮询),您可以细粒度地控制负载平衡。 这里我们给出一个加权轮循的例子。 加权随机是相同的。
weight方法有两个参数。 首先是一个布尔值,它定义策略是循环(true)还是随机(false)。 第二个参数是一个字符串,它定义相应端点的分配比率。 这里的“ 2,1”表示m1接收到的流量是m2接收到的流量的两倍。 在早期版本的Camel中,您必须使用整数列表。
WeightedRoundRobinLoadBalance.java
package com.jcg;
import javax.naming.Context;
import org.apache.camel.EndpointInject;
import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.component.dataset.SimpleDataSet;
import org.apache.camel.component.mock.MockEndpoint;
import org.apache.camel.test.junit4.CamelTestSupport;
import org.junit.Test;
public class WeightedRoundRobinLoadBalance extends CamelTestSupport{
@EndpointInject(uri="mock:m1")
MockEndpoint m1;
@EndpointInject(uri="mock:m2")
MockEndpoint m2;
@EndpointInject(uri="mock:end")
MockEndpoint end;
@Override
protected RouteBuilder createRouteBuilder() throws Exception{
return new RouteBuilder(){
@Override
public void configure() throws Exception {
// first argument of weighted method is a boolean defines if the policy is
// Round robin (true) or Random (false)
from("dataset:start").loadBalance().weighted(true,"2,1").to(m1,m2).end().to(end);
}
};
}
@Override
protected Context createJndiContext() throws Exception{
SimpleDataSet sds = new SimpleDataSet();
sds.setSize(6);
Context context = super.createJndiContext();
context.bind("start", sds);
return context;
}
@Test
public void testSending() throws Exception{
m1.expectedMessageCount(4);
m2.expectedMessageCount(2);
end.expectedMessageCount(6);
template.sendBody("dataset:start", "");
m1.assertIsSatisfied();
m2.assertIsSatisfied();
end.assertIsSatisfied();
}
}
话题
主题从根本上不同于其他策略,因为所有端点都收到消息。 在我们的示例代码m1,m2和m3中,全部处理5条消息,并且端点也接收5条消息。 主题对于防止端点故障很有用。
TopicLoadBalance.java
package com.jcg;
import javax.naming.Context;
import org.apache.camel.EndpointInject;
import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.component.dataset.SimpleDataSet;
import org.apache.camel.component.mock.MockEndpoint;
import org.apache.camel.test.junit4.CamelTestSupport;
import org.junit.Test;
public class TopicLoadBalance extends CamelTestSupport{
@EndpointInject(uri="mock:m1")
MockEndpoint m1;
@EndpointInject(uri="mock:m2")
MockEndpoint m2;
@EndpointInject(uri="mock:m3")
MockEndpoint m3;
@EndpointInject(uri="mock:end")
MockEndpoint end;
@Override
protected RouteBuilder createRouteBuilder() throws Exception{
return new RouteBuilder(){
@Override
public void configure() throws Exception {
from("dataset:start").loadBalance().topic().to(m1,m2,m3).end().to(end);
}
};
}
@Override
protected Context createJndiContext() throws Exception{
SimpleDataSet sds = new SimpleDataSet();
sds.setSize(5);
Context context = super.createJndiContext();
context.bind("start", sds);
return context;
}
@Test
public void testSending() throws Exception{
m1.expectedMessageCount(5);
m2.expectedMessageCount(5);
m3.expectedMessageCount(5);
end.expectedMessageCount(5);
template.sendBody("dataset:start", "");
m1.assertIsSatisfied();
m2.assertIsSatisfied();
m3.assertIsSatisfied();
end.assertIsSatisfied();
}
}
自定义负载均衡器
骆驼提供了许多有用的策略,但是总有一些策略无法满足您的需求。 在这种情况下,您必须定义自己的负载平衡策略,但Camel不会让您感到孤独。 自定义负载平衡器使您可以轻松定义自己的策略。 在示例代码中,我们定义了一个负载均衡器,用于检查消息头“ sessionID”字段。 如果是偶数,则将其发送到m1;如果是m2,则将其发送给m1。 当然,这是一个不现实的示例,但是我们故意简化了能够专注于负载平衡实现而又没有业务逻辑混乱的情况。 首先,我们创建一个扩展LoadBalancerSupport类并覆盖处理方法的类。 然后,我们将此类的实例传递给loadBalance方法。
SessionChecker.java
package com.jcg;
import org.apache.camel.AsyncCallback;
import org.apache.camel.Exchange;
import org.apache.camel.processor.loadbalancer.LoadBalancerSupport;
public class SessionChecker extends LoadBalancerSupport{
@Override
public boolean process(Exchange exchange, AsyncCallback callback) {
int id = exchange.getIn().getHeader("sessionID", Integer.class);
try{
if(id%2 == 0){
getProcessors().get(0).process(exchange);
} else{
getProcessors().get(1).process(exchange);
}
}catch(Exception e){
e.printStackTrace();
}
callback.done(true);
return true;
}
}
CustomLoadBalance.java
package com.jcg;
import java.util.HashMap;
import java.util.Map;
import javax.naming.Context;
import org.apache.camel.EndpointInject;
import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.component.dataset.SimpleDataSet;
import org.apache.camel.component.mock.MockEndpoint;
import org.apache.camel.test.junit4.CamelTestSupport;
import org.junit.Test;
public class CustomLoadBalance extends CamelTestSupport{
@EndpointInject(uri="mock:m1")
MockEndpoint m1;
@EndpointInject(uri="mock:m2")
MockEndpoint m2;
@EndpointInject(uri="mock:end")
MockEndpoint end;
@Override
protected RouteBuilder createRouteBuilder() throws Exception{
return new RouteBuilder(){
@Override
public void configure() throws Exception {
from("dataset:start").loadBalance(new SessionChecker()).to(m1,m2).end().to(end);
}
};
}
@Override
protected Context createJndiContext() throws Exception{
SimpleDataSet sds = new SimpleDataSet();
Map<String, Object> headers = new HashMap<>();
headers.put("sessionID", 1);
sds.setDefaultHeaders(headers);
sds.setSize(2);
Context context = super.createJndiContext();
context.bind("start", sds);
return context;
}
@Test
public void testSending() throws Exception{
m1.expectedMessageCount(0);
m2.expectedMessageCount(2);
end.expectedMessageCount(2);
template.sendBody("dataset:start", "");
m1.assertIsSatisfied();
m2.assertIsSatisfied();
end.assertIsSatisfied();
}
}
3.结论
骆驼负载平衡还有更多。 我们没有涵盖诸如故障转移,粘性和断路器之类的策略。 实际上,骆驼不仅仅局限于此。 您可以在更多情况下使用负载平衡,例如客户端和服务器之间的HTTP代理。
4.下载Eclipse项目
这是不同的Camel负载平衡策略的示例。
您可以在此处下载此示例的完整源代码: Camel负载均衡器
翻译自: https://www.javacodegeeks.com/2016/06/load-balancing-apache-camel.html