소개

본 장에서는 HMS에 관한 소개와 구조를 서술하고, 메시징 시스템에 관한 기본적 개념과 용어를 설명한다.

1. 개요

메시징 시스템(Messaging System)이란 송신자(Sender)와 수신자(Receiver) 사이의 느슨한 결합(loosely coupled)을 가능하게 하는 통신 매개체이다. 메시징 시스템을 사용하여 송신자와 수신자는 서로에 관한 정보를 알 필요없이 가상적 채널, 즉 Destination에 관한 정보만 가지고 서로 통신할 수 있다. 또한 송신하는 시점과 수신하는 시점을 분리할 수 있어 데이터에 대한 지연처리가 가능하며, 이를 위해 메시징 시스템은 메시지의 송수신에 대한 신뢰성(Reliability)을 보장한다.

Hybrid Messaging System(이하 HMS)은 엔터프라이즈 시스템 사이에 이루어지는 정보 교환의 양상을 메시지라는 형태의 데이터와 Destination이라는 가상적인 채널로 추상화한다. 사용자가 생성한 메시지는 관리자에 의해 생성된 가상 채널인 Destination에 전달되며 이 정보가 필요한 애플리케이션은 언제라도 이 Destination에 자신을 등록하여 메시지를 얻어올 수 있다. HMS는 Sun Microsystems에서 재정한 Java 기반의 메시징 시스템 표준인 JMS(Java Messaging Service)의 개념과 동작방식을 반영하였다.

HMS는 TP-Monitor인 Tmax 시스템에서 동작하므로 사용자는 TP-Monitor의 기능과 메시징 시스템의 기능을 유연하게 결합하여 사용할 수 있다. 리소스 매니저(Resource Manager, 이하 RM)와의 2PC(2 Phase Commit) 기능, 백업 노드 설정으로 장애가 발생한 경우 유연한 대처 등이 가능하다.

2. HMS 구조

HMS는 Tmax 시스템 안에서 멀티 스레드 프로세스로 동작한다.

figure hms architecture
HMS의 동작 구조

HMS의 스레드는 다음과 같이 2가지로 구분된다.

  • Main Thread

    메인 스레드는 클라이언트, 서비스 등 Tmax와의 통신 부분을 담당하며 해당 요청이나 메시지를 워커 스레드로 전달하는 역할을 한다.

  • Worker Thread

    워커 스레드는 일반 스레드와 스토리지 스레드로 구분된다. 메시지나 요청의 종류에 따라 스토리지 관련 작업이 필요한 경우에는 스토리지 스레드가 그 외의 경우에는 일반 스레드가 해당 메시지나 요청을 처리한다.

    각 워커 스레드의 개수는 환경 파일에 사용자가 직접 설정할 수 있다. 설정하지 않으면 기본적으로 일반 스레드는 2개, 스토리지 스레드는 4개로 동작한다. 스토리지 스레드의 개수는 많을수록 무조건 좋은 것은 아니며, 운영 시스템의 성능과 스토리지의 성능에 따라 적절한 값을 설정해주어야 한다.

3. JMS와 HMS 프로그래밍

다음은 JMS와 HMS에서 사용하는 프로그래밍 모델을 나타낸 것이다.

figure programming model
프로그래밍 모델

HMS를 사용하기 위해서는 메시징 시스템에 대한 기본적 개념과 용어에 대한 이해가 필요하다. HMS는 JMS의 개념을 사용하므로 앞으로의 설명에서 사용하는 용어는 JMS에서 사용하는 용어와 동일하다.

3.1. Connection

HMS 기능을 사용하려고 하는 애플리케이션은 기본적으로 Tmax와의 연결을 맺어야 한다. 기동되면서 자동으로 연결을 맺는 서버 애플리케이션과는 달리 클라이언트 애플리케이션은 HMS 관련 API를 사용하기 전에 tpstart()를 이용해 Tmax와의 연결을 맺어야만 한다. 연결이 종료될 경우 클라이언트가 tpend()를 수행하거나 서버가 종료될 경우 애플리케이션에서 생성한 세션과 클라이언트 정보가 HMS에서 모두 삭제된다.

