16.2 클러스터링의 핵심기술
JGroups
JGroups는 멀티캐스트 프로토콜을 사용하여 신뢰성 높은 통신을 할 수 있도록 구현된 네트워크 통신 라이브러리이다. JBoss EAP 6의 클러스터링 구현, Infinispan의 네트워크 캐시 구현, HornetQ의 클러스터링 구현 등에 JGroups(http://www.jgroups.org)가 사용된다.
JGroups에서 중요한 프로토콜은 가입과 탈퇴(JOIN/REMOVE), 장애 감지(FD, FD_SOCK) 파티션 결합(MERGE), PING이다.
| 항목 | 설명 |
|---|---|
| 가입(JOIN) | JGroups를 시작할 때 만들어지는 멀티캐스트 그룹 가입을 위한 방식이다. 처음으로 가입하여 다른 멤버가 없으면 리더(코디네이터)가 된다. 멤버가 있으면 기존 리더에게 참가 요청을 하여 멤버 리스트에 추가해 달라고 한다. 그러면 리더가 그룹에 속한 모든 멤버들에게 클러스터 멤버 리스트를 배포하고 정보를 공유한다. |
| 탈퇴(REMOVE) | 탈퇴(REMOVE)은 JGroups 정지시 멀티캐스트 그룹에서 탈퇴하기 위한 것이다. 리더가 아닌 일반 멤버가 탈퇴하는 경우에는 리더가 클러스터 멤버 리스트를 업데이트하고 다른 멤버에게 배포한다. 리더 자신이 탈퇴하는 경우엔 두 번째 멤버가 리더가 되고 클러스터 멤버 리스트를 업데이트하여 다른 멤버에게 배포한다. 마지막 멤버가 탈퇴하면 그 그룹은 없어진다. |
| 장애 감지(FD) | 장애 감지(FD; Failure Detection)는 Heart Beat 메시지를 사용하여 오류가 발생한 멤버를 감지하는 것이다. 각 멤버는 Heart Beat 메시지를 수신하면 응답 메시지를 보내 정상적인 상태 임을 알려야 한다. 지정한 타임아웃 시간 동안 재시도하여 응답을 받지 못하면, 멤버에 오류가 발생한 것으로 간주하여 클러스터 멤버에서 제거한다. |
| 장애 감지 소켓(FD_SOCK) | 장애 감지 소켓(FD_SOCK)은 클러스터 멤버들간에 TCP 소켓으로 A → B → C → A처럼 링 모양으로 연결하여 상태를 모니터링하기 위한 프로토콜이다. 링 모양이기 때문에 각 멤버는 그 이웃 멤버만 감시하게 된다. 멤버 B가 정상 종료할 때는 멤버 A에 메시지를 보내 종료되는 것을 알려준다. 만약, 멤버 B에 장애가 발생하여 갑자기 종료되면, 멤버 A는 연결된 소켓이 비정상 종료되는 것을 감지할 수 있다. 장애를 감지하면 확인 단계를 거치고 장애가 확실하면 클러스터 멤버 리스트에서 삭제한다. |
| 파티션 결합 (MERGE2) | MERGE는 통신 장애 등 여러 가지 이유로 멀티캐스트 그룹이 여러 개로 나뉜 경우 쪼개진 그룹을 하나로 결합하기 위한 것이다. 리더(코디네이터)는 주기적으로 리더가 여기 있다는 멀티캐스트 메시지를 보낸다. 만약 그룹이 쪼개져서 만들어진 다른 그룹의 리더가 이 메시지를 받으면 결합 프로세스를 시작한다. {A, B}와 {C, D, E}을 결합하여 하나의 {A, B, C, D, E}의 그룹으로 만든다. |
| PING | 처음 클러스터의 멤버를 발견하는 데 사용하는 프로토콜이다. 멀티캐스트 주소에 MPING 요청을 보내서 리더(코디네이터)를 찾고 다른 멤버들을 찾는다. 멀티캐스트를 사용할 수 없는 환경에서는 TCPPING이나 GOSSIP 서버를 이용한 TCPGOSSIP, 공유 파일 시스템을 이용한 FILE_PING, 데이터베이스 테이블을 사용하는 JDBC_PING, 아마존 AWS 환경에서 S3(Simple Storage Service)를 사용한 S3_PING, 오픈스택의 Swift를 사용한 SWIFT_PING등 다양한 방식의 PING을 설정할 수 있다. |
표 1. JGroups의 주요 프로토콜
JBoss EAP 6에서는 ha, full-ha 프로파일에 jgroups 서브 시스템이 설정되어 있다. jgroups 서브시스템에는 멀티캐스트를 사용하는 udp 프로토콜 스택과 TCP를 사용하는 tcp 프로토콜 스택이 정의되어 있고, 기본적으로 udp 프로토콜을 사용하도록 설정되어 있다. 아래의 내용을 살펴보면, 방금 설명한 FD, FD_SOCK, PING등 여러 가지 복잡한 값들이 설정되어 있다. 대부분 기본값을 그대로 사용하면 된다.
<subsystem xmlns="urn:jboss:domain:jgroups:1.1" default-stack="udp">
<stack name="udp">
<transport type="UDP" socket-binding="jgroups-udp"/>
<protocol type="PING"/>
<protocol type="MERGE3"/>
<protocol type="FD_SOCK" socket-binding="jgroups-udp-fd"/>
<protocol type="FD"/>
<protocol type="VERIFY_SUSPECT"/>
<protocol type="pbcast.NAKACK"/>
<protocol type="UNICAST2"/>
<protocol type="pbcast.STABLE"/>
<protocol type="pbcast.GMS"/>
<protocol type="UFC"/>
<protocol type="MFC"/>
<protocol type="FRAG2"/>
<protocol type="RSVP"/>
</stack>
<stack name="tcp">
<transport type="TCP" socket-binding="jgroups-tcp"/>
<protocol type="MPING" socket-binding="jgroups-mping"/>
<protocol type="MERGE2"/>
<protocol type="FD_SOCK" socket-binding="jgroups-tcp-fd"/>
<protocol type="FD"/>
<protocol type="VERIFY_SUSPECT"/>
<protocol type="pbcast.NAKACK"/>
<protocol type="UNICAST2"/>
<protocol type="pbcast.STABLE"/>
<protocol type="pbcast.GMS"/>
<protocol type="UFC"/>
<protocol type="MFC"/>
<protocol type="FRAG2"/>
<protocol type="RSVP"/>
</stack>
</subsystem>
다음과 같이 default-stack을 tcp로 변경하면 TCP를 사용하도록 변경할 수 있다.
<subsystem xmlns="urn:jboss:domain:jgroups:1.1" default-stack="tcp">
멀티캐스트 통신
멀티캐스트 통신은 특정 주소에 참여하는 모든 호스트에 동시에 같은 메시지를 전송하는 통신 방식이다. 멀티캐스트에 사용하는 주소는 IP 주소 상의 D 클래스로 앞의 4 비트가 1110인 224.0.0.0 ~ 239.255.255.255 범위의 주소를 사용한다. 라우터에서 사용하도록 예약된 주소가 있어 실제로 애플리케이션에서 사용할 수 있는 주소는 224.0.1.0 ~ 238.255.255.255 이다.

그림 3. 멀티캐스트 주소
멀티캐스트 통신의 장점은 패킷이 멀티캐스트 그룹 단위로 하나만 전송되기 때문에 네트워크 트래픽이 혼잡해지지 않는다는 것이다. 유니캐스트는 멤버 수만큼 여러 번 패킷을 전송해야 한다.
호스트에 여러 개의 네트워크 인터페이스 카드가 있으면 첫 번째 인터페이스를 멀티캐스트 통신에 사용한다. 다음과 같이 설정하면 지정된 인터페이스 카드를 통해 멀티캐스트 통신할 수 있다.
$ route add-net 231.12.21.0 netmask 255.255.255.0 <인터페이스>
IPv6를 사용할 수 있는 운영체제에서는 기본적으로 소켓이 IPv6를 사용하기 때문에 Java가 IPv6를 사용한다. IPv4를 사용하도록 설정하려면 Java 실행 시 다음 옵션을 지정한다.
-Djava.net.preferIPv4Stack=true
멀티캐스트 테스트
멀티캐스트는 먼저 운영체제에서 멀티캐스트할 수 있게 설정되어야 하며, 사용하는 라우터에서도 멀티캐스트 프로토콜을 지원해야 한다. 멀티캐스트가 가능한 환경인지 테스트하는 있는 방법이 필요하다.
jgroups 라이브러리에는 마치 채팅과 같이 멀티캐스트를 사용하여 메시지를 보내는 테스트 애플리케이션을 제공하고 있다.
다음 명령으로 지정한 멀티캐스트 IP, 포트에 참여하여 메시지를 수신하는 애플리케이션을 시작한다.
$ java -cp jgroups-3.2.5.Final.jar org.jgroups.tests.McastReceiverTest -mcast_addr 224.10.10.10 -port 5555
다음 명령으로 지정한 멀티캐스트 IP, 포트로 메시지를 보내는 애플리케이션을 실행하여, 멀티캐스트로 전송할 텍스트 메시지를 입력한다.
$ java -cp jgroups-3.2.5.Final.jar org.jgroups.tests.McastSenderTest -mcast_addr 224.10.10.10 -port 5555
Socket #2=0.0.0.0/0.0.0.0:5555, ttl=32, bind interface=/192.168.0.23
Socket #4=0.0.0.0/0.0.0.0:5555, ttl=32, bind interface=/127.0.0.1
> test
먼저 실행한 멀티캐스트 수신 애플리케이션에 메시지가 수신되면, 멀티캐스트 통신이 정상적으로 동작하는 것이다.
$ java -cp jgroups-3.2.5.Final.jar org.jgroups.tests.McastReceiverTest -mcast_addr 224.10.10.10 -port 5555
Socket=0.0.0.0/0.0.0.0:5555, bind interface=/192.168.0.28
Socket=0.0.0.0/0.0.0.0:5555, bind interface=/127.0.0.1
test [sender=192.168.0.23:5555]
test [sender=192.168.0.23:5555]