8.10. 로드 밸런서

8.10.1. 개요

로드 밸런서 패턴을 사용하면 다양한 로드 밸런싱 정책을 사용하여 메시지 처리를 여러 끝점 중 하나에 위임할 수 있습니다.

8.10.2. Java DSL 예

다음 경로는 라운드 로빈 로드 밸런싱 정책을 사용하여 대상 끝점 mock:x,mock:y,mock:z 사이에 수신 메시지를 배포합니다.

from("direct:start").loadBalance().roundRobin().to("mock:x", "mock:y", "mock:z");

8.10.3. 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>

8.10.4. 로드 밸런싱 정책

Apache Camel 로드 밸런서는 다음과 같은 로드 밸런싱 정책을 지원합니다.

8.10.5. 라운드 로빈

라운드 로빈 로드 밸런싱 정책은 모든 대상 끝점을 통해 사이클에서 들어오는 각 메시지를 다음 엔드포인트로 전송합니다. 예를 들어 대상 끝점 목록이, mock:x,mock:y,mock:z 인 경우 수신되는 메시지는 끝점의 다음 시퀀스로 전송됩니다. mock:x,mock:y,mock:x, mock:x ,mock: y 등.

다음과 같이 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>

8.10.6. random

임의의 로드 밸런싱 정책은 지정된 목록에서 임의로 대상 끝점을 선택합니다.

다음과 같이 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>

8.10.7. 고정

고정 로드 밸런싱 정책은 지정된 표현식의 해시 값을 계산하여 선택한 엔드포인트로 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>
참고

장애 조치 로드 밸런서에 고정 옵션을 추가하면 로드 밸런서가 마지막으로 알려진 좋은 끝점에서 시작됩니다.

8.10.8. 주제

주제 부하 분산 정책은 나열된 모든 대상 끝점에 각 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>

8.10.9. 페일오버

Apache Camel 2.0에서 사용 가능한 장애 조치 로드 밸런서는 처리 중에 예외적으로 Exchange가 실패한 경우 다음 프로세서를 시도할 수 있습니다. 장애 조치를 트리거하는 특정 예외 목록을 사용하여 장애 조치를 구성할 수 있습니다. 예외를 지정하지 않으면 예외를 통해 페일오버가 트리거됩니다. 장애 조치 로드 밸런서는 onException 예외 절과 일치하는 예외에 대해 동일한 전략을 사용합니다.

스트림을 사용하는 경우 스트림 캐싱 활성화

스트리밍을 사용하는 경우 장애 조치 로드 밸런서를 사용할 때 스트림 캐싱 을 활성화해야 합니다. 실패할 때 스트림을 다시 읽을 수 있도록 이 작업이 필요합니다.

장애 조치 로드 밸런서는 다음 옵션을 지원합니다.

옵션

유형

Default

설명

inheritErrorHandler

boolean

true

Camel 2.3: 경로에 구성된 errorHandler 사용 여부를 지정합니다. 다음 끝점으로 즉시 장애 조치하려면 이 옵션( false)을 비활성화해야 합니다. 이 옵션을 활성화하면 Apache Camel에서 먼저 errorHandler 를 사용하여 메시지를 처리하려고 합니다.

예를 들어 메시지를 다시 전달하고 시도 사이에 지연을 사용하도록 오류 처리기 를 구성할 수 있습니다. Apache Camel은 처음에 원래 엔드포인트로 다시 전달하려고 시도하며, errorHandler 가 소진된 경우에만 다음 끝점으로 장애 조치됩니다.

maximumFailoverAttempts

int

-1

Camel 2.3: 새 엔드포인트로 장애 조치하려는 최대 시도 횟수를 지정합니다. 값 0 에서는 장애 조치 시도가 이루어지지 않으며-1 은 장애 조치(failover) 시도 횟수가 없음을 의미합니다.

roundRobin

boolean

false

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>

다음 예제에서는 라운드 로빈 모드에서 장애 조치하는 방법을 보여줍니다.

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 를 비활성화할 수 있습니다. 오류 처리기를 비활성화하면 개입하지 않도록 할 수 있습니다. 이렇게 하면 장애 조치 로드 밸런서가 가능한 한 빨리 장애 조치(failover)를 처리할 수 있습니다. 또한 roundRobin 모드를 활성화하면 성공할 때까지 재시도됩니다. 그런 다음 최대FailoverAttempts 옵션을 높은 값으로 구성하여 결국 소진하고 실패하도록 할 수 있습니다.

8.10.10. weighted round robin 및 weighted random

일반적으로 개별 서버 처리 용량에 따라 부하를 배포하는 것이 좋습니다.In many enterprise environments, where server nodes of processing power are hosting services, it is usually preferable to distribute the load in accordance with the individual server processing capacityacities. 가중치가 지정된 라운드 로빈 알고리즘 또는 가중치가 지정된 임의 알고리즘을 사용하여 이 문제를 해결할 수 있습니다.

가중치가 지정된 부하 분산 정책을 사용하면 다른 서버와 관련하여 각 서버에 대한 처리 부하 분산 비율 을 지정할 수 있습니다. 이 값을 각 서버의 양의 처리 가중치로 지정할 수 있습니다. 숫자가 클수록 서버가 더 큰 부하를 처리할 수 있음을 나타냅니다. 처리 가중치는 다른 처리 끝점과 관련하여 각 처리 끝점의 페이로드 분배 비율을 결정하는 데 사용됩니다.

사용할 수 있는 매개변수는 다음 표에 설명되어 있습니다.

표 8.3. weighted Options

옵션유형Default설명

roundRobin

boolean

false

라운드 로빈의 기본값은 false 입니다. 이 설정 또는 매개변수가 없으면 사용된 로드 밸런싱 알고리즘은 random입니다.

distributionRatioDelimiter

문자열

,

distributionRatioDelimiterdistributionRatio 를 지정하는 데 사용되는 구분 기호입니다. 이 속성이 지정되지 않은 경우 쉼표는 기본 구분 기호입니다.

다음 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>

8.10.11. 사용자 정의 로드 밸런서

사용자 정의 로드 밸런서(예: 자체 구현)도 사용할 수 있습니다.

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;
     }
 }

8.10.12. 회로 차단기

회로 차단기 로드 밸런서는 특정 예외에 대한 모든 호출을 모니터링하는 데 사용되는 상태 저장 패턴입니다. 처음에 회로 차단기는 폐쇄 상태에 있으며 모든 메시지를 전달합니다. 실패가 있고 임계값에 도달하면 state로 이동하고 halfOpenAfter 시간 초과에 도달할 때까지 모든 호출을 거부합니다. 시간 초과 후 새 호출이 있는 경우 회로 차단기는 모든 메시지를 전달합니다. 결과가 성공하면 회로 차단기가 닫힌 상태로 이동합니다. 그렇지 않으면 열린 상태로 돌아갑니다.

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>