3.2. Session

세션(Session)은 HMS 기능을 사용하는 데에 가장 기본이 되는 처리 단위이다.

HMS에서 사용하는 세션은 다음의 4가지로 구분된다.

  • 일반 세션

    세션은 Tmax와의 연결이 존재하는 상태에서 생성해야 하며 하나의 애플리케이션 안에서 다수의 세션을 생성할 수도 있다. 세션을 생성하기 위해서는 대상 HMS의 이름이 필요하고 생성될 경우 세션의 여러 가지 속성을 부여할 수 있다.

    다음은 세션의 기본적인 속성이다.

    속성 설명

    Transacted

    세션의 Transacted 속성 사용 여부를 결정한다.

    Acknowledge Mode

    메시지 수신에 대한 응답 방법의 종류를 결정한다.

    현재 지원하는 응답 방법은 다음과 같다.

    • AUTO_ACK : 자동으로 응답

    • CLIENT_ACK : 사용자가 응답을 직접 전송

  • Transacted 세션

    Transacted 세션은 생성될 때 Transacted 속성을 부여받아 생성된 세션이다. 주로 로컬 트랜잭션을 사용하기 위해 사용한다. Transacted 세션에서는 메시지 송수신의 결과가 HMS로 즉시 반영되지 않는다. hms_commit(), hms_rollback() API를 통해 반영 여부를 결정한다.

    예를 들어 Transacted 세션으로 생성된 생산자가 다수의 메시지를 송신하고 hms_rollback()을 했다면 송신했던 메시지는 Destination에 들어가지 않고 무시된다. 메시지를 수신할 때 결과 반영 여부를 hms_commit(), hms_rollback()으로 결정하게 된다. Transacted 세션에서는 AUTO_ACK만 허용한다.

  • XA 세션

    XA 세션은 HMS와 다른 RM과의 2PC를 수행하기 위해 존재한다. 트랜잭션으로 묶을 구간의 시작과 끝에 Tmax의 트랜잭션 관련 API(tx_beggin(), tx_commit(), tx_rollback())를 이용하여 명시한다.

    트랜잭션이 시작되지 않은 상태에서는 일반 세션처럼 동작한다.

  • 비동기(Async) 세션

    HMS는 메시지에 대한 요청 이후 메시지가 송신되는 동기적인 방법뿐만 아니라 메시지에 대한 요청 없이도 메시지를 수신할 수 있는 비동기 세션을 지원한다. 비동기 세션으로 소비자(Consumer)를 생성할 경우 메시지가 도착할 때 불릴 서비스명(Listener)을 넘겨주면, 메시지가 도착할 때마다 지정한 Tmax 서비스가 호출된다.

3.3. Destination

Destination은 지연처리를 위해 송신된 메시지가 소비자에게 수신될 때까지 머무르는 저장소이다. 각 Destination은 고유한 이름을 가지며, 종류로는 Topic과 Queue가 있다.

  • Topic

    Publish-and-Subscribe 메시징에서 사용되는 Destination이다. 1개의 메시지는 송신된 시점에 가입되어 있는 구독자(Subscriber)에게 모두 전달된다. 그 시점에 가입된 구독자가 존재하지 않을 경우에는 송신된 메시지는 버려진다.

  • Queue

    Point-to-Point 메시징에서 사용되는 Destination이다. 하나의 메시지는 하나의 수신자(Receiver)에게 전달된다. 송신자가 송신한 메시지는 수신자가 메시지를 꺼내갈 때까지 Destination에 존재한다.

Producer

