[서버] 메세지 큐(Message Queue) 을 알아보자

최동근·2023년 8월 12일
6

메세지 큐

목록 보기
4/4

백엔드 개발자로써 개발을 하다보면 메세지 큐(Message Queue) 을 많이 접하게 됩니다.
특히 MSA 아키텍처로 많은 개발이 이루어지고 있는 현재 핵심 역할을 하는 메세지 큐 에 대해서 선제적인 이해가 꼭 필요할 것 같아 이번 포스팅을 시작합니다 ❗️

📬 메세지 지향 미들웨어(MOM)

메세지 큐 를 본격적으로 알아보기 전에 메세지 지향 미들웨어(MOM) 에 대해 알아보겠습니다.

메세지 지향 미들웨어란 응용 소프트웨어 간의 비동기적 데이터 통신을 위한 소프트웨어입니다.

즉, 비동기적(Asynchronous) 한 방식을 이용해서 프로세스간의 데이터를 주고 받는 기능을 위한 시스템입니다.
메세지 지향 미들웨어는 메세지를 전달하는 과정에서 보관하거나 라우팅 및 변환할 수 있다는 장점을 가집니다.

메세지의 백업 기능을 유지함으로 써 지속성을 제공하며 이 덕분에 송수신 측은 동시에 네트워크 연결을 유지할 필요가 없습니다.(보관)
또한, 미들웨어 계층 자신이 직접 메세지 라우팅을 수행하기 때문에, 하나의 메세지를 여러 수신자에게 배포가 가능합니다.(라우팅)
이뿐만 아니라, 송수신 측의 요구에 따라 전달하는 메세지를 변환할 수 있습니다.(변환)

이번 포스팅에서 핵심적으로 알아볼 메세지 큐 는 메세지 지향 미들웨어에 속합니다 👨‍💻

📬 메세지 큐란?

Queue 란 선입선출(First in First out) 구조를 가진 자료구조입니다.
Queue 는 2개의 끝을 가지며 각각은 입구와 출구입니다. 새로운 데이터는 입구로 들어오고 나가는 데이터는 출구에서 나갑니다.

메세지 큐(Message Queue)Queue 라는 자료구조를 채택해서 메세지를 전달하는 시스템이며, 메세지 지향 미들웨어(MOM) 을 구현한 시스템입니다.

메세지 큐를 통해 메세지를 전달하려면 메세지를 전달하는 부분과 메세지를 받는 부분이 필요하겠죠?
여기서 메세지를 발행하고 전달하는 부분을 Producer 라고 하며, 메세지를 받아서 소비하는 부분을 Consumer 라고 합니다.
메세지 큐는 ProducerConsumer 의 메세지 전달 역할을 하는 매개체입니다.

메세지 큐는 요즘 가장 핫한 소프트웨어 아키텍처 디자인 패턴인 MSA(Microservice Architecture) 에서 아키텍처의 핵심적인 역할을 합니다 ❗️

[메세지 브로커 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): 다수의 프로세스들이 큐에 메시지를 보낼 수 있다.

1. 비동기 (Asynchronous)

메세지큐가 없다고 가정해보겠습니다.
메세지를 발행하는 Producer 역할을 하는 애플리케이션은 자신의 메세지를 전달 받는 Consumer 역할을 하는 애플리케이션에게 직접적으로 메세지를 보내야합니다.
End-To-End 통신을 통해 메세지 전달이 이루어집니다. 이 때문에 해당 과정이 완료되기 전까지는 다른 메세지 전달 과정을 이루어지지 못합니다.

이러한 방식을 동기(Synchronous) 라고 하며 전송속도가 빠르고 전송 결과를 신속하게 알 수 있는 장점이 있는 반면에, 대용량 트래픽이 발생하는 서버에서 이러한 방식은 매우 비효율적입니다🚫

이를 해결하기 위해 메세지큐를 중간에 배치한다면 Producer 는 메세지를 Consumer 에게 바로 보내지 않고 Queue 에 메세지를 넣어 관리합니다. 이를 통해 Consumer 는 비동기적으로 메세지를 처리할 수 있습니다 ❗️

2. 낮은 결합도(Decoupling)

