CS

[CS] RabbitMQ 멀티리스너 설정 시 패키지 통일

lnacles 2024. 4. 3. 23:45

RabbitMQ를 사용할 때 멀티리스너 설정 시 발생하는 에러를 해결한 경험과 의존성에 관한 글입니다.

 

RabbitMQ를 사용하기 위해서 큐에 메시지를 쓰는 애플리케이션과 메시지를 가져와 읽는 애플리케이션을 구현해야 합니다. 물론 하나의 애플리케이션에서 구현할 수 있지만 두 개로 구분할 수도 있습니다.

 

흔히 PUB/SUB 패턴 또는 단순히 Producer와 Consumer라고 표현하는데 앞서 설명했듯이 exchange에 바인딩된 queue에 여러 가지 타입으로 메시지를 추가할 수 있었습니다. 이 말은 Producer가 여러개 존재할 수 있는 구조입니다.

 

[CS] RabbitMQ 기본

RabbitMQ는 오픈소스 메시지 브로커 소프트웨어이고 Erlang으로 구현되어 있습니다. 기본 프로토콜을 AMQP(Advanced Message Queue Protocol)을 사용하고 있으며 플러그인으로 STOMP, MQTT 등의 프로토콜로 확장

devlog-jul95.tistory.com

 

그렇다면 Consumer는 꼭 하나만 존재해야 할까?

 

네! Consumer에서 멀티 리스너를 설정하여 큐를 동시에 여러 개 처리할 수 있습니다. 하지만 간단하게 구현할 수 있는 단일 리스너에 반해 멀티 리스너를 구현할 시 패키지 이름이 달라서 발생하는 에러가 있습니다.

 

단일 리스너

 

위와 같이 메시지를 추가할 때 메시지 속성값인 Headers에 __TypeId__라는 키 값에 메시지 객체의 패키지 정보가 담겨서 큐에 들어가게 되고 메시지를 읽을 때 Consumer 내에서 객체를 생성해서 맵핑해서 읽을 수 있습니다. 여기서 단일 리스너일 경우 패키지를 통일하지 않아도 됩니다. 하지만 멀티 리스너로 구현될 경우 Consumer에서 메시지를 읽을 때 Producer의 패키지 위치에 메시지 객체를 생성 해야합니다.

 

멀티 리스너

이렇게 멀티리스너로 구현된 경우 메시지를 꺼내는 쪽에서 메시지를 추가한 정보와 통일시켜 줘야 정상적으로 읽을 수 있습니다.

 

Producer는 exchange와 연동되어 있기 때문에 큐를 사용하는 서비스가 무수히 늘어나는 구조입니다. 그래서 큐의 사용이 한번 두 번은 개발자가 수고하여 패키지를 통일할 수 있지만 무수히 늘어나면 Consumer에서 패키지를 통일해 줄 수 없습니다.

 

그렇다면 Producer 입장에서 메시지를 추가할 때 exchange를 명시할 것이고 해당 exchange에 바인딩된 queue를 보면 어떤 애플리케이션에서 queue를 가리키는지 확인할 수 있습니다.

 

그래서 Producer에서 메시지를 추가할 때 이 메시지는 A라는 애플리케이션이 읽을 것이니까 A의 패키지를 정의해 주면 __TypeId__ 의존성을 줄일 수 있다고 생각했습니다.

마침 convertAndSend함수에서 4번째 인자로 MessagePostProcessor 객체를 받는데 여기서 MessagePostProcessor  객체를 재정의 하여 메시지의 속성값을 수정할 수 있었습니다.

 

private final RabbitTemplate rabbitTemplate;

public void sendMessage(MessageDto messageDto){
        rabbitTemplate.convertAndSend("sample.exchange", "sample.key.#", messageDto, new MessagePostProcessor() {
        @Override
        public Message postProcessMessage(Message message) throws AmqpException {
            MessageProperties props = message.getMessageProperties();
            props.setHeader("__TypeId__","org.example.receiver.dto.MessageDto");
            return message;
        }
    });
}

 

이로써 메시지가 어디서 왔는지 알아야 하는 의존성을 제거하게 되었습니다. 관련된 코드는 아래 Github에서 자세하게 확인할 수 있습니다. 

 

GitHub - DevJIYUL/RabbitMQ_MultiConsumer: Rabbitmq_Multiconsumer messagepostprocessor override

Rabbitmq_Multiconsumer messagepostprocessor override - DevJIYUL/RabbitMQ_MultiConsumer

github.com