생산자(Producer)는 Destination에 메시지를 송신하는 주체를 의미한다. 대상 Destination의 종류에 따라 Topic에 대한 생산자는 발행자(Publisher), Queue에 대한 생산자는 송신자(Sender)라고 한다.

생산자를 생성하기 위해서는 Tmax 시스템과 연결이 된 상태에서 생성한 세션, Destination의 이름, Destination의 종류가 필요하다. 그리고 필요에 따라 생산자의 이름을 설정할 수 있다. 생산자는 메시지를 송신할 때 해당 메시지 전달에 대한 속성을 부여할 수 있다.

속성 설명

Delivery Mode

메시지에 영속적(Persistent) 또는 비영속적(Non-Persistent) 속성을 부여해서 송신한다. 영속적 메시지는 Destination에 도착하는 동시에 스토리지에도 저장되어 장애가 발생할 경우 복구가 가능하다. 비영속적 메시지는 HMS의 메모리에서만 존재하며 HMS를 종료하거나 장애가 발생하면 소멸된다.

Priority

메시지가 Destination 안에 Queuing될 때 우선순위를 지정한다. 현재 HMS에서는 지원하지 않는다.

Time to Live

메시지가 Destination 안에서 유효한 시간을 지정한다. 지정한 시간이 지나면 메시지는 더 이상 소비자에게 전달될 수 없다. HMS는 Time to Live(이하 TTL)를 초 단위로 지원한다.

메지시가 송신에 성공하게 되면 각 메시지는 고유한 메시지 ID를 발급받는다. 메시지 ID는 프로퍼티로서 메시지에 존재하게 되며 사용자가 hms_get_property()를 이용하여 확인할 수 있다.

Consumer

소비자(Consumer)는 Destination으로부터 메시지를 수신하는 주체를 의미한다.

소비자를 생성하려면 세션, Destination의 이름, Destination의 종류, 생성하고자 하는 소비자의 이름이 필요하다. 또한 특정 프로퍼티를 갖는 메시지만 선택해서 수신할 경우에는 Message Selector를 설정할 수 있으며, 비동기적 메시지를 수신할 경우 수신될 때 호출될 서비스명을 설정한다. 소비자가 메시지를 수신할 때 타임아웃 값을 지정할 수 있다. 지정하지 않을 경우 메시지가 도착할 때까지 블록된다. 타임아웃 값의 단위는 초이다.

  • 구독자(Subscriber)

    대상 Destination의 종류에 따른 Topic에 대한 소비자를 구독자라고 한다.

    소비자 중에 영속적인 속성을 갖는 구독자를 영속적 구독자(Durable Subscriber)라고 한다. 영속적 구독자는 생성된 이후에 구독해제(unsubscribe)할 때까지 Destination으로 전달된 모든 메시지를 받을 수 있다. 영속적 구독자가 Tmax와의 연결에서 해제되어도 추후에 재접속하면 이전 메시지에 이어서 수신이 가능하다는 의미이다. HMS가 영속적 구독자를 구분하는 기준은 구독자의 이름이다. 따라서 영속적 구독자를 생성할 때에는 반드시 고유한 이름을 부여해야 한다.

  • 수신자(Receiver)

    Queue에 대한 소비자를 수신자라고 한다.

    수신자를 생성할 때에 Message Selector를 설정할 수 있다. Message Selector는 사용자가 일정한 조건을 설정하고 해당 조건을 충족하는 메시지만을 수신할 수 있도록 해준다. Message Selector 구문은 SQL 조건문과 동일하다.

    예를 들어 메시지에 Type과 Month라는 프로퍼티가 존재한다면, 다음과 같은 Message Selector를 설정한 소비자는 '4월 이후의 뉴스' 메시지만 수신한다.

    "(Type = 'News') AND (Month > 4)"

    Message Selector에 대한 자세한 내용은 Message Selector 사용법을 참고한다.

3.4. Message

