AMQP 개념 및 Spring-RabbitMQ 적용

BlackHan·2023년 11월 16일
0
post-thumbnail

AMQP(Advanced Message Queuing Protocol)란 ?
메시지 지향 미들웨어(MOM) 시스템 간에 통신하기 위한 개방형 네트워크 프로토콜이다.

간단히 말해서, 송신자(Producer)와 수신자(Consumer) 사이에서 메시지를 안전하게 교환하는 표준 프로토콜이다.

AMQP는 Queue, Exchange, Binding이라는 개념으로 구성된다.

  • Queue
    메시지를 수신하고 처리를 대기하는 대기열이며, 큐는 메시지를 안전하게 저장하고 필요에 따라 소비자에게 전달한다.
  • exchange
    Producer가 메시지를 큐로 보내기 위한 진입점이며, 여기서 바인딩 규칙에 따라 어떤 큐에게 메시지를 전달할지 결정한다.
  • binding
    익스체인지와 큐 간의 연결을 나타내며, 메시지가 어떤 큐로 라우팅 되어야 하는지를 결정

왜 사용하는가 ❓

개발을 하다보면 여러 서버를 구성하고, 서로 상호 작용하는 방식으로 구성하게 된다. 이런 상황에서 서버들은 서로 정보를 주고받아야 하는 상황이 발생한다.
그러나 HTTP 통신은 요청을 보내면 응답을 받을 때까지 요청을 보낸 서버의 수행이 중단된다. 이렇게 되면 여러 서버에 동시에 정보를 전달하기 어려워진다. 이런 상황에서 AMQP를 이용하게 되면 Message Broker 라는 미들웨어를 활용해서 비동기식으로 메시지를 전달할 수 있게 된다.

장점

  1. 시스템 간 통신을 향상시키고, 확장성 있는 아키텍처를 구축하는 데 유용하다.
  2. 서버가 메시지를 정상적으로 받았는지를 확인할 필요가 없어 결합성 감소한다.
  3. 비동기 통신을 기반으로 한 다양한 기능을 구현하는 데 도움이 된다

RabbitMQ란

AMQP를 구현한 오픈소스 메시지 브로커이다.

나는 여기서 RabbitMQ를 써보기로 한다. RabbitMQ는 다운받아서 로컬에서도 작동시킬 수 있지만 CloudAMQP라는 사이트에서 회원가입만 진행하고, 웹상에서 활용할 수도 있다. 나는 후자의 방법을 이용했고 SpringBoot를 사용했다. 먼저 새로운 인스턴스를 생성해 준다.

1. 의존성을 추가한다.

dependencies {
		implementation 'org.springframework.boot:spring-boot-starter-amqp'
		implementation 'com.google.code.gson:gson:2.9.0'
		testImplementation 'org.springframework.amqp:spring-rabbit-test'
	}

2. yaml 파일도 수정해 준다.

spring:
  rabbitmq:
    username: <RabbitMQ 계정>
    password: <RabbitMQ 비밀번호>
    host: <RabbitMQ 서버>
    virtual-host: <virtual host>

로컬의 경우에는 RabbitMQ의 초기 설정은 ID(user): admin, Password: <호스트 이름>이다. CloudAMQP는 name을 클릭하면 알 수 있다. host에는 dingo.rmq.cloudamqp.com 를 넣어주었다.
그럼 아래와 같은 데이터를 볼 수 있다.

  1. Producer와 Consumer를 생성해야 한다. Producer에는 작업의 Entity를 생성하고, Repository를 만든다. Repository는 JpaRepository를 상속받아 만들었다.

  2. 작업 생성 DTO, 처리하는 서버에 데이터를 전달하는 DTO, 조회를 위해서 정보를 반환하는 DTO, 작업의 상태를 확인하는 DTO를 만들었다.

  3. Queue를 정의하는 Config를 만든다.

@Configuration
public class PdConfig {
    @Bean
    public Queue queue(){
        return new Queue("test-queue", true, false, true);
    }
}

여기서 Queue는 name, durable, exclusive, autoDelete의 값을 설정할 수 있다.
name은 Queue를 구분 짓고, 작업 처리 시 이름을 활용하여 Queue를 찾는 데 이용된다.
durable은 서버 종료 이후에도 Queue를 유지할지를 설정한다.
exclusive는 해당 서버에만 사용하는지 설정한다.
autoDelete는 사용되지 않는 상황에서도 Queue 유지하는지의 설정이다.

  1. Service에서 RabbitMQ에 메시지를 보내기 위한 객체를 만든다.
    작업을 식별하는 Id를 만들고, 내용을 기록한다. 그리고 Json을 이용하여 객체를 직렬화하여 전송한다.
     rabbitTemplate.convertAndSend(
            Queue.getName(), gson.toJson(payload));

해당 요청을 Post하게 되면 Queue에 작업이 쌓이는 것을 확인할 수 있다.
다음으로 Consumer를 설정하여, Queue에 있는 작업을 처리해 본다.

  1. 나머지는 모두 동일하며, 해당 작업을 처리하기 위해서는 Consumer의 Config에서 Producer의 Config의 name과 동일하게 만들어야 한다.

  2. Consumer의 Service에 작업을 처리해 주는 메소드를 만든다.
    여기서 RabbitHandler라는 어노테이션을 이용하게 되는데, 이 어노테이션은 이 클래스가 Consumer의 Config에서 정의한 Queue에 적재되는 메세지를 처리하는 클래스임을 나타낸다.

    결과는 위와 같고, Queue에서 해당 작업을 꺼내 처리하게 된다.

회고

RabbitMQ를 통해 간단한 작업을 해 보았는데, 나름 신선했고 RabbitMQ를 활용하여 비동기적으로 처리하면서 어떻게 코드의 유연성과 확장성을 향상시킬 수 있는지에 대한 통찰을 했다.
큐를 통해 데이터의 흐름을 조절하고, 시스템 간 통신을 효율적으로 관리하는 방법에 대한 이해가 조금 생긴 것 같다만, 이정도로 사용할 줄 안다고는 할 수는 없을 것 같다. 한번은 팀원이 RabbitMQ를 사용하여 결제 시스템을 고도화시킨 적이 있었다. 다음에는 결제서비스를 이해해보기로 한다.

profile
Slow-starter

0개의 댓글