제6장 EJB 클러스터링

내용 목차

6.1. 개요
6.2. 주요 기능
6.2.1. Load Balancing
6.2.2. Failover(EJB 복구)
6.2.3. Idempotent 메소드를 통한 EJB 복구
6.2.4. Session Replication
6.3. EJB 클러스터링 설정
6.3.1. Annotation을 통한 클러스터링 설정
6.3.2. xml을 통한 클러스터링 설정
6.3.3. Stateful Session Bean의 클러스터링 설정
6.4. EJB Failover 제한

본 장에서는 EJB 클러스터링 개념과 주요 기능 설정 방법에 대해 설명한다.

EJB의 Failover와 Load Balancing 기능을 사용하기 위해서 각 Bean들은 여러 EJB 엔진에 deploy되어 클러스터링을 형성해야 한다. 클러스터링은 컴포넌트 레벨(개별 Bean)에서 수행되고 Stateless/Stateful Session Bean과 Entity Bean에서 이용할 수 있다. Message Driven Bean(MDB)은 클러스터링 대상에 해당 되지 않는다.

JEUS EJB 클러스터링은 크게 다음과 같은 2가지 기능을 갖는다.

다음 그림은 EJB 클러스터링의 주요 기능인 Failover와 Load Balancing의 동작 방식이다.



클러스터링을 원하는 모듈을 deploy하면 Naming Server에 모두 같은 이름으로 바인드된다. 클라이언트는 그 하나의 이름으로 수행해도 Load Balancing과 Failover가 가능하다. 따라서 같은 모듈이더라도 Naming Server에 바인딩할 이름을 다르게 하여 deploy하면 해당 모듈은 클러스터링되지 않음에 주의한다.

참고

Stateful Session Bean의 경우 Failover를 위해 JEUS 분산 세션 매니저(Session Manager)를 사용한다. 세션 매니저는 EJB 엔진당 하나만 존재하기 때문에 클러스터링할 Bean의 클러스터링 범위가 각 Bean별로 다르면 안 된다. 예를 들어 Bean A는 EJB einge1과 EJB engine2로 묶고 Bean B는 EJB engine1과 engine3으로 묶었다면 세션 매니저는 Bean A와 Bean B가 EJB engine1, EJB engine2, EJB engine3에 클러스터링되어 있다고 잘못 확인하게 된다.

다음은 EJB 클러스터링의 주요 기능에 대한 설명이다.

클라이언트가 lookup이나 injection에 의해 Bean A를 요청하면 Naming Server는 3개의 EJB 엔진에 존재하는 3개의 Bean 중 하나를 선택하여 반환한다. 이는 3개의 Bean들은 동일하게 같은 메소드 호출 요청을 받게 되고 잠재적으로 한 개의 엔진이 모든 요청에 대해 서비스하는 것보다 무려 3배의 시스템 성능 향상을 기대할 수 있다는 것을 의미한다(Load Balancing의 경우에 발생하는 작은 자원소모를 계산하지 않을 때).

클라이언트는 Bean의 종류에 따라 아래와 같이 동작한다.

아래의 표는 위의 EJB 버전 및 타입에 따른 Load Balancing 여부를 표로 정리한 것이다.

구분new InitialContext()lookupmethod invoke
EJB 2.x, EJB 3.x - StatefulO (Random)OX
EJB 3.x - StatelessO (Random)XO

만약 성능보다 동작방식을 우선하여 'EJB 3.x - Stateless'를 EJB 2.x과 같은 방식의 Load Balancing으로 동작시키려면 “6.3. EJB 클러스터링 설정”를 참조하여 JEUS 7 이하 버전의 클러스터링 방식을 사용해야 한다.

Failover는 하나의 EJB 서비스에 장애가 발생해도 서비스를 정상적으로 제공하는 것을 의미한다. (예: OS 장애, 네트워크 중단 또는 EJB 엔진 장애)

JEUS 시스템이 처리할 수 있는 장애 복구에는 다음의 2가지가 있다.