메세지큐를 통해 하나의 서비스를 구성하는 애플리케이션끼리의 결합도를 낮출 수 있습니다.
만약, 애플리케이션끼리의 결합도가 높으면 어떨까요?
물론 결합도가 높을 때 얻을 수 있는 장점도 있지만 확장성,유연성,효율적인 유지 보수,장애 전파 방지 등에 결합도가 낮을 때 얻을 수 있는 장점이 많습니다.
낮은 결합성은 특히 현재 가장 핫한 MSA 아키텍쳐의 핵심 특징입니다.

3. 탄력성(Resilience)

여기서 탄력성(Resilience) 란 시스템이 예기치 않은 상황 또는 장애에 대응하고 유연하게 대처할 수 있는 능력을 의미합니다.
이는 앞서 살펴보았던 낮은 결합도(Decoupling) 을 통해 실현될 수 있습니다.
이해를 위해 한가지 예시를 들어보겠습니다.

은행 송금 시스템에서 A,B 라는 2가지의 프로세스가 있다고 가정해보겠습니다.
A 프로세스는 회원이 요청한 송금을 처리하는 프로세스이며, B 프로세스는 회원이 보낸 송금을 받아 계좌에 반영하는 프로세스입니다.

ProcessTask
AB 프로세스에게 송금(메세지) 을 보낸다.
BA 프로세스에게서 받은 송금(메세지) 을 받아 사용자 계좌에 반영한다.

여기서 메세지 큐가 없다고 가정해보겠습니다.
이때, 어떠한 이유로 B 프로세스에 장애가 발생했을 때 해당 장애는 A 프로세스에게도 전파되어 장애가 복구되는 시간동안 A,B 두 프로세스 모두 정상적으로 동작하지 못한채 Blocking 됩니다.
러한 결과는 당연한 결과인데 B 프로세스가 더이상 A 프로세스에서 보내는 송금을 받아 처리할 수 없으니 A 프로세스도 덩달아 송금을 처리하는 작업을 하지 못하게 되는 것입니다 🥲

하지만 메세지 큐가 있다면 이러한 문제를 효율적으로 해결할 수 있습니다.
위와 같이 동일한 상황일 때 A 프로세스는 B 프로세스의 장애 여부와 상관 없이 자신이 보내는 송금(메세지) 을 메세지 큐에게 전달만 해주면 됩니다.
송금(메세지) 을 받은 메세지 큐는 B 프로세스의 장애가 해결될 때까지 큐 내부에 A 에서 받아오는 송금(메세지) 를 보관할 수 있습니다 ❗️
이로써, B 서비스의 일시적인 불능 상태가 A 서비스에 직접적인 영향을 주지 않고, 시스템의 기능을 유지할 수 있습니다 👍

정리하자면 메세지 큐의 이러한 특성 덕분에 Producer 프로세스는 Consumer 프로세스가 다운되어 있어도 메세지를 정상적으로 발행할 수 있고, Consumer 는 구독한 메세지를 발행하는 Producer 프로세스가 다운되어 있어도 정상적으로 수신할 수 있습니다❗️

4. 과잉(Redundancy)

여기서 과잉(Redundancy) 란 정상적인 메세지 송/수신이 실패하는 경우 재실행이 가능하다는 뜻입니다.
메세지 큐가 없다고 가정해보겠습니다 🤔

A 프로세스와 B 프로세스는 End-to-End 통신을 하는 데 만약 B 프로세스에서 장애가 발생해 A 프로세스에서 장애 기간동안 정상적으로 메세지를 송신할 수 없다면 A 프로세스를 사용하는 클라이언트는 장애 기간동안 큰 어려움을 겪을 수 있습니다.
또한 여기에는 애플리케이션 수준에서 큰 문제가 될 수 있는데 시스템 응답성 저하,데이터 불일치 ,메세지 유실 등 다양한 문제가 발생할 수 있습니다 😱

하지만 메세지 큐를 사용한다면 이러한 문제를 완화할 수 있습니다.
작업을 메세지로 메세지 큐에 넣어두면 일정 장애 기간동안 송신된 메세지는 큐에 남아있어 추후 장애 복구 시 정상적으로 재시도 및 복구가 가능합니다 👍

