12장. 메시징 서브시스템
이번 장에서는 메시징 서브시스템에 대해 설명한다.
메시징 서브시스템은 Java EE 6의 중요한 컴포넌트 중 하나인 Java Message Service(JMS)를 제공하기 위한 서브시스템이다. 먼저 JMS의 개념 및 메시징 서브시스템을 간단하게 설명하고 JMS 서브시스템의 설정 방법을 설명한다.
1.메시징 개념
대부분 요청을 보내면 응답이 오기까지 기다리는 동기 처리에 익숙하여서, 요청을 보낸 후 응답을 기다리지 않고 곧바로 다른 일을 처리하는 비동기 처리에 대해 막연히 불안하게 생각될 수 있다.
비동기 처리에 대해 자주 예로 드는 것이 메일이다. 일상생활에서 종이로 보내는 메일이나 전자메일 모두 보내는 즉시 답변 메일이 오는 것이 아녀서 기다리지 않는다. 반면 전화는 실생활에서 경험할 수 있는 대표적인 동기 처리의 예이다. 통화 상 대가 다른 일을 하고 있었더라도 연결되면 전화 통화를 시작하게 된다.
엔터프라이즈 시스템에서는 일반적으로 MQ(Message Queue) 혹은 MOM(Message Oriented Middleware)라고 부르는 비동기 메시징 시스템을 사용하여 여러 시스템 간에 메시지를 전송하여 처리하는 메시지 교환 시스템을 구현해 왔다. JMS는 Java 애플리케이션에서 이런 메시징 시스템을 구현하기 위한 표준이며, Java EE에도 초기부터 포함된 비교적 오랜 시간동안 발전해 온 표준이다. JMS를 사용하면 Java EE환경에서 간단하게 비동기 메시지 처리를 구현할 수 있다. 비동기 메시징을 사용하면 시스템 성능 향상, 자원 효율화, 처리 순서지정 등 여러 가지 장점이 있다.
시스템 간 메시지 전송을 비동기로 설계하면 하드웨어 리소스 사용률이 줄어들고 IO 작업을 최소화하며 네트워크 대역폭을 더 적게 사용할 수 있다.
동기 전송을 사용하는 RPC 방법은 요청에 대한 응답을 기다려야 하기 때문에 네트워크 지연 시간이 발생한다.
메시징 시스템은 메시지를 보내는 메시지 제공자와 메시지를 받는 메시지 소비자와 분리하여 처리한다. 메시지 제공자와 소비자는 완전히 독립적이며 유연하고 느슨한 결합 시스템을 만들 수 있다.
JMS는 메시지 지향 미들웨어(Message Oriented Middleware : MOM)라는 메시징 시스템에 접근하기 위한 표준 인터페이스이다. 즉 메시징 시스템 자체의 구현이 아닌 MOM 서비스를 이용하기 위한 Java 기반의 표준 인터페이스이다. JMS는 Java EE에 포함되어 있으며 JMS 표준은 벤더 중립적이다.
JMS 제공자는 트랜잭션 시스템을 사용하여 변경 사항을 원자적으로 커밋 또는 롤백한다. RPC를 기반으로 하는 시스템과 달리 메시징 시스템은 요청과 응답 사이에 비동 기 메시지 전달 패턴을 주로 사용한다.
JMS를 이용하여 여러 애플리케이션이 서로 메시지를 전송하여 통신할 수 있다. 대부분의 메시징 형태는 피어 투 피어 형이고 JMS 애플리케이션은 대부분 ‘클라이언트’가 된다. JMS는 J2EE의 다른 서비스(JTA/JTS, JNDI, JDBC 등)와 연계하여 Servlet, JSP, EJB 애플리케이션에서 사용할 수 있다. 또 메시지 드리븐 빈을 통해 JMS메시지를 수신하여 동작하는 비동기 EJB를 만들 수 있다.
JMS의 특징을 정리하면 다음과 같다.
- Java 애플리케이션에서 기존 MOM시스템과 메시지를 주고받을 수 있다.
- 메시지를 작성하고 송수신하기 위한 표준 인터페이스가 제공되어 메시징 애플리케이션 개발이 쉬워진다.
- 표준화된 메시징 API 를 사용하여 메시징 애플리케이션의 이식성을 높일 수 있다.
2.JMS 메시징 모델
일반적으로 메시징 시스템은 두 가지 비동기 메시징 패턴을 사용한다. 하나는 메시지 큐 방식의 PTP(point-to-point) 패턴과 다른 하나는 게시/가입 패턴(Publish/Subscribe) 메시지 방식이다. PTP는 메시지 큐를 사용하고 있어 하나의 대상(destination)에 대해 하나의 소스에서 메시지가 전송된다. Pub/Sub는 하나의 소스에서 여러 클라이언트에 같은 메시지를 동시에 전달한다. JMS는 이 두 가지 메시지 모델과 애플리케이션 개발에 필요한 클라이언트 인터페이스를 제공한다.
3.PTP패턴
PTP 메시징은 먼저 메시지를 큐에 보낸다. 메시지는 일반적으로 전송을 보장하기 위해 디스크에 저장된다. 다음 메시징 시스템이 메시지를 소비자에게 전달한다. 소비자는 메시지를 처리하고 처리가 완료되면 승인 메시지를 보낸다. 승인 메시지를 받으면 메시징 큐에서 메시지는 삭제되고 다시 배포할 수 없다. 메시징 서버가 소비자로부터 승인을 받기 전에 오류가 발생한 경우에는 복구하여 다시 메시지를 소비자에게 보낼 수 있다.
P2P 메시징에서 같은 큐를 바라보는 여러 소비자가 있을 수 있지만, 특정 메시지는 하나의 소비자에게서만 처리된다. 큐에 메시지를 보낸 제공자는 큐에서 메시지를 받는 소비자와 완전히 분리된다. 즉, 보낸 사람과 받는 사람이 서로의 존재를 인지할 필요가 없다.
기업의 도서 주문 시스템의 주문 큐가 P2P 메시징의 전형적인 예제이다. 각 주문은 주문 큐에 전송되는 메시지가 된다. 주문 큐로 메시지를 보내는 주문 시스템을 생각해보자. 메시지가 큐에 도착하면 일단 저장한다. 이렇게 하면 오류가 발생했을 때 주문 정보가 유실되지 않는다. 또한, 주문 큐에 많은 소비자가 있다고 생각하자. 각 소비자는 주문을 처리하는 인스턴스라고 생각할 수 있다. 메시징 시스템은 각 메시지를 하나의 주문 처리 컴포넌트로 전달한다. 다양한 메시지를 각종 주문 프로세서에서 처리 할 수 있지만 하나의 주문은 1개의 주문 프로세서에서만 처리된다. 이렇게 하면 주문이 두 번 처리되지 않는다.
주문처리 프로세서가 메시지를 받으면 도서 주문이 완료되고, 주문된 정보가 물류 시스템으로 전송되어 데이터베이스에 주문 정보가 업데이트된다. 주문 프로세서가 데이터베이스를 업데이트하면 주문이 처리되며 완료됐다는 메시지를 서버에게 알린다. 창고의 재고관리 시스템에 전송할 수도 있고, 데이터베이스의 업데이트는 단일 트랜잭션으로 완료한다.