위의 두 시나리오의 차이는 오류 상황이 발견되는 시점이다. 즉, Remote Business 메소드를 호출하기 전인지 또는 Bean이 요청을 처리하고 있는 중인지의 예가 있을 수 있다.

Idempotent 메소드는 부작용이 없는 getter 메소드이다. 이는 메소드의 수행 중에 어떠한 상태(예: instance 변수, DB 필드 등)도 변경되지 않는 것을 보장한다.

따라서 “6.2.2. Failover(EJB 복구)”에서의 두 번째 복구 방법이 지닌 한계는 Idempotent 메소드로 극복할 수 있다. 그러나 Idempotent 메소드가 아니라면 역시 대책이 없다. 런타임 에러가 발생한 메소드를 다시 실행시키는 것보다는 Exception을 던지는 것이 차라리 낫다. 그러므로 Idempotent 메소드를 많이 사용할수록 EJB Failover는 더 잘 작동된다. 메소드가 Idempotent 메소드인지 아닌지 판단하는 공식은 없다. 그러므로 Business 메소드의 상태를 정확히 식별하고 설정해야 한다.

Stateful Session Bean의 경우 세션의 백업을 위해서 JEUS 세션 매니저를 사용한다. 일반적으로 Business 메소드 호출 단위로 세션의 상태가 변화하기 때문에 JEUS에서는 메소드 호출이 발생하고 결과가 리턴되는 시점마다 JEUS 세션 매니저에 세션 백업을 요청한다. 이러한 백업 작업을 다른 용어로 세션 복제(Session Replication)라고 한다.

JEUS 세션 매니저는 세션을 동기적(Sync) 또는 비동기적(Async)으로 복제할 수 있다. JEUS에서는 이를 복제 모드(Replication Mode)라고 한다.

2가지 방법은 서로 장단점이 있으므로 JEUS에서는 Bean과 각 Business 메소드 특성에 따라 사용자가 설정할 수 있다. 또한 세션 복제를 하지 않아도 되는 메소드가 있을 수 있으므로 이 역시 설정할 수 있다. 자세한 설정 방법은 “6.3. EJB 클러스터링 설정”을 참고한다.

참고

JEUS에서는 클러스터링에 참여한 Stateful Session Bean이라면 기본적으로 동기적(Sync) 복제 모드로 세션 복제가 이루어진다. 사용자는 설정에 의해 이를 조정할 수 있다.

EJB 클러스터링은 Bean 클래스에 Annotation으로 설정하거나 jeus-ejb-dd.xml에 설정할 수 있다. 설정할 사항은 클러스터링으로 구성될 Bean, 그 Bean의 Idempotent 메소드 그리고 Bean 또는 각 메소드의 세션 복제 모드이다.

본 절에서는 예를 통해 Annotation과 DD(xml) 파일에 클러스터링을 설정하는 방법에 대해 설명한다.

클러스터링에 참여하는 Bean 클래스 또는 메소드에 다음과 같은 Annotation을 이용하여 설정한다.


다음은 각 클래스별 설정에 대한 설명이다.

클래스설명
@jeus.ejb.Clustered

Bean의 클러스터링을 전체적으로 활성화 또는 비활성화시킨다.

useDlr=true로 설정하면 JEUS 8에 새로 들어간 속도를 개선한 클러스터링을 사용하지 않게 된다. JEUS 8 클러스터링의 Failover 방식이 이전과는 다르게 작동하기 때문에 호환성을 위한 옵션이다. JEUS 8.5에서는 EJB 3.x stateless에만 적용된다. (기본값: false)

@jeus.ejb.Idempotent
  • Bean 또는 Business 메소드가 Idempotent인지 선언한다.

  • value를 false로 하면 Idempotent하지 않은 경우이다.

  • 원격 Bean 객체를 생성하는 중 예외 상황이 발생할 경우 Stateless Session Bean에 대해서는 Idempotent로 항상 다시 시도하고 Stateful Session Bean의 경우에는 non-idempotent operation으로 애플리케이션에게 예외를 던진다.

@jeus.ejb.CreateIdempotent
  • Session Bean을 생성할 때 Idempotent하게 할지 선언한다.

  • value를 false로 하면 Idempotent하지 않은 경우이다. 만약 이 Annotation을 기술하지 않는다면 Stateless Session Bean에 대해서는 항상 Idempotent로 간주한다.