HMS에서 사용되는 메시지(Message)는 Tmax의 필드 버퍼를 사용하기 때문에 필드 버퍼의 장점을 그대로 이용할 수 있다. 하나의 메시지 안에는 1개의 Body와 다수의 프로퍼티를 설정할 수 있다.

  • Body

    CARRAY 타입으로 설정한다.

  • 프로퍼티

    프로퍼티는 필드 버퍼에서 지원하는 HMS_CHAR, HMS_SHORT, HMS_INT, HMS_LONG, HMS_FLOAT, HMS_DOUBLE, HMS_STRING, HMS_CARRAY의 8가지 데이터 타입으로 설정한다. 프로퍼티는 이름과 함께 값을 설정하게 되며, 프로퍼티 이름은 메시지에서 유일해야 한다. 같은 이름으로 프로퍼티를 재설정할 경우 이전 값이 수정된다.

    메시지를 생성하려면 세션을 이용해야 하며, 각 프로퍼티는 데이터 부분뿐만 아니라 이름을 나타내는 공간도 필요하므로 많은 프로퍼티를 설정할 경우 메시지의 크기를 고려하여 넉넉하게 할당해야 한다.

    다음은 HMS에서 기본적으로 정의한 예약 프로퍼티이다. 사용자는 이와 같은 이름으로 프로퍼티를 재설정할 수 없다(이외의 다른 예약된 프로퍼티가 있으나 현재 지원하지 않는다).

    프로퍼티 설명

    HMSMessageID

    ($MessageID)

    메시지의 고유한 ID이다. HMS가 발급하므로 송신에 성공한 이후에 확인할 수 있다. 12자의 16진수의 문자열로 확인할 수 있다.

    HMSTimeStamp

    ($TimeStamp)

    생산자가 메시지를 송신하고 그 응답을 받을 때까지 걸린 시간(초)을 나타낸다.

    HMSDestination

    ($Destination)

    메시지가 송수신된 Destination의 이름을 나타낸다.

    HMSDeliveryMode

    ($DeliveryMode)

    메시지가 영속적(Persistent)인지 비영속적(Non-Persistent)인지 여부를 나타낸다.

    HMSExpiration

    ($Expiration)

    생산자가 메시지를 송신하면서 설정한 TTL 값을 의미한다.

3.5. Queue Browser

Queue Browser는 Queue의 메시지를 조회할 수 있는 일종의 소비자이다. Queue로부터 확인 용도의 메시지를 수신하지만 실제로는 메시지가 소비되지는 않는다. 기본적으로 가장 최신 메시지부터 오래된 순으로 열람하도록 동작하나, 가장 오래된 메시지부터의 열람 또한 가능하다. Queue Browser의 이름에서처럼 대상 Destination은 Queue만 허용한다.

3.6. Recovery

영속적 메시지(Persistent Message)와 영속적 구독자(Durable Subscriber)의 정보는 스토리지에 저장된다. HMS는 기동이 되자마자 스토리지에 남아있는 처리되지 않은 영속적 메시지와 영속적 구독자의 정보를 복구할 수 있다.

복구 여부는 부트 옵션으로 설정하며, Destination별로 각각 설정할 수 있다.

옵션 설명

WARM

기동될 때 복구한다.

COLD

기동될 때 스토리지의 정보를 삭제한다.

영속적 구독자가 복구 후 메시지를 이어서 수신하기 위해서는 이전에 생성되었던 이름으로 다시 생성해야 한다. 따라서 영속적 구독자를 생성할 때에는 고유한 이름을 부여하는 것이 중요하다. 또한 구독해제(unsubscribe)하지 않고 영속적 구독자를 제거한다면 해당 영속적 구독자에게 전달되지 않은 메시지와 그 이후에 도착하는 모든 메시지가 Destination에 쌓여 있게 되므로 주의해야 한다.

3.7. Clustering

