8.10. Load Balancer


概述

通过 负载均衡器 模式,您可以使用各种不同的负载平衡策略将消息处理委派给多个端点之一。

Java DSL 示例

以下路由使用 round robin 负载均衡策略在目标端点 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 负载均衡器支持以下负载平衡策略:

round robin

循环通过所有目标端点进行负载平衡策略周期,将每个传入消息发送到周期中的下一个端点。例如,如果目标端点列表是 mock:x,mock:y,mock:z ,,进入的消息将发送到以下端点序列: mock:x,mock:y, mock:z ,mock:x, mock:y ,mock:y,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 消息定向到通过计算指定表达式中的哈希值来选择的端点。这种负载平衡策略的优点是,相同值的表达式始终发送到同一服务器。例如,通过计算包含用户名的标头的哈希值,您可以确保特定用户的消息始终发送到同一目标端点。另一种有用的方法是指定一个表达式,从传入消息中提取会话 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 开始,故障转移 负载均衡器能够尝试下一个处理器,以防交换在处理期间失败。您可以使用触发 故障转移 的特定例外列表配置故障切换。如果没有指定任何异常,则任何异常会触发故障转移。故障转移负载平衡器使用与 onException 异常条款相同的策略。

使用流时启用流缓存

如果使用流,在使用故障转移负载均衡器时应启用 流缓存。这是必要的,以便在失败时重新读取流。

故障转移 负载均衡器支持以下选项:

选项

类型

Default(默认)

描述

inheritErrorHandler

布尔值

true

Camel 2.3: 指定是否使用路由上配置的 errorHandler。如果要立即切换到下一个端点,您应该禁用这个选项(值为 false)。如果启用这个选项,Apache Camel 将首先尝试使用 errorHandler 处理消息。

例如,errorHandler 可能被配置为 redeliver 消息,并在尝试之间使用延迟。Apache Camel 最初会尝试重新显示 到原始 端点,只有在错误处理程序耗尽时,才会切换到下一个端点。

maximumFailoverAttempts

int

-1

Camel 2.3: 指定尝试故障转移到新端点的最大次数。值 0 表示没有进行故障转移尝试,值 -1 表示是无限数量的故障转移尝试。

roundRobin

布尔值

false

Camel 2.3: 指定 故障转移 负载均衡器是否应该以轮循模式运行。如果没有,它将 始终在 处理新消息时从第一个端点启动。换句话说,它会针对每个消息从顶部重新启动。如果启用了循环,它会保持状态,并以轮循方式继续进行下一端点。当使用 round robin 时,它不会记住最后一个已知的良好端点,它将始终选择要使用的下一个端点。

以下示例被配置为故障切换,只有在抛出 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 模式,它会一直重试,直到成功为止。然后您可以将 maximumFailoverAttempts 选项配置为高值,使其最终耗尽并失败。

加权轮循和权重随机

在许多企业环境中,不等处理能力的服务器节点是托管服务的,通常最好根据各个服务器处理容量来分发负载。可以使用 加权循环 算法或 加权随机 算法来解决这个问题。

加权负载平衡策略允许您为每个服务器 指定处理负载比率。您可以将这个值指定为每台服务器的正处理权重。较大的数字表示服务器可以处理更大的负载。处理权重用于决定每个处理端点的有效负载分布比例与其它端点相关。

下表描述了可以使用的参数:

表 8.3. 加权选项
选项类型Default(默认)描述

roundRobin

布尔值

false

round-robin 的默认值为 false。如果没有此设置或参数,则使用负载平衡算法是随机的。

distributionRatioDelimiter

字符串

,

distributionRatioDelimiter 是用于指定 发布率 的分隔符。如果没有指定此属性 逗号 是默认的分隔符。

以下 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>

要实现自定义负载均衡器,您可以扩展一些支持类,如 LoadBalancerSupportSimpleLoadBalancerSupport。前者支持异步路由引擎,后者则不支持。下面是一个示例:

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 负载均衡器是一个有状态模式,用于监控特定异常的所有调用。最初,断路器处于关闭状态,并传递所有消息。如果失败并且达到阈值,它将进入 open 状态并拒绝所有调用,直到达到 一半OpenAfter 超时为止。超时后,如果存在新调用,则 Circuit Breaker 将传递所有消息。如果结果成功,则 Circuit Breaker 将变为 closed 状态(如果不是),则会返回开放状态。

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>
Red Hat logoGithubRedditYoutubeTwitter

学习

尝试、购买和销售

社区

关于红帽文档

通过我们的产品和服务,以及可以信赖的内容,帮助红帽用户创新并实现他们的目标。

让开源更具包容性

红帽致力于替换我们的代码、文档和 Web 属性中存在问题的语言。欲了解更多详情,请参阅红帽博客.

關於紅帽

我们提供强化的解决方案,使企业能够更轻松地跨平台和环境(从核心数据中心到网络边缘)工作。

© 2024 Red Hat, Inc.