본문 바로가기
1. 개발/1.8. ActiveMQ

JMS와 AMQP 프로토콜 간의 타입 매핑 방식은?

by 엉짱 2026. 3. 13.
반응형

JMS와 AMQP 프로토콜 간의 타입 매핑 방식은?

엔터프라이즈 환경에서 메시징 인프라를 구축할 때, Java 생태계의 표준 API인 JMS(Java Message Service)와 이기종 시스템 간의 상호 운용성을 보장하는 와이어 프로토콜인 AMQP(Advanced Message Queuing Protocol, 주로 1.0)를 함께 사용하는 경우가 많습니다.

ActiveMQ나 Amazon MQ와 같은 멀티 프로토콜 지원 브로커 환경에서 JMS 클라이언트와 비 Java(AMQP) 클라이언트가 원활하게 메시지를 주고받으려면, 두 시스템 간의 데이터 타입과 메시지 구조가 어떻게 변환(Mapping)되는지 정확히 이해해야 합니다.

 


1. 매핑의 핵심 원리: API vs Wire Protocol

JMS는 Java 언어에 종속된 5가지 특정 메시지 타입(Text, Bytes, Map, Object, Stream)을 정의하는 API 스펙입니다. 반면, AMQP 1.0은 네트워크 상에서 데이터가 어떻게 표현되어야 하는지를 정의하는 이진(Binary) 프로토콜로, 메시지 바디(Body)를 표현하기 위해 AmqpValue, Data, AmqpSequence라는 세 가지 데이터 섹션을 사용합니다.

따라서 클라이언트(예: Apache Qpid JMS)나 메시지 브로커는 메시지를 송수신할 때 이 두 규격 사이의 임피던스 불일치(Impedance Mismatch)를 해결하기 위한 자동 변환 작업을 수행합니다.


2. JMS 메시지에서 AMQP 타입으로의 변환 (Outbound)

JMS 클라이언트가 AMQP 네트워크를 통해 메시지를 전송할 때, JMS 메시지 타입은 AMQP 데이터 섹션으로 다음과 같이 인코딩됩니다.

JMS 메시지 타입 AMQP 바디 (Body) 섹션 AMQP 타입 상세 (Type Definition)
TextMessage AmqpValue String 타입으로 인코딩되며, UTF-8 문자열을 포함합니다.
BytesMessage Data Binary 타입으로 인코딩됩니다. 순수한 바이트 배열이 그대로 전송됩니다.
MapMessage AmqpValue Map 타입으로 인코딩됩니다. Key는 보통 String이며, Value는 지원되는 원시 타입입니다.
StreamMessage AmqpSequence List 타입으로 인코딩됩니다. 순서가 있는 원시 데이터의 나열을 표현합니다.
ObjectMessage Data (또는 AmqpValue) 기본적으로 Java 직렬화(Serialization)된 바이트 배열이 Data 섹션에 담깁니다.

ObjectMessage 사용 시 주의점:
ObjectMessage는 Java 고유의 직렬화 메커니즘을 사용하므로 AMQP를 사용하는 타 언어(Python, C++ 등) 클라이언트에서는 역직렬화할 수 없습니다. 이기종 통신이 목적이라면 ObjectMessage 대신 객체를 JSON 문자열로 직렬화하여 TextMessage로 전송하는 것이 권장됩니다.


3. AMQP 타입에서 JMS 메시지로의 변환 (Inbound)

AMQP 클라이언트가 보낸 메시지를 JMS 클라이언트가 수신할 때, 들어온 AMQP 바디 섹션을 보고 어떤 JMS 메시지 객체로 인스턴스화할지 결정해야 합니다.

AMQP 표준에서는 이를 명확히 하기 위해 메시지 어노테이션(Message Annotations)을 활용합니다. 대표적으로 x-opt-jms-msg-type 어노테이션이 사용되며, 이 값이 존재하면 브로커나 수신 클라이언트는 해당 타입으로 즉시 매핑합니다. (값: 0=Message, 1=Object, 2=Map, 3=Bytes, 4=Stream, 5=Text)

만약 어노테이션이 없다면 AMQP 바디의 형태를 추론하여 매핑합니다.

  • 바디가 AmqpValue인 경우:
  • 내부 값이 String이면 $\rightarrow$ TextMessage
  • 내부 값이 Map이면 $\rightarrow$ MapMessage
  • 내부 값이 없거나(Null) 기타 원시 타입이면 $\rightarrow$ ObjectMessage (단일 기본형 객체 래핑)
  • 바디가 Data인 경우:
  • 형식에 상관없이 기본적으로 $\rightarrow$ BytesMessage
  • 바디가 AmqpSequence인 경우:
  • $\rightarrow$ StreamMessage

4. 프로퍼티 (Properties) 및 헤더 매핑 규칙

메시지 본문 외에도 메타데이터 역할을 하는 헤더와 프로퍼티 역시 1:1 매핑 규칙을 따릅니다.

A. JMS 헤더 $\leftrightarrow$ AMQP 시스템 프로퍼티

  • JMSMessageID $\leftrightarrow$ AMQP message-id
  • JMSCorrelationID $\leftrightarrow$ AMQP correlation-id
  • JMSReplyTo $\leftrightarrow$ AMQP reply-to
  • JMSType $\leftrightarrow$ AMQP subject
  • JMSDeliveryMode $\leftrightarrow$ AMQP headerdurable 속성 (Persistent=true, Non-Persistent=false)

B. JMS 사용자 정의 프로퍼티 $\leftrightarrow$ AMQP Application Properties
JMS에서 setStringProperty(), setIntProperty() 등으로 추가한 사용자 정의 메타데이터는 AMQP의 Application Properties 맵에 동일한 Key-Value 형태로 저장됩니다.
이때 지원되는 데이터 타입은 제한적이며, Java의 원시 타입 래퍼(Boolean, Byte, Short, Integer, Long, Float, Double, String)만 안전하게 매핑됩니다. AMQP에는 존재하는 Unsigned 타입(예: Unsigned Integer)이 AMQP $\rightarrow$ JMS 방향으로 들어올 때는 데이터 손실을 막기 위해 한 단계 더 큰 Java 타입(예: Long)으로 승격(Promotion)되어 매핑됩니다.


5. Amazon MQ / ActiveMQ 환경에서의 아키텍처 가이드

다중 프로토콜을 지원하는 브로커(Amazon MQ 등)에서 이 타입 매핑은 브로커 내부에서 투명하게 이루어집니다.

  1. 페이로드 변환 오버헤드 최소화: 브로커가 AMQP $\leftrightarrow$ OpenWire(JMS 기본 프로토콜) 간에 메시지를 변환할 때 약간의 직렬화/역직렬화 오버헤드가 발생합니다. 성능이 극도로 중요한 시스템에서는 프로토콜을 통일하는 것이 유리할 수 있습니다.
  2. 공통 포맷 표준화: 시스템 전반에 걸쳐 이기종 통신이 필수적이라면, 브로커에 의존한 복잡한 MapMessage나 StreamMessage 매핑보다는 모든 시스템이 TextMessage 바디에 JSON 포맷을 담아 통신하도록 표준화하는 것이 가장 유지보수하기 좋고 오류가 적은 방법입니다.
반응형