Tmax 멀티노드 환경에서 다수의 HMS는 클러스터링(Clustering) 구성이 가능하다. 이를 이용해서 Failover와 부하분산 효과를 얻을 수 있다. 이름이 동일하고, GLOBAL 속성을 설정한 Destination은 논리적으로 하나의 Destination처럼 동작한다.

HMS의 클러스터링을 구성하기 위해서는 각 절에 다음의 설정을 해야 한다.

  • SVRGROUP 절

    HMSPORT를 반드시 설정해주어야 하며, Queue를 클러스터링하기 위해서는 추가적으로 GQINT를 설정해 주어야 한다.

  • HMS 절

    클러스터링할 Destination의 이름은 동일하게 설정하고, GLOBAL=Y로 설정해야 한다.

클러스터링된 HMS는 서로에 대한 장애감지를 위해 Heartbeat 메시지를 주고받는다. 사용자가 설정한 HMSHEARTBEAT 시간 내에 Heartbeat 메시지가 오지 않을 경우 장애 상황으로 판단한다.

HMS에서는 클러스터링이 설정된 Topic을 Global Topic, Queue를 Global Queue라고 한다.

  • Global Topic

    Global Topic으로 송신된 메시지는 나머지 다른 노드의 Global Topic으로 전달된다.

    예를 들어 노드 A, B, C에 Topic01이라는 같은 이름을 갖는 Topic에 모두 'GLOBAL=Y’로 설정을 했다면, 노드 A의 Topic01에 도착한 메시지는 노드 B, C의 Topic01에도 전달된다.

  • Global Queue

    설정된 모든 노드에 복사본이 전달되는 Global Topic과는 달리 Global Queue에서는 메시지는 1개만이 존재하고 소비될 수 있으므로 클러스터링에 있어서 다른 방법을 사용한다.

    각 HMS는 Global Queue에 대한 정보를 일정 시간(HMSGQINT)을 주기로 계속 주고받는다. 이 정보에는 현재 노드의 각 Queue에 존재하는 메시지의 개수, 연결된 클라이언트 수 등이 포함된다.

    교환 정보 설명

    Global Queue Information Interval

    (GQINT)

    HMS의 Global Queue에 대한 상태정보를 교환하는 주기이다.

    Global Queue Threshold

    (GQTHR)

    Global Queue의 버퍼의 크기를 구하는 데 사용되는 상수값이다.

    (버퍼크기 = 해당 Queue의 소비자 수 X GQTHR)

    Global Queue Max Request

    (GQMAXREQ)

    현재 Queue의 길이가 버퍼량을 채우지 못할 때 다른 노드로부터 한 번의 요청으로 가져올 수 있는 최대 메시지의 개수이다.

    Global Queue Full Length

    (GQFULL)

    Queue의 길이가 불균형이 되는 현상을 방지하기 위해 설정하는 Queue의 임계길이이다. 이 길이 이상이 되면 더 짧은 길이를 갖는 Queue로 메시지가 이동한다.

    각 Queue에는 원활한 메시지 전달을 위해 버퍼링을 하는데, 그 크기는 현재 Queue에 연결되어 있는 소비자의 수에 사용자가 설정한 상수값(GQTHR)을 곱해서 구한다.

    Queue의 메시지 수가 계산된 버퍼의 크기보다 작을 경우에는 다른 노드의 Queue로부터 메시지를 요청한다. 한 번의 요청으로 가져올 수 있는 메시지의 수(GQMAXREQ) 또한 설정할 수 있다. 이 값이 클 경우 적은 요청으로 필요한 메시지를 채울 수 있으나, 너무 클 경우에는 노드 간의 불필요한 메시지의 이동이 발생할 수 있다.

    버퍼의 크기 말고도 Queue의 길이가 불균형적으로 크게 차이나는 현상을 방지하기 위하여 메시지가 일정 수 이상(GQFULL)이 되면 메시지의 요청이 없어도 Queue의 길이를 균형적으로 맞춰주는 기능도 제공한다.