5. 신뢰성(Guarantees)

여기서 신뢰성(Guarantees) 이란 송신된 메세지의 안전하고 확실한 전달을 의미합니다.
앞에 살펴보았던 장점들과 비슷한 맥락인데, 결국 메세지 큐라는 시스템 덕분에 장애가 발생하더라도 송신되는 메세지를 안전하고 확실하게 Consumer 가 수신할 수 있습니다 👍

6. 확장성(Scalable)

여기서 확장성(Scalable) 은 수평확장을 의미합니다.
만약 기존 메시지 큐를 이용한 통신에서 부하가 증가하거나 클라이언트의 동시다발적인 요청이 증가할 때, 메세지 큐에 ProducerConsumer 을 추가함으로 비교적 간단하고 쉽게 확장을 할 수 있습니다.

📬 메세지 큐의 종류

1. RabbitMQ

RabiitMQ 을 본격적으로 알아보기 전에 AMQP(Advanced Message Queue Protocol) 을 알아보겠습니다 ❗️

[AMQP 에 대해서]

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

AMQP는 일반적인 메세지 큐와 비슷하지만 Exchange 라는 라우터가 존재하며 Binding 이라는 개념이 존재합니다❗️
AMQP 을 구성하는 것들을 정리해보겠습니다.

[RabbitMQ 구성요소]

  • Producer : 요청을 보내는 주체이며 보내고자 하는 메세지를 ExchangePublish 합니다.
  • Consumer : Producer 로 부터 메세지를 받아 처리하는 주체입니다.
  • Exchange : Producer 로 부터 전달받은 메세지를 어떤 메세지 큐로 전송할지 결정하는 장소입니다. 이러한 기능을 라우팅 기능이라고 할 수 있습니다.
  • Queue : Consumer 가 소비하기 전까지 메세지가 보관되는 장소입니다.
  • Binding : ExchangeQueue 와의 관계입니다. 즉, 특정 Exchange 가 특정 Queue 에 메세지를 보내도록 정의합니다.

[RabbitMQ 특징 및 장점]

RabbitMQAMQP 프로토콜을 구현해 놓은 오픈 소스 메시지 브로커이며 여러가지 특성을 가집니다❗️

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

[RabbitMQ 처리 구조]

  1. ProducerBroker 로 메세지를 보냅니다.
  2. BrokerExchange 에서 해당하는 Key 에 맞게 Queue 에 분배합니다.(Binding)
  3. 해당 Queue 를 구독하는 Consumer 가 메세지를 소비합니다.

[RabbitMQ 단점]

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

2. ActiveMQ

ActiveMQ 을 본격적으로 알아보기 전에 JMS(Java Message Service) 에 대해 알아보겠습니다❗️

JMS 는 메세지 큐 및 Publish - Subscribe 패턴과 같은 메세지 기반 통신을 추상화하고 표준화한 API입니다.
Java MOM 표준 API 이며 소프트웨어 응용 프로그램 구성 요소가 소비하는 요청, 보고서 또는 이벤트로 메시지를 작성, 전송, 수신 및 읽을 수있는 메시징 표준입니다. JMS는 다른 시스템의 프로그램이나 다른 프로그래밍 언어로 작성된 프로그램이 메시지를 통해 서로 조정할 수 있도록합니다.

쉽게 이해하자면 Java 에서 채택한 대표적인 MOM 시스템이라고 생각하면 좋을 것 같습니다.
일반적인 메세지 큐 구조와 비슷한 것을 볼 수 있습니다.

ActiveMQJMS 스펙을 좀 더 사용하기 편리하게 구현한 오픈소스 메시지 브로커입니다.
RabbitMQ 와 더불어 현재 대표적인 메세지 브로커로 사용되고 있습니다❗️

[ActiveMQ 구성 요소]

  • Message Broker : 목적지에 안전하게 메세지를 건네주는 중개자 역할
  • Destination : 목적지에 배달될 2가지 메시지 모델 QueueTopic
  • Queue : 메세지가 전달되는 통로입니다. (경함이 있음)
  • Topic : Queue 와 비슷한 역할 그러나, 여러 Consumer 에게 메세지를 건네줄 수 있습니다.(경합이 없음)

