본문 바로가기
Java , Spring/Spring

[Spring] RabbitMQ 연결해서 메세지 주고받기

by 방배킹 2024. 5. 21.

 

프로젝트를 진행하면서 선착순으로 쿠폰을 발급하는 기능을 개발하는데,

쿠폰을 발급하는 요청이 한번에 많이 들어모면 동시성 문제가 생길수있는데, 이를 메세지큐를 이용해 해결하기 위해 간단히 정리를 하고 간단한 실습을 해보았다.

 

Message Queue

Queue는 선입선출(First in First out) 구조를 가진 자료구조이다.

메세지 큐(Message Queue)는 Queue를 이용해서 메세지를 전달하는 시스템이며, 메세지 지향 미들웨어(MOM) 을 구현한 시스템이다.

메세지 브로커 VS 이벤트 브로커

메세지 큐에서 데이터를 운반하는 방식에 따라 메세지 브로커 와 이벤트 브로커로 나누어진다.

메세지 브로커(Message Broker)

  • 메세지 브로커는 Producer 가 생산한 메세지를 메세지 큐에 저장하고, 저장된 메세지를 Consumer가 가져갈 수 있도록 합니다.
  • 메세지 브로커는 Consumer 가 메세지 큐에서 데이터를 가져가게 되면 짧은 시간 내에 메세지 큐에서 삭제되는 특징이 있다.
  • ex) RabbitMQ, ActiveMQ, AWS SQS, Redis

이벤트 브로커(Event Broker)

  • 이벤트 브로커는 기본적으로 메세지 브로커의 역할을 할 수 있다. 하지만 반대로 메세지 브로커는 이벤트 브로커의 역할을 할 수 없다.
  • 이벤트 브로커가 관리하는 데이터를 이벤트라고 하며 Consumer 가 메세지 큐에서 데이터를 가져가게 되면 짧은 시간 내에 메세지가 삭제되는 것과 달리, 이벤트 브로커는 Consumer 가 소비한 데이터를 필요한 경우 다시 소비할 수 있다. (이벤트 브로커는 데이터를 삭제하지 않는다.)
  • ex) Kafka

메세지 큐의 장점

  1. 비동기(Asynchronous): Queue에 넣어두기 때문에 나중에 처리할 수 있다.
  2. 낮은 결합도(Decoupling): 애플리케이션과 분리할 수 있다.
  3. 탄력성(Resilience): 일부가 실패 시 전체에 영향을 받지 않는다.
  4. 과잉(Redundancy): 실패 할 경우 재실행이 가능하다.
  5. 신뢰성(Guarantees): 작업이 처리된 걸 확인할 수 있다.
  6. 확장성(Scalable): 다수의 프로세스들이 큐에 메시지를 보낼 수 있다.

RabbitMQ

RabbitMQ 는 AMQP 프로토콜을 구현해 놓은 오픈 소스 메시지 브로커이다.

AMQP란 메세지 지향 미들웨어(MOM) 을 위한 개방형 표준 응용 계층 프로토콜이다.

AMQP는 일반적인 메세지 큐와 비슷하지만 Exchange 라는 라우터가 존재하며 Binding 이라는 개념이 존재한다.

장점

  • AMQP 을 구현해 놓은 메세지 큐
  • 신뢰성,안전성과 성능을 충족할 수 있도록 다양한 기능을 제공
  • Broker 중심적인 형태
  • 유연하고 복잡한 라우팅이 가능
  • 관리 UI 존재
  • 거의 모든 언어와 운영체제를 지원
  • 20kb/sec 정도의 속도
  • 데이터 처리 보단, 관리적 측면이나 다양한 기능 구현을 위한 서비스를 구축할 때 사용

단점

  • 메세지 큐 서버가 종료 후 재가동시 큐 내용은 모두 삭제합니다. (데이터 손실 위험)
  • Producer 와 Consumer 의 결합도가 높다.

 

실습

메시지를 전달하는 sender와 메시지큐에서 메시지를 받아 출력하는 receiver를 만들어서 메시지를 주고 받아보자.

 

https://www.rabbitmq.com/tutorials/tutorial-one-java

 

RabbitMQ tutorial - "Hello World!" | RabbitMQ

<!--

www.rabbitmq.com

 

spring:
  rabbitmq:
    host: 
    port: 
    username: root
    password: 1234
@Configuration
@AllArgsConstructor
public class SenderModule {

    final RabbitTemplate rabbitTemplate;

    @Scheduled(fixedRate = 1000)
    public void sender(){
        LocalDateTime nowDateTime = LocalDateTime.now();
        String time = nowDateTime.toString();
        System.out.println("send message => " + time);
        rabbitTemplate.convertAndSend("time","my-key",time);
    }
}
@Component
public class ReceiverModule {

    @RabbitListener(bindings = @QueueBinding(
            exchange = @Exchange(name="time",type= ExchangeTypes.TOPIC),
            value=@Queue(name="time-second"),
            key = "my-key")
    )
    public void receiver(String msg){
        System.out.println("receive message => " + msg);
    }

}

댓글