@jeus.ejb.Replication
  • Bean별 또는 각 Business 메소드별로 세션 복제 모드를 설정할 수 있다.

  • 여기에는 jeus.ejb.ReplicationMode라는 enum 타입의 클래스를 사용해야 한다. 이 클래스에 대한 것은 JEUS API 문서(javadoc)를 참고한다. 이 Annotation은 @Replication(ReplicationMode.SYNC)와 같은 식으로 사용이 가능하다. 사용자는 Bean별로 설정할 수 있으며 아무런 설정을 하지 않을 경우 디폴트는 ReplicationMode.SYNC이다. 메소드는 아무런 설정을 하지 않았을 경우 기본적으로 Bean에 설정된 값을 따른다. 단, @Idempotent인 경우는 기본적으로 ReplicationMode.NONE이다. 그리고 비즈니스 홈에 정의되는 create()는 Bean의 설정을 따른다.

JEUS EJB 모듈 DD 파일(jeus-ejb-dd.xml)에는 클러스터링에 참여하는 각각의 Bean들을 위해서 <clustering> 태그 아래에 다음과 같은 설정을 적용할 수 있다.


다음은 <clustering>의 하위 설정 태그에 대한 설명이다.

태그설명
<enable-clustering>Bean의 클러스터링을 전체적으로 활성화 또는 비활성화시킨다.
<use-dlr>

EJB 클러스터링을 사용할 때 DynamicLinkRef를 사용할지 여부를 선택한다.

  • true : JEUS 8에 새로 들어간 속도를 개선한 클러스터링을 사용하지 않게 된다. JEUS 8 클러스터링의 Failover 방식이 이전과는 다르게 작동하기 때문에, 호환성을 위한 옵션이다. JEUS 8 Fix#0에서는 EJB 3.x stateless에만 적용된다.

  • false : JEUS 8에 새로 들어간 속도를 개선한 클러스터링을 사용한다. (기본값)

<ejb-remote-idempotent-method>Bean 메소드 중에 Idempotent 메소드들을 선언한다(“6.3.1. Annotation을 통한 클러스터링 설정”의 @jeus.ejb.Idempotent 설명 참조).
<ejb-remote-idempotent-exclude-method>Bean 메소드 중에 Idempotent 메소드들로 선언한 것 중 제외하고 싶은 메소드를 선언한다. <ejb-remote-idempotent-method>보다 우선순위는 높고, 사용법은 동일하다.
<ejb-home-idempotent-method>2.x 스타일의 홈 인터페이스에 정의된 메소드 중에 Idempotent 메소드들을 선언한다(“6.3.1. Annotation을 통한 클러스터링 설정”의 @jeus.ejb.CreateIdempotent 설명 참조). 사용법은 <ejb-remote-idempotent-method>와 동일하다.
<ejb-home-idempotent-exclude-method>2.x 스타일의 홈 인터페이스에 정의된 메소드 중에 Idempotent 메소드들로 선언한 것 중 제외하고 싶은 메소드를 선언한다. <ejb-home-idempotent-method>보다 우선된다. 사용법은 <ejb-remote-idempotent-method>와 동일하다.
<create-idempotent>Session Bean을 생성할 때 Idempotent하게 할지 선언한다.
<replication>Bean 레벨의 세션 복제 모드 또는 메소드별 복제 모드를 설정한다. 자세한 내용은 “6.2.4. Session Replication”[예 6.2]를 참고한다.

위에서 지정한 Bean 클러스터링이 작동하기 위해서는 다음의 내용을 주의해야 한다.

  • 클러스터링에 참여하는 모든 Bean들은 <clustering> 하위의 모든 정보가 동일해야 한다.

  • 클러스터링으로 구성하기 위해서는 원하는 Bean의 <export-name>을 모두 동일하게 설정한다.

클러스터링 환경에서 Stateful Session Bean을 실행하려면 세션 매니저 설정을 추가로 해야 한다.