[ActiveMQ 처리 모델]

  • Queue 모델의 경우 메세지를 받는 Consumer 가 다수일 때 연결된 순서 로 메세지가 제공됩니다.
  • Topic 모델의 경우 메세지를 받는 Consumer 가 다수일 때 메세지는 모두에게 제공됩니다.

해당 이미지는 Queue 모델과 Topic 모델을 보여주는 이미지입니다 🎨
ActiveMQ 는 일반적인 메세지큐의 특징 및 장점을 가지고 있으며 AMQP 기반의 RabbitMQ 을 사용하는 프로세스와의 통신은 불가능합니다 🚫

3. Kafka

Kafka 에 대한 자세한 정리 글은 [서버] Kafka 에 대해서 을 참고해주세요 👨‍💻

카프카(Kafka)Linked-in 에서 개발한 파이프라인, 스트리밍 분석, 데이터 통합 및 미션 크리티컬 애플리케이션을 위해 설계된 고성능 분산 이벤트 스트리밍 플랫폼입니다.
Pub-Sub 모델의 메시지 큐 형태로 동작하며 분산환경에 특화되어 있으며, Fortune 100개 기업 중 80% 이상이 Kafka를 사용합니다.
국내에서도 많이 사용하는 추세입니다 👍

Kafka 는 앞서 살펴보았던 메세지 브로커인 RabbitMQ, ActiveMQ 와는 달리 이벤트 브로커입니다.
또한 다른 동작 원리를 가집니다.

대용량 실시간 로그처리에 특화되어 설계된 메시징 시스템으로 TPS가 매우 우수하고,

메시지를 메모리에 저장하는 기존 메시징 시스템과는 달리 파일에 저장을 하는데 그로 인해 카프카를 재시작해도 메시지 유실 우려가 감소됩니다.

기본 메시징 시스템(rabbitMQ, ActiveMQ)에서는 브로커(Broker)가 컨슈머(consumer)에게 메시지를 push해 주는 방식인데, 카프카는 컨슈머(Consumer)가 브로커(Broker)로부터 메시지를 직접 가져가는 PULL 방식으로 동작하기 때문에 컨슈머는 자신의 처리 능력만큼의 메시지만 가져와 최적의 성능을 낼 수 있습니다.
대용량처리에 특화 되었다는 것은 아마도 이러한 구조로 설계가 되어 가능하게 된게 아닌가 싶습니다.

여기서 한가지 의문이 듭니다🤔
일반적으로 파일보다 메모리가 성능이 우수한데 왜 카프카가 성능이 좋은 것일까요?
그 이유는 카프카의 파일 시스템을 활용한 고성능 디자인에 있습니다.
일반적으로 하드디스크는 메모리보다 수백배 느리지만 하드디스크의 순차적 읽기에 대한 성능은 메모리보다 크게 떨어지지 않는다고 합니다.

정리하자면 대용량 분산 시스템이 필요하면 Kafka 을 구축하면 되고 그 외에는 Queue 기능에서 신뢰성과 안전성을 좀 더 보장하는 ActiveMQ 혹은 RabbitMQ 을 사용하면 될 것 같습니다.

📬 마치며

MSA 가 트랜디한 아키텍처로 자리잡은 현재 메세지 큐는 MSA 와 가장많이 사용되는 시스템입니다.
따라서 대표적인 메세지큐에 대한 개념을 꼭 정리하고 실제로 서버에 구축해보는 경험이 필수적이라고 생각합니다.
다음 포스팅에서는 각각의 메세지 큐를 Spring 프레임워크에 구축해보는 시간을 가져보려고 합니다 🎁
긴 글 읽어주셔서 감사합니다👨‍💻


참고

Apache-Kafka-카프카란-무엇인가#2-rabbitmq-의-동작-방식--및-특징
[메시지 지향 미들웨어:MOM] ActiveMQ, rabbitMQ, Kafka
Java Message Service Transport
Springboot에서 ActiveMQ로 메세시 송수신하기
메시지 큐와 종류 그리고 비교

profile
비즈니스가치를추구하는개발자

1개의 댓글

comment-user-thumbnail
2023년 8월 12일

정보 감사합니다.

답글 달기