여러가지 Exchange 타입과 라우팅 방식
특정 서비스 하나에만 메시지를 전달해야 할 때와, 연결된 모든 서비스에 동시에 뿌려야 할 때 — 같은 Exchange로 처리할 수 있을까?
Exchange 타입과 라우팅 방식
왜 Exchange 타입이 여러 가지인가
RabbitMQ에서 메시지를 큐로 전달하는 방식은 비즈니스 요구사항에 따라 크게 달라집니다. 특정 서비스에만 정확히 전달해야 할 때도 있고, 모든 서비스에 동시에 브로드캐스트해야 할 때도 있으며, 패턴에 따라 선별적으로 전달해야 할 때도 있습니다.
이러한 다양한 라우팅 요구를 충족하기 위해 RabbitMQ는 네 가지 Exchange 타입을 제공합니다.
| Exchange 타입 | 핵심 키워드 | 라우팅 기준 | 비유 |
|---|---|---|---|
| Direct | 정확한 매칭 | 라우팅 키 일치 | 택배 배송 (주소 기반) |
| Fanout | 브로드캐스트 | 없음 (모든 큐) | 긴급 재난 문자 |
| Topic | 패턴 매칭 | 와일드카드 패턴 | 뉴스 카테고리 구독 |
| Headers | 속성 조합 | 메시지 헤더 값 | 복합 조건 검색 |
바인딩(Binding)이란
Exchange 타입을 살펴보기 전에, ** 바인딩(Binding)**의 개념을 먼저 이해해야 합니다.
RabbitMQ에서 생산자가 발행한 메시지는 바로 큐에 적재되지 않습니다. 생산자는 Exchange에 메시지를 발행하고, Exchange는 자신의 타입과 라우팅 규칙에 따라 적절한 큐로 메시지를 전달합니다. 이때 Exchange가 어떤 큐로 메시지를 라우팅해야 하는지 미리 연결해두는 작업이 바로 바인딩 입니다.
바인딩의 주요 특징은 다음과 같습니다.
- Exchange와 큐를 연결하여 라우팅 규칙을 정의합니다.
- 런타임에도 추가, 수정, 삭제가 가능 하여 시스템 확장이 유연합니다.
- Exchange 타입에 따라 바인딩 시 설정하는 규칙(라우팅 키, 헤더 조건 등)이 달라집니다.
Exchange 타입과 라우팅 방식을 명확히 정의한 후, 그에 맞는 바인딩 작업을 진행해야 합니다.
1. Direct Exchange
Direct Exchange는 라우팅 키가 정확히 일치하는 큐에만 메시지를 전달 합니다. 택배 기사가 주소(라우팅 키)를 보고 정확한 집(큐)으로 택배(메시지)를 배송하는 것과 같습니다.
동작 방식
- 생산자가 메시지를 발행할 때 Exchange 이름과 라우팅 키를 지정합니다.
- Exchange는 바인딩된 큐 중 라우팅 키가 일치하는 큐를 찾습니다.
- 일치하는 큐에 메시지를 전달합니다.
**참고 **: 동일한 라우팅 키로 여러 큐가 바인딩되어 있으면, 해당 라우팅 키와 일치하는 ** 모든 큐에 메시지가 복사되어 전달 **됩니다. — RabbitMQ AMQP 0-9-1 Model Explained
코드 예시
/**
* 메시지를 Direct Exchange로 발행합니다.
* 생산자는 큐 이름을 알 필요 없이, Exchange와 라우팅 키만 지정합니다.
*/
public void sendMessage(String exchangeName, String routingKey, String message) {
rabbitTemplate.convertAndSend(exchangeName, routingKey, message);
}
한계점
| 한계 | 설명 |
|---|---|
| 정적 바인딩 의존 | 브로드캐스트 대상 큐를 미리 생성하고 동일한 라우팅 키로 바인딩해야 함 |
| ** 라우팅 키 필수** | 메시지 발행 시 반드시 라우팅 키를 지정해야 하며, 키 없이 전달 불가 |
| ** 유연성 부족** | 큐를 동적으로 추가하거나 패턴 기반 분배가 어려움 |
이러한 한계를 해소하기 위해 RabbitMQ는 Fanout Exchange를 제공합니다.
2. Fanout Exchange
Fanout Exchange는 ** 라우팅 키와 상관없이 바인딩된 모든 큐에 메시지를 브로드캐스트 **합니다. 긴급 재난 문자처럼 모든 대상에게 동시에 동일한 메시지를 전달하는 방식입니다.
동작 방식
- 생산자가 메시지를 Fanout Exchange에 발행합니다 (라우팅 키는 무시됩니다).
- Exchange는 바인딩된 ** 모든 큐 **에 메시지를 복사하여 전달합니다.
코드 예시
/**
* 메시지를 Fanout Exchange로 발행합니다.
* 라우팅 키를 사용하지 않으므로 빈 문자열("")을 전달합니다.
*/
public void sendFanoutMessage(String exchangeName, String message) {
rabbitTemplate.convertAndSend(exchangeName, "", message);
}
라우팅 키 자리에
null, 빈 문자열(""), 또는 임의의 문자열을 넣어도 동작에 영향이 없습니다. 다만, 의도를 명확히 전달하기 위해 빈 문자열을 사용하는 것이 관례 입니다.
한계점
| 한계 | 설명 |
|---|---|
| 선택적 필터링 불가 | 모든 큐에 동일한 메시지가 전달되므로 큐별 선별 수신 불가 |
| ** 리소스 소모** | 바인딩된 큐가 많을수록 메시지 복사로 인한 메모리/디스크 사용량 증가 |
| ** 불필요한 소비** | 실제로 필요하지 않은 큐에서도 메시지를 수신하여 비효율 발생 |
Fanout Exchange는 "연결된 모든 큐"로 메시지를 보내야 하는 시나리오에 적합하지만, ** 특정 조건을 만족하는 큐에만 전달 **하려면 Topic Exchange가 필요합니다.
3. Topic Exchange
Topic Exchange는 ** 라우팅 키의 패턴(와일드카드)을 이용하여 조건에 맞는 큐에만 메시지를 전달 **합니다. 뉴스 카테고리를 구독하듯, 원하는 패턴의 메시지만 선별적으로 받을 수 있습니다.
와일드카드 패턴
| 와일드카드 | 의미 | 예시 바인딩 | 매칭되는 라우팅 키 |
|---|---|---|---|
* (별표) | 정확히 한 단어 와 일치 | order.* | order.created, order.cancelled |
# (샵) | 0개 이상의 단어 와 일치 | order.# | order.created, order.status.updated, order.a.b.c |
동작 방식
- 큐를 바인딩할 때 와일드카드 패턴을 등록합니다.
- 메시지 발행 시 실제 라우팅 키를 지정합니다.
- Exchange는 바인딩된 큐의 패턴과 라우팅 키를 비교하여 매칭되는 큐에만 전달합니다.
패턴 매칭 예시
| 바인딩 패턴 | 라우팅 키 | 매칭 여부 |
|---|---|---|
order.* | order.created | 매칭 |
order.* | order.status.updated | 불일치 (*는 한 단어만 매칭) |
order.# | order.status.updated | 매칭 (#는 여러 단어 매칭) |
*.created | order.created | 매칭 |
# | (모든 라우팅 키) | 매칭 (Fanout처럼 동작) |
패턴 설계 시 주의사항
- 패턴이 너무 좁으면 필요한 메시지를 놓치고, ** 너무 넓으면** 불필요한 메시지까지 수신합니다.
*와#의 차이를 정확히 이해하고 사용해야 합니다.- 라우팅 키 구조를 **일관성 있게 설계 **(예:
{도메인}.{이벤트}.{세부항목})해야 패턴 활용이 수월합니다.
4. Headers Exchange
Topic Exchange가 한 가지 조건(라우팅 키 패턴)으로 필터링한다면, Headers Exchange는 ** 메시지의 헤더 속성을 기준으로 여러 조건을 조합 **하여 라우팅합니다.
x-match 설정
헤더 조건이 여러 개일 때, "모든 조건을 만족해야 하는가" 또는 "하나만 만족하면 되는가"를 결정하는 옵션이 x-match입니다.
| x-match 값 | 동작 | 예시 |
|---|---|---|
all | ** 모든** 헤더 조건을 만족해야 전달 | type=order AND priority=high 모두 일치해야 함 |
any | ** 하나라도** 만족하면 전달 | type=order 만 일치해도 전달됨 |
x-match=all 예시
Binding: {"x-match": "all", "type": "order", "priority": "high"}
Message Header: type=order, priority=high → 전달됨
Message Header: type=order, priority=low → 전달 안 됨
x-match=any 예시
Binding: {"x-match": "any", "type": "order", "priority": "high"}
Message Header: type=order, priority=low → 전달됨 (type=order 일치)
Message Header: type=log, priority=low → 전달 안 됨
사용 시 고려사항
Headers Exchange는 복잡한 조건 조합이 가능하지만, ** 라우팅 성능이 Direct, Topic에 비해 느릴 수 있으며 설계가 복잡해집니다.** 우선 Direct, Topic Exchange를 검토하고, 이들로 구현할 수 없는 복합 조건 라우팅이 필요한 경우에만 Headers Exchange를 고려하는 것을 권장합니다.
Exchange 타입 선택 가이드
| 시나리오 | 권장 Exchange | 이유 |
|---|---|---|
| 특정 서비스로 1:1 전달 | Direct | 라우팅 키로 정확히 지정 가능 |
| 전체 서비스에 동일 메시지 전파 | Fanout | 별도 라우팅 없이 전체 브로드캐스트 |
| 카테고리/도메인별 선별 전달 | Topic | 와일드카드 패턴으로 유연한 필터링 |
| 여러 속성 조합 기반 라우팅 | Headers | 헤더 값 기반 복합 조건 처리 |
주의할 점
Topic 패턴 설계를 잘못하면 메시지가 사라진다
Topic Exchange에서 바인딩 패턴이 라우팅 키와 매칭되지 않으면 메시지는 어떤 큐에도 전달되지 않고 ** 조용히 사라집니다 **. mandatory 플래그를 설정하지 않은 한 에러도 발생하지 않습니다. 라우팅 키 네이밍 규칙({도메인}.{이벤트}.{세부항목})을 팀 단위로 먼저 합의하고 시작해야 합니다.
Direct Exchange의 "멀티캐스트 함정"
같은 라우팅 키로 여러 큐를 바인딩하면 Fanout처럼 동작합니다. 1:1 전달을 기대하고 설정했는데 의도치 않게 메시지가 복제되는 경우가 있으니, 바인딩 상태를 주기적으로 확인해야 합니다.
정리
| Exchange 타입 | 라우팅 기준 | 적합한 상황 | 주의사항 |
|---|---|---|---|
| Direct | 라우팅 키 정확 매칭 | 1:1 전달 | 동일 키로 여러 큐 바인딩 시 멀티캐스트 |
| Fanout | 없음 (전체) | 브로드캐스트 | 선택적 필터링 불가 |
| Topic | 와일드카드 패턴 | 카테고리별 분배 | 매칭 안 되면 메시지 유실 |
| Headers | 헤더 속성 조합 | 복합 조건 | 성능 상대적으로 낮음 |
실무에서는 대부분 Direct 와 Topic 으로 충분하며, 전체 브로드캐스트가 필요하면 Fanout, 복합 조건이 필요하면 Headers 를 선택합니다.
**공식 문서 참고 **: AMQP 0-9-1 Model Explained | RabbitMQ Tutorials