8.10. Load Balancer
概述
通过 负载均衡器 模式,您可以使用各种不同负载平衡策略将消息处理委托给多个端点之一。
Java DSL 示例
以下路由使用轮循负载均衡策略在目标端点( mock:x、mock:y、mock:z )之间分发传入的信息:
from("direct:start").loadBalance().roundRobin().to("mock:x", "mock:y", "mock:z");XML 配置示例
以下示例演示了如何在 XML 中配置相同的路由:
<camelContext xmlns="http://camel.apache.org/schema/spring">
<route>
<from uri="direct:start"/>
<loadBalance>
<roundRobin/>
<to uri="mock:x"/>
<to uri="mock:y"/>
<to uri="mock:z"/>
</loadBalance>
</route>
</camelContext>负载均衡策略
Apache Camel 负载均衡器支持以下负载均衡策略:
轮循
循环负载平衡策略在所有目标端点上循环,将每个传入消息发送到周期中的下一端点。例如,如果目标端点列表为: mock:x,mock:y,,则传入的消息会发送到以下端点序列:mock:z mock:x,mock:y, mock:z , mock:x, mock:x ,mock:y,mock:z, mock:z 等等。
您可以在 Java DSL 中指定循环负载均衡策略,如下所示:
from("direct:start").loadBalance().roundRobin().to("mock:x", "mock:y", "mock:z");另外,您可以在 XML 中配置相同的路由,如下所示:
<camelContext xmlns="http://camel.apache.org/schema/spring">
<route>
<from uri="direct:start"/>
<loadBalance>
<roundRobin/>
<to uri="mock:x"/>
<to uri="mock:y"/>
<to uri="mock:z"/>
</loadBalance>
</route>
</camelContext>随机
随机负载均衡策略从指定列表随机选择目标端点。
您可以在 Java DSL 中指定随机负载均衡策略,如下所示:
from("direct:start").loadBalance().random().to("mock:x", "mock:y", "mock:z");另外,您可以在 XML 中配置相同的路由,如下所示:
<camelContext xmlns="http://camel.apache.org/schema/spring">
<route>
<from uri="direct:start"/>
<loadBalance>
<random/>
<to uri="mock:x"/>
<to uri="mock:y"/>
<to uri="mock:z"/>
</loadBalance>
</route>
</camelContext>sticky
粘性负载平衡策略通过将 In 消息定向到端点,该端点通过计算指定表达式中的哈希值来选择。此负载均衡策略的优点是,相同值的表达式始终会发送到同一服务器。例如,通过计算包含 username 的标头的 hash 值,请确保来自特定用户的消息始终发送到同一目标端点。另一种有用的方式是指定从传入消息中提取会话 ID 的表达式。这样可确保属于同一会话的所有消息都发送到同一目标端点。
您可以在 Java DSL 中指定粘性负载均衡策略,如下所示:
from("direct:start").loadBalance().sticky(header("username")).to("mock:x", "mock:y", "mock:z");另外,您可以在 XML 中配置相同的路由,如下所示:
<camelContext xmlns="http://camel.apache.org/schema/spring">
<route>
<from uri="direct:start"/>
<loadBalance>
<sticky>
<correlationExpression>
<simple>header.username</simple>
</correlationExpression>
</sticky>
<to uri="mock:x"/>
<to uri="mock:y"/>
<to uri="mock:z"/>
</loadBalance>
</route>
</camelContext>在故障转移负载均衡器中添加 sticky 选项时,负载均衡器会从最后一个已知的好端点开始。
Topic
主题负载均衡策略会将每个 In 消息的副本发送到所有列出的目标端点(有效地将消息广播到所有目的地,如 JMS 主题)。
您可以使用 Java DSL 指定主题负载均衡策略,如下所示:
from("direct:start").loadBalance().topic().to("mock:x", "mock:y", "mock:z");另外,您可以在 XML 中配置相同的路由,如下所示:
<camelContext xmlns="http://camel.apache.org/schema/spring">
<route>
<from uri="direct:start"/>
<loadBalance>
<topic/>
<to uri="mock:x"/>
<to uri="mock:y"/>
<to uri="mock:z"/>
</loadBalance>
</route>
</camelContext>故障切换
对于 Apache Camel 2.0,故障转移 负载均衡器可以在处理过程中 异常 时尝试下一个处理器。您可以使用触发 故障转移 的特定例外列表配置故障转移。如果没有指定任何例外,则任意异常会触发故障转移。故障转移负载平衡器使用与 Exception 例外条款相同的策略。
如果使用流流,在使用故障转移负载均衡器时应启用 流缓存。这需要,以便在故障切换时重新读取流。
故障转移 负载均衡器支持以下选项:
| 选项 | 类型 | 默认值 | 描述 |
|
|
|
|
Camel 2.3: 指定是否使用路由
例如, |
|
|
|
|
Camel 2.3: 指定切换到新端点的最大尝试次数。值 |
|
|
|
|
Camel 2.3: 指定 |
以下示例配置为仅引发 IOException 异常:
from("direct:start")
// here we will load balance if IOException was thrown
// any other kind of exception will result in the Exchange as failed
// to failover over any kind of exception we can just omit the exception
// in the failOver DSL
.loadBalance().failover(IOException.class)
.to("direct:x", "direct:y", "direct:z");您可以选择指定多个例外来故障切换,如下所示:
// enable redelivery so failover can react
errorHandler(defaultErrorHandler().maximumRedeliveries(5));
from("direct:foo")
.loadBalance()
.failover(IOException.class, MyOtherException.class)
.to("direct:a", "direct:b");您可以在 XML 中配置相同的路由,如下所示:
<route errorHandlerRef="myErrorHandler">
<from uri="direct:foo"/>
<loadBalance>
<failover>
<exception>java.io.IOException</exception>
<exception>com.mycompany.MyOtherException</exception>
</failover>
<to uri="direct:a"/>
<to uri="direct:b"/>
</loadBalance>
</route>以下示例演示了如何以 round robin 模式进行故障转移:
from("direct:start")
// Use failover load balancer in stateful round robin mode,
// which means it will fail over immediately in case of an exception
// as it does NOT inherit error handler. It will also keep retrying, as
// it is configured to retry indefinitely.
.loadBalance().failover(-1, false, true)
.to("direct:bad", "direct:bad2", "direct:good", "direct:good2");您可以在 XML 中配置相同的路由,如下所示:
<route>
<from uri="direct:start"/>
<loadBalance>
<!-- failover using stateful round robin,
which will keep retrying the 4 endpoints indefinitely.
You can set the maximumFailoverAttempt to break out after X attempts -->
<failover roundRobin="true"/>
<to uri="direct:bad"/>
<to uri="direct:bad2"/>
<to uri="direct:good"/>
<to uri="direct:good2"/>
</loadBalance>
</route>
如果想要尽快切换到下一个端点,您可以通过配置 inheritErrorHandler =false 来禁用 inheritErrorHandler。通过禁用 Error Handler,您可以确保它不会干预。这允许故障切换负载均衡器尽快处理故障切换。如果您还启用 roundRobin 模式,则会持续重试,直到它成功为止。然后,您可以将 max FailoverAttempts 选项配置为高值,使其最终耗尽和失败。
随机的权重轮询和权重
在许多企业环境中,未处理电源的服务器节点是托管服务的,通常最好根据各个服务器处理容量来分布负载。可以使用权重的 循环 算法或 加权随机 算法来解决这个问题。
通过加权的负载平衡策略,您可以为每个服务器指定处理负载 分布比,但与其他服务器相关。您可以将这个值指定为每台服务器的正处理权重。较大的数字表示服务器可以处理更大的负载。处理 weight 用于决定每个处理端点的载荷分布比方。
下表描述了可使用的参数:
表 8.3. 加权选项
| 选项 | 类型 | 默认值 | 描述 |
|---|---|---|---|
|
|
|
|
round-robin 的默认值为 |
|
|
|
|
|
以下 Java DSL 示例演示了如何定义权重的循环路由和权重的随机路由:
// Java
// round-robin
from("direct:start")
.loadBalance().weighted(true, "4:2:1" distributionRatioDelimiter=":")
.to("mock:x", "mock:y", "mock:z");
//random
from("direct:start")
.loadBalance().weighted(false, "4,2,1")
.to("mock:x", "mock:y", "mock:z");您可以在 XML 中配置循环路由,如下所示:
<!-- round-robin -->
<route>
<from uri="direct:start"/>
<loadBalance>
<weighted roundRobin="true" distributionRatio="4:2:1" distributionRatioDelimiter=":" />
<to uri="mock:x"/>
<to uri="mock:y"/>
<to uri="mock:z"/>
</loadBalance>
</route>自定义 Load Balancer
您还可以使用自定义负载均衡器(如您自己的实现)。
使用 Java DSL 的示例:
from("direct:start")
// using our custom load balancer
.loadBalance(new MyLoadBalancer())
.to("mock:x", "mock:y", "mock:z");使用 XML DSL 的相同示例:
<!-- this is the implementation of our custom load balancer -->
<bean id="myBalancer" class="org.apache.camel.processor.CustomLoadBalanceTest$MyLoadBalancer"/>
<camelContext xmlns="http://camel.apache.org/schema/spring">
<route>
<from uri="direct:start"/>
<loadBalance>
<!-- refer to my custom load balancer -->
<custom ref="myBalancer"/>
<!-- these are the endpoints to balancer -->
<to uri="mock:x"/>
<to uri="mock:y"/>
<to uri="mock:z"/>
</loadBalance>
</route>
</camelContext>注意在上面的 XML DSL 中,我们使用 <custom>,它仅适用于 Camel 2.8。在较旧的版本中,您需要执行如下操作:
<loadBalance ref="myBalancer">
<!-- these are the endpoints to balancer -->
<to uri="mock:x"/>
<to uri="mock:y"/>
<to uri="mock:z"/>
</loadBalance>
要实现自定义负载均衡器,您可以扩展 LoadBalancerSupport 和 SimpleLoadBalancerSupport 等一些支持类别。前者支持异步路由引擎,后者不支持。下面是一个示例:
public static class MyLoadBalancer extends LoadBalancerSupport {
public boolean process(Exchange exchange, AsyncCallback callback) {
String body = exchange.getIn().getBody(String.class);
try {
if ("x".equals(body)) {
getProcessors().get(0).process(exchange);
} else if ("y".equals(body)) {
getProcessors().get(1).process(exchange);
} else {
getProcessors().get(2).process(exchange);
}
} catch (Throwable e) {
exchange.setException(e);
}
callback.done(true);
return true;
}
}断路器
Circuit Breaker 负载均衡器是一个有状态模式,用于监控特定异常的所有调用。最初,断路器处于关闭状态并传递所有消息。如果失败且达到阈值,则会进入打开状态并拒绝所有调用,直到达到 一半OpenAfter 超时为止。超时后,如果出现一个新调用,断路器将传递所有消息。如果结果成功,Circuit Breaker 会进入关闭状态(如果不是),它会重新变为开放状态。
Java DSL 示例:
from("direct:start").loadBalance()
.circuitBreaker(2, 1000L, MyCustomException.class)
.to("mock:result");Spring XML 示例:
<camelContext id="camel" xmlns="http://camel.apache.org/schema/spring">
<route>
<from uri="direct:start"/>
<loadBalance>
<circuitBreaker threshold="2" halfOpenAfter="1000">
<exception>MyCustomException</exception>
</circuitBreaker>
<to uri="mock:result"/>
</loadBalance>
</route>
</camelContext>