그림 1. P2P 메시징 시스템
4.게시-가입 패턴
게시-가입 메시징은 게시자(Publisher)가 어떤 가입자(Subscriber)가 있는지 모르는 상태에서 메시지를 보내게 되고 이렇게 전송된 메시지가 여러 가입자에게 모두 전달되는 구조이다. 즉, 1:N 형식으로 여러 가입자에게 동시에 메시지를 전달하고 싶을 때 사용한다.
JMS에서는 이런 형식의 메시징을 ‘토픽(Topic)’이라고 부른다.
게시-가입 메시징에서도 영속성을 유지할 수 있다. PTP 메시징과 마찬가지로 가입자가 메시지를 완전히 소비할 때까지 메시지의 복사본을 유지하고 있다가 처리가 완료되면 삭제하는 방식이다.
게시-가입 메시징의 대표적인 예제는 뉴스 피드이다. 전세계에서 발생하는 다양한 뉴스가 작성되면 뉴스 피드에 전송된다. 뉴스 기사를 받아보고 싶은 많은 구독자가 세계 곳곳에 걸쳐 있다. 뉴스 피드를 관리하는 시스템은 구독자들에게 뉴스 메시지의 복사본을 전달하면, 구독자들은 각자에게 전달된 최신 뉴스를 읽어 볼 수 있게 된다.

그림 2. 게시-구독 메시징 시스템
5.HornetQ
JBoss EAP 6의 JMS 구현은 JBoss.org 커뮤니티에서 개발된 HornetQ 라는 고성능, 고신뢰성, 유연성을 특징으로 하는 비동기 메시징 시스템이 사용되었다.
JBoss Messaging 2.0이라는 이름으로 프로젝트를 진행하다 HornetQ로 이름을 변경하여 독립 프로젝트로 진행되었다.
HornetQ의 내부 통신모듈은 Netty 라는 고성능 네트워크 애플리케이션 프레임워크를 사용하고 있다. 또, 메시지를 저장하는데 최적화된 저널이라는 파일기반의 영속화 시스템을 갖추고 있다. Linux 환경에서는 저널을 더 빠르게 처리할 수 있도록 AIO(Asynchronous I/O) 플러그인도 제공하고 있다.
HornetQ의 유연한 클러스터링 기능을 제공하여 메시지를 분산하여 처리할 수 있다. 또, 고가용성이 요구되는 엔터프라이즈에서 사용하는데 문제가 되지 않도록 클러스터링 구성을 라이브 백업 구성으로 구현할 수 있다.
6.JMS의 이용
Java EE 6에서는 JMS는 Full 프로파일에 포함되어 있고 웹 프로파일에는 포함되어 있지 않다. 스탠드얼론 모드에서 파일명을 지정하지 않고 JBoss EAP 6를 시작하면 웹 프로파일을 사용하게 되기 때문에 Messaging 서브시스템을 이용하려면 풀 프로파일의 설정 파일인 standalone-full.xml을 지정하고 시작해야 한다.
$./standalone.sh --server-config=standalone-full.xml