RabbitMQ란?
RabbitMQ는 메시지 전송 브로커 오픈소스입니다.
시스템 간 비동기 메시징을 가능하게 하여 서비스 간 통신을 안정적이고 효율적으로 처리할 수 있습니다.
MSA환경에서 가장 일반적으로 쓰이며 대량의 데이터 전송 시 발생할 수 있는 과부하를 분산시키고, 비동기 처리와 지연이 필요한 작업을 효과적으로 관리할 수 있습니다.
RabbitMQ의 설치방법은 구글링을 통해 OS에 맞는 방식으로 설치하면 됩니다.
메시지큐를 사용하는 이유
1. 비동기 메시지를 사용해 다른 Application 사이에 데이터를 송수신 할 수 있습니다.
2. 클라이언트에 대한 동기 처리는 병목의 요인이 되므로 비동기로 처리 해도 될 영역에 대해서는 큐를 통해 분리해서 처리한다.
3. 분산환경에서 Application을 분리하고 독립적으로 확장하기 위해서 사용, 기능 별로 모듈 구성이 용이합니다.
4. 요청에 대한 응답을 기다릴 필요가 없기 때문에 각 영여의 역할만 신경쓰면 됩니다. Application 레벨에서 분리할 수 있습니다.
5. 데이터를 메모리 대신에 디스크에 저장하여 데이터 유실을 방지합니다.
- 즉시 처리하지 않아도 나중에 다시 처리가 가능하다.
- 메시지 영구 저장, 메시지 확인, 장애 복구 메커니즘을 통해 메시지의 신뢰성을 보장합니다.
6. 확장성 : 여러 노드에 걸쳐 쉽게 확장할 수 있어 높은 가용성을 제공하며 ,필요에 따라 메시지를 클러스터링 하거나 페더레이션 방식으로 확장할 수 있댜ㅏ.
7. 유연성 : 다양한 exchange 유형과 라우팅 규칙을 지원하며 메시지를 효과적으로 라우팅하고 관리할 수 있습니다.
- 광범위한 프로토콜을 지원 : AMQP를 기본으로 사용, STOMP, MQTT, HTTP 등 다양한 프로토콜을 지원한다.
- JAVA, Python, .NET... 등 다양한 언어로 클라이언트 라이브러리를 제공하여 다양한 Application에서 사용할 수 있다.
AMQP
Advanced Message Queing Protocol, MQ의 오픈소스에 기반한 표준 프로토콜이다.
이것에 대한 구현체가 RabbitMQ라고 봐도 됨.
Producer 모듈과 Consumer 모듈이 있습니다.
Producer는 생산자 역할로, payload를 생성해서 exchange를 통해서 라우팅을 한다던가 해서 Queue에 데이터를 저장합니다.
Consumer는 메시지큐들을 순차적으로 빼오는 형태로 메시지가 들어온 순서대로 메시지를 처리합니다.
Queue는 그냥 메시지를 보관하는 버퍼역할. Producer나 Consumer와 같은 Client 사이에서 RabbitMQ의 메커니즘을 따라가며 큐에 데이터를 보관하고 있는것.
AMQP의 특징
과거에도 MQ 제품들이 많았지만, 대부분 플랫폼 종속적이었기 때문에 서로 다른 이기종간 메시지를 교환하기 위해 메시지 포멧 변환을 위한 메시지 브릿지를 이용하거나(속도 저하), 시스템 자체를 통일시켜야 하는 불편함과 비효율성이 있었다고 합니다. AMQP의 목적은 서로 다른 시스템간에 최대한 효율적인 방법으로 메시지를 교환하기 위한 MQ프로토콜이라고 생각하면 됩니다. 특징은 아래와 같습니다.
1. 모든 broker들은 똑같은 방식으로 동작할 것
2. 모든 client들은 똑같은 방식으로 동잘할 것
3. 네트워크상으로 전송되는 명령어의 표준화
4. 프로그래밍 언어 중립적
Routing Model Components
AMQP의 라우팅 모델은 3개의 component로 구성됩니다.
1. Exchange
- Publisher로부터 수신한 메시지를 적절한 큐 또는 다른 exchange로 분배하는 라우터의 기능을 한다.
2. Queue
- 메모리나 디스크에 메시지를 저장하고, 메시지를 Consumer에게 전달하는 역할을 한다.
3. Binding
- exchange와 큐와의 관계를 정의한 일종의 라우팅 테이블. 같은 큐가 여러개의 exchange에 bind 될 수 도 있고, 하나의 exchange에 여러 개의 큐가 bind 될 수도 있다.
- Routing key : 라우팅 키는 발행된 메시지와 큐가 라우팅 테이블을 통해 매칭되는 키입니다. Publisher/Producer로 칭하는 송신부에서 송신한 메시지 헤더에 포함되는 것으로 가상의 주소라고 보면 됩니다.
용어 정리
1. Producer (생산자):
- 메시지를 생성하고 RabbitMQ에 전송하는 Application
- Producer는 특정 Exchange에 메시지를 전송하고 Exchange는 메시지를 라우팅하 여 큐에 배치
2. Exchange :
- Producer로 부터 받은 메시지를 큐에 전달
- Exchange 유형:
-- Direct: 특정 라우팅 키와 정확히 일치하는 큐에 메시지를 전송
-- Fanout: 모든 큐에 메시지를 브로드캐스트
-- Topic: 라우팅 키 패턴을 기반으로 메시지를 특정 큐에 전달
-- Headers: 메시지 헤더 속성에 따라 메시지를 라우팅 메시지가 Exchange로 전송될 때, Routing Key가 함께 전달
3. Routing Key :
- 메시지를 전송할 때 Producer가 Exchange에 전달하는 키
- Exchange는 이 Routing Key를 참고하여 어떤 큐에 메시지를 전달할지 결정
4. Queue :
- 메시지를 일시적으로 저장하는 버퍼 역할. RabbitMQ의 큐는 FIFO (First In, First Out) 방식으로 동작하며, 메시지가 소비자에 게 전달될 때까지 보관
- 각 큐는 여러 Consumer가 구독(수신)할 수 있으며, 메시지는 큐에 들어온 순서대로 전달
- 비동기적으로 동작하며, 여러 컨슈머가 동시에 메시지를 소비할 수 있다. 단 하나의 메 시지가 여러 소비자에게 중복으로 전달될수는 없음 동일한 메시지를 수신하려면 Fanout Exchange 방식으로 동작해야만 함.
5. Binding :
- exchange와 큐간의 관계를 정의
- 바인딩은 메시지를 라우팅할 때 어떤 조건으로 큐에 보낼지 정의하고 이를 위해 binding key가 사용됨
- Binding Key와 Routing Key가 일치하면 해당 큐로 메시지가 전달 (패턴 매칭 가능)
6. Consumer (소비자):
- 큐에서 메시지를 가져와 처리하는 애플리케이션
- RabbitMQ는 여러 소비자에게 메시지를 로드 밸런싱 할 수 있다.
- Consumer는 큐에서 메시지를 받아 처리하면 메시지에 대한 확인(ACK, acknowledgment)을 브로커에 전송함
- 확인을 보내지 않으면, 브로커는 메시지를 재전송하거나 설정한 다른 Consumer에게 전달할 수 있다.
7. Message Acknowledgment (메시지 확인):
- 메시지가 성공적으로 처리되었음을 RabbitMQ에 알리는 과정 만약 소비자가 메시지를 성공적으로 처리하지 못했다면, 메시지를 다시 큐에 넣어 다른 소비자가 처리하도록 할 수 있다
8. Prefetch Count :
- 소비자가 받을 수 있는 최대 메시지 수를 설정
- 한 번에 많은 양의 메시지를 처리하지 않도록 하여 소비자의 성능 최적화
9. Virtual Host:
- RabbitMQ 서버 내의 논리적인 구획으로, 메시지 큐, 익스체인지, 사용자 권한 등을 구 분
- 하나의 RabbitMQ 서버 내에 여러 개의 가상 호스트를 설정하여 서로 다른 애플리케이 션의 메시지를 격리 할 수 있다.
10. Dead Letter Queue:
- 메시지가 처리되지 못하거나 유효 기간이 지난 경우 별도의 큐로 이동하는 구조도 설정할 수 있다.
동작 과정
1. Producer가 메시지와 Routing Key를 Exchange에 전송.
2. Exchange가 Routing Key를 사용해 Binding Key가 일치하는 큐에 메시지를 라우팅
3. Consumer가 큐에서 메시지를 가져와 처리하고, 성공적으로 처리됐음을 Acknowledgment로 RabbitMQ에 알림
Routing Key는 Producer에서 Exchange로 갈 때,
Binding Key는 Exchange에서 Queue로 갈 때 이용.
Exchange 유형
1. Direct Exchange
- Direct Exchange는 메시지가 라우팅 키에 따라 특정 큐로 하나씩 전달되는 방식.
- 메시지를 발행할 때 사용하는 라우팅 키와 동일한 키로 Exchange에 바인딩 된 모든 큐에 메시지를 전달한다.
- 해당 라우팅 키와 일치하는 큐에만 메시지가 전달되는 방식이기 때문에 Dicrect Exchange라고 함.
- 하나의 라우팅 키에 대해 여러 큐가 바인딩 될 수 있기 때문에 1:N 매칭이 가능함
- 활용 예시:
1. 메시지가 명확하게 특정 큐로 전달되어야 할 때.
2. 큐마다 고유한 라우팅 규칙을 적용하여 메시지를 분류해야 할 때.
ex) 주문 상태 처리, 결제 처리, 사용자 알림 시스템...
2. Topic Exchange
- Topic Exchange는 라우팅 키를 패턴 기반 으로 정의하여 메시지를 여러 큐에 유연하게 전달할 수 있는 방식이다.
- 라우팅 키에 와일드카드(*, #) 매칭을 사용해 더 복잡한 라우팅이 가능
- * 은 하나의 단어를 대체. log.info, log,warn, log.error 와 같은 패턴의 메시지를 수신할 때 log.*로 모두 수신 가능
- # 은 0개 이상의 단어를 대체하므로 app.login.success, app.oreder.success, ... 와 같은 라우팅 키를 #.success로 수신 가능
- 동적이고 유연한 라우팅이 필요할 때 사용(로그 수집, 이벤트 기반 모니터링)
3. Fanout Exchange
- 브로드캐스트 방식으로 메시지를 모든 바인딩된 큐에 전달한다.
- 한 번의 메시지 발행으로 모든 큐가 동일한 메시지를 받는다.
- 이벤트가 발생하면 모든 서비스가 동일한 메시지를 받는 서비스에서 유용.
4. Headers Exchange
- 메시지의 속성에 기반한 복잡한 라우팅이 필요할 때.
- 다국어 서비스, 고객의 등급별 혜택 알림
- 메시지 헤더에 language:"ko", language:"en" 등의 값을 설정해 헤더 기반 라우팅을 수행
메시지 전송 단계별 프로세스
1. 메시지 송신 (Producer -> Broker)
- Producer가 RabbitMQ Broker로 메시지를 송신, 이 때 메시지는 큐에 저장되고, 익스체인지와 바인딩 설정에 따라 적절한 큐로 라우팅
2. 메시지 전달 (Broker -> Consumer)
- Broker는 큐에 있는 메시지를 Consumer에 전달
- Consumer는 큐에서 메시지를 가져가거나(Polling) 메시지를 푸시(Push) 받는 방식으로 수신
3. 메시지 확인(ACK) 또는 거절(NACK)
- ACK : Consumer가 메시지를 성공적으로 처리한 후 Broker에게 ACK를 전송.
- 이 경우 Broker는 해당 메시지를 큐에서 제거하고 Producer에게 Message Acknowleged응답을 전송
- NACK : Consumer가 메시지 처리에 실패하거나 메시지를 거절할 경우 NACKNegative Acknowledgment)을 전송.
- NACK에는 메시지를 다시 큐로 보내야 할지(requeue) 또는 폐기해야 할지(discard) 설 정 가능
- requeue(재전송 요청) : 메시지를 다시 큐로 보내고 재처리할 수 있도록 설정
- discard(폐기) : 메시지를 큐에서 제거하고 폐기 처리
- Consumer가 메시지를 NACK하면 Broker는 Producer에게 Message Rejected 응답 전송
4. Producer에 응답 (Message Acknowledged / Message Rejected)
- Producer가 Publisher Confirms를 활성화한 경우, Broker는 ACK 또는 NACK 결과를 Producer에게 전송
- ACK를 받은 경우 메시지가 성공적으로 소비된 것으로 간주되며, NACK를 받은 경우 Producer는 메시지 실패를 기록하거나 재전송
'개발지식 정리' 카테고리의 다른 글
페이징 쿼리 최적화: Covering Index 활용하기 (2) | 2025.01.30 |
---|---|
비동기 아키텍처 이해 3 - Work Queues (0) | 2025.01.28 |
비동기 아키텍처 이해 2 - 메시지 전송 예제 (0) | 2025.01.24 |