다음은 WebAdmin의 [Clusters] 메뉴를 선택한 후 [Session Router Config]Session Router Config 화면의 주요 설정 항목에 대한 설명이다. 그외 항목에 대한 자세한 설명은 JEUS 세션 관리 안내서”의 “2.7. 세션 클러스터 설정”을 참고한다.

항목설명
Passivation Timeout

Bean의 정보를 passivate하는 것과 관계된 설정이다.

EJB 엔진의 Resolution에 설정된 MS마다 passivate되거나 disconnect할 Bean이 있는지를 체크한다. 이때 마지막으로 Bean에 접근한 시간이 설정한 MS을 초과한 Bean들은 passivation 대상이 된다.

세션 설정 중 EJB passivation timeout과 관련된 설정은 Trigger - Timeout 이다.

매번 클라이언트에서 EJB Reference(Stub)를 lookup하지 않고, lookup한 EJB Reference를 Cache하여 계속 사용하는 경우(Injection을 사용하는 경우도 포함), 살아 있는 다른 EJB Endpoint가 있음에도 불구하고 Failover가 되지 않는 경우가 있을 수 있다. 이는 lookup하는 시점에 존재했던 EJB Endpoint 리스트에 해당하는 MS들이 모두 살아 있지 않고 그 이후에 구동된 새로운 MS만 존재하는 경우에 발생할 수 있다.

Failover를 해야하는 시점에서 내부적으로 lookup하여 새로운 EJB Reference를 클라이언트에게 전달한다. 그러나 이때 사용 중이던 EJB Reference가 lookup될 때 deploy되어 있던 MS들이 모두 다운되면 현재 사용 중이던 EJB Reference가 lookup될 당시 deploy되지는 않았지만 그 후에 deploy되어 Failover하는 시점에서 서비스 가능한 새로운 EJB Endpoint가 존재해도 Failover가 되지 않는다.

여기서 기존 MS들이 모두 다운되었다는 것은 비정상 종료되거나, 다운되거나, EJB Endpoint가 undeploy되어서 기존의 모든 EJB Endpoint의 서비스가 불가능한 것을 의미한다. 또한 새로운 EJB Endpoint가 deploy되는 경우는 뒤늦게(EJB Reference를 lookup하여 이미 사용 중일 때) 새로운 MS가 클러스터에 포함되거나, 뒤늦게 다운했던 MS를 재시작했거나 undeploy했던 EJB Endpoint를 뒤늦게 redeploy를 하는 경우가 포함된다.

2개의 MS로 Active/Backup 클러스터링을 구성하는 경우에 이런 현상이 발생할 수 있다. 또는 다음과 같은 시나리오에서 이런 경우가 발생할 수 있다.

예를 들어 A, B, C라는 MS가 있는데 클라이언트가 처음 lookup을 하여 계속 Cache를 하는 경우이다.

  1. A, B, C에 모두 deploy되어 있고 처음 lookup한 결과, A의 EJB를 받는다.

  2. A의 EJB를 사용하다 A가 비정상 종료되어 내부적으로 B의 EJB를 lookup하여 계속 서비스받는다.

  3. B의 EJB가 undeploy되어서 C의 EJB를 lookup해서 사용한다.

  4. 이때 다시 B의 EJB가 deploy되고, 곧이어 C가 비정상 종료되었다.

이 경우 C의 EJB Reference가 lookup될 때 B의 EJB Endpoint는 undeploy되어 있었고 C의 EJB Reference를 lookup한 다음에 deploy되었으므로 C가 다운되었을 때 B는 운용 중이었지만 Failover는 되지 않는다. 그러나 이때 B가 deploy나 undeploy된 것이 아니라 비정상 기동나 비정상 종료가 되었다면 정상적으로 Failover된다. 비정상 종료의 경우에는 Failover 시점에서 재기동 여부를 검사하기 때문에 가능하다.

이렇게 Failover가 제대로 수행되지 않는 상황에는 다시 lookup해서 새로운 EJB Reference를 가져온다. 그러면 새로운 Endpoint 목록을 가져오기 때문에 이런 문제를 피할 수 있다.