익스체인지
익스체인지 (Exchange)
익스체인지는 AMQP 0-9-1에서 퍼블리셔가 메시지를 게시하는 엔티티예요. 익스체인지를 거친 메시지는 하나 이상의 큐나 스트림으로 라우팅되죠. 이번엔 익스체인지 타입이 라우팅을 어떻게 결정하는지, 그리고 기본 익스체인지와 바인딩의 성질까지 살펴볼게요.
본문
AMQP 0-9-1에서 익스체인지는 퍼블리셔가 메시지를 게시하면 그 메시지를 큐나 스트림 집합으로 라우팅하는 엔티티예요. 익스체인지는 AMQP 0-9-1의 다른 토폴로지 요소처럼 애플리케이션이 클라이언트 라이브러리로 선언해요. 익스체인지의 목적은 익스체인지를 통과하는 모든 메시지를 하나 이상의 큐·스트림·다른 익스체인지로 라우팅하는 거예요. 익스체인지 타입과 바인딩 속성이 라우팅 로직을 구현해요.
모든 익스체인지는 다른 토폴로지 요소처럼 하나의 가상 호스트에 속해요. 시스템 익스체인지도 예외가 아니고, 이들은 기본 가상 호스트에만 존재해요. 가상 호스트가 생성되면 사전 선언된 익스체인지가 자동으로 여러 개 생성돼요.
모든 익스체인지에는 이름이 있어야 해요. 기본 익스체인지(아래 참고)라는 특별한 익스체인지는 게시 대상으로 지정할 때 빈 문자열을 이름으로 써요. 다른 맥락(예: 권한 관리)에서는 같은 익스체인지를 amq.default로 지칭할 수 있지만, 이 이름으로 메시지를 게시할 수는 없어요.
익스체인지 타입
익스체인지는 타입이 여러 가지일 수 있어요. 익스체인지 타입은 그 익스체인지에 게시된 메시지를 어떻게 라우팅할지 결정해요. 예를 들어 한 타입은 토픽(패턴) 기반 라우팅을 쓰는 반면, 다른 타입은 모든 메시지를 모든 바인딩된 큐로 무조건 라우팅할 수 있어요.
RabbitMQ에는 여러 익스체인지 타입이 내장되어 있어요.
- Fanout: 튜토리얼 3
- Topic: 튜토리얼 5
- Direct: 튜토리얼 4
- 기본 direct 익스체인지: 특별한 성질을 가진 내장 direct 익스체인지
- Local Random
- Modulus Hash
- JMS Topic
- Consistent Hashing 익스체인지
- Random 익스체인지
- Recent history 익스체인지
- Headers
익스체인지 타입은 플러그인으로도 제공할 수 있어요.
Fanout 익스체인지는 게시된 모든 메시지의 사본을 바인딩된 모든 큐·스트림·익스체인지로 라우팅해요. 이때 메시지의 라우팅 키는 완전히 무시돼요. 튜토리얼 3에서 이 타입의 사용법을 볼 수 있어요.
Topic 익스체인지는 메시지의 라우팅 키와 바인딩 시점에 사용한 라우팅(바인딩) 키 패턴을 패턴 매칭해요. 라우팅을 위해 키는 .으로 세그먼트로 나뉘고, 일부 세그먼트는 특정 값으로, 일부는 와일드카드로 채워져요. *는 정확히 한 세그먼트, #은 0개 이상(여러 개 포함)의 세그먼트를 뜻해요.
예를 들어:
- 바인딩(라우팅) 키 패턴
regions.na.cities.*은 메시지 라우팅 키regions.na.cities.toronto와regions.na.cities.newyork을 매칭하지만,regions.na.cities는 매칭하지 않아요.*는 정확히 한 세그먼트만 매칭하는 와일드카드이기 때문이에요 - 바인딩(라우팅) 키 패턴
audit.events.#은audit.events,audit.events.users.signup,audit.events.orders.placed는 매칭하지만, 두 번째 세그먼트가 맞지 않으므로audit.users는 매칭하지 않아요 - 바인딩(라우팅) 키 패턴
#은 어떤 라우팅 키든 매칭해서, 그런 패턴을 쓰는 바인딩에서는 토픽 익스체인지가 fanout처럼 동작하게 해요
튜토리얼 5에서 이 타입의 사용법을 볼 수 있어요.
Direct 익스체인지는 바인딩 라우팅 키의 정확한 동등 비교로 하나 이상의 바인딩된 큐·스트림·익스체인지에 라우팅해요. 예를 들어 바인딩(라우팅) 키 abc는 abc만 매칭해요. 튜토리얼 4에서 사용법을 볼 수 있어요.
기본 익스체인지는 몇 가지 특별한 성질을 가진 direct 익스체인지예요.
- 항상 존재해요(사전 선언됨)
- AMQP 0-9-1 클라이언트에게 이름은 빈 문자열(
"")이에요 - 큐가 선언되면 RabbitMQ는 큐 이름을 라우팅 키로 삼아 그 큐를 기본 익스체인지에 자동으로 바인딩해요
이로써 AMQP 0-9-1 애플리케이션은 이름만으로 큐에 "직접" 게시할 수 있는 편리한 메커니즘을 얻게 돼요. 겉으론 그래 보여도 실제로는 여전히 direct 익스체인지가 관여하고 있죠.
tip: 기본 익스체인지는 그 특별한 성질 때문에 쓰는 거예요. 애플리케이션이 명시적으로 바인딩을 만드는 "일반" 익스체인지로 쓰라고 만든 게 아니에요. direct 익스체인지와 커스텀 토폴로지가 필요하다면 별도의 direct 익스체인지를 선언해서 쓰는 걸 고려하세요.
Local Random은 별도 문서 가이드에서 다루는 전문 익스체인지 타입이에요. JMS Topic 익스체인지는 RabbitMQ JMS 클라이언트의 특정 JMS 기능을 구현하기 위해 도입됐어요.
바인딩
익스체인지는 선언되었을 때 어떤 큐·스트림도 알지 못해요. 처음 선언된 익스체인지는 빈 명명된 라우팅 테이블이에요. 테이블에 라우팅 규칙을 채우려면 큐·스트림 또는 (아래 참고) 다른 익스체인지가 그 익스체인지에 바인딩되어야 해요. 즉, 애플리케이션이 익스체인지와 큐·스트림 사이에 바인딩을 만들어야 해요.
바인딩은 다음 속성을 가져요.
- 소스 이름: 이 바인딩이 추가되는 익스체인지의 이름
- 대상 이름: 대상 큐·스트림 또는 다른 익스체인지의 이름
- 대상 타입(
queue는 큐·스트림용,exchange는 익스체인지-익스체인지 바인딩용) - 선택적 인자 맵(헤더 익스체인지 같은 특정 익스체인지 타입이 사용)
바인딩은 소스와 대상에서 내구성을 상속해요. 그래서 바인딩은:
- 완전 내구성: 익스체인지와 대상 큐/스트림 모두 내구성
- 반 내구성: 실질적으로 익스체인지는 내구성, 대상 큐/스트림은 일시적
- 완전 일시적: 익스체인지와 대상 큐/스트림 모두 일시적
반 내구성·완전 일시적 바인딩 지원은 미래에 제거될 예정이에요. 바인딩 내구성은 일시적 classic 큐와 함께 쓸 때 중요할 수 있어요.
warning: 비복제(classic) 큐를 호스팅하는 노드가 중지되면, 그 노드의 모든 일시적 큐와 반 내구성 바인딩이 제거돼요. 큰 토폴로지에서는 이 작업에 시간이 걸리고, 노드가 다시 살아나 애플리케이션이 재연결되면 반 내구성·일시적 바인딩이 동시에 제거·재추가되면서 바인딩 상태가 일관되지 않아 혼란스러운 라우팅 동작이 생길 수 있어요. 이 문제를 피하려면 내구성(복제 여부와 무관) 큐만 사용하고, 선택적으로 짧은 TTL을 두고, 스트림을 쓰며, 일시적 큐 사용은 예를 들어 기본 익스체인지로 게시하는 경우로 한정하세요.
AMQP 0-9-1 명세에 따라 모든 가상 호스트에는 사전 선언된 익스체인지가 몇 개 있어요.
- 기본 익스체인지
- 타입별로 하나씩의
amq.*익스체인지(예:amq.fanout,amq.topic) amq.rabbitmq.log— 옵트인 로깅 기능이 쓰는 시스템 토픽 익스체인지amq.rabbitmq.event— 내부 이벤트 메커니즘이 쓰는 시스템 토픽 익스체인지
익스체인지 속성
익스체인지에는 선언 시 지정할 수 있는 몇 가지 핵심 속성이 있어요. 큐처럼 익스체인지도 내구성 또는 일시적일 수 있어요. 하지만 일시적 익스체인지는 실제로 거의 쓰이지 않아요. 다음과 같은 이유로 내구성 익스체인지를 쓰는 게 좋아요.
- 일시적·클라이언트 특정 상태를 가진 애플리케이션은 커스텀 익스체인지를 거의 필요로 하지 않고(
amq.topic같은 사전 선언된 것을 주로 사용), 그런 익스체인지에 의존해요 - 4.x 시리즈에서 더 나아가 Khepri가 유일하게 지원되는 메타데이터 스토어가 되면, 일시적(비내구성) 엔티티 지원이 제거될 예정이에요
자동 삭제 익스체인지는 마지막 바인딩이 제거될 때 삭제돼요. 이 메커니즘은 바인딩이 적어도 하나 존재해야 동작하므로, 한 번도 바인딩되지 않은 익스체인지는 자동 삭제되지 않아요.
선택적 익스체인지 인자(AMQP 0-9-1 프로토콜의 필드명 때문에 "x-arguments"라고도 불러요)는 익스체인지를 선언할 때 클라이언트가 제공할 수 있는 임의의 키/값 쌍 맵(딕셔너리)이에요. 이 맵은 대체 익스체인지(alternate exchange)와 헤더 익스체인지 같은 특정 기능·타입이 사용해요. 이런 선택적 인자는 폴리시로도 설정할 수 있어요.
tip: 선택적 인자를 폴리시로 설정할 수 있으면, 애플리케이션 코드에 값을 하드코딩하기보다 항상 폴리시를 먼저 고려하세요.
선택적 익스체인지 인자는 두 가지 방식으로 설정돼요.
- 폴리시로 익스체인지 그룹에 적용(권장)
- 선언 시점에 익스체인지 단위로 적용
전자가 더 유연하고 간섭이 적으며, 애플리케이션 수정·재배포가 필요 없어요. 그래서 대부분의 사용자에게 권장돼요. 다만 일부 선택적 인자는 동적으로 변경할 수 없고 선언 시점에 알아야 하므로 클라이언트만 제공할 수 있어요. 다만 그런 제약은 주로 큐·스트림에 적용되고 익스체인지에는 덜해요.
클라이언트가 선택적 인자를 제공하는 방식은 클라이언트 라이브러리마다 다르지만, 보통 익스체인지를 선언하는 함수(메서드)의 durable, auto_delete 등 인자 옆의 인자로 제공돼요.
같은 키가 클라이언트 제공 x-arguments와 폴리시 양쪽에 있으면 전자가 우선해요. 하지만 운영자 폴리시도 사용 중이면 그게 클라이언트 제공 인자보다도 우선해요. 운영자 폴리시는 보호 메커니즘이라 클라이언트 제공 값과 사용자 폴리시 값을 덮어써요. 숫자 값의 경우 둘 중 더 낮은 값이 사용돼요. 애플리케이션이 더 낮은 값을 필요로 하거나 선택하면 운영자 폴리시가 허용하고, 운영자 폴리시에 정의된 값보다 높은 값은 쓸 수 없어요. 운영자 폴리시는 리소스 사용(예: 최대 디스크 공간 사용량)과 관련된 애플리케이션 제어 파라미터에 가드레일을 도입할 때 유용해요.
익스체인지 간 바인딩과 대체 익스체인지
큐·스트림 외에도, RabbitMQ의 AMQP 0-9-1 프로토콜 확장인 익스체인지-익스체인지 바인딩(줄여서 E2E)으로 익스체인지를 다른 익스체인지에 바인딩할 수 있어요. 애플리케이션은 소스 익스체인지에 게시하고, 소스 익스체인지가 메시지를 대상 익스체인지로 라우팅해요.
note: 효율성 때문에, E2E 바인딩이 있는 소스 익스체인지에 게시된 메시지는 소스와 그에 바인딩된 모든 대상 익스체인지의 사용 가능한 바인딩 전체를 합쳐 한 번만 라우팅돼요. 즉, E2E 바인딩은 메시지를 재게시하는 게 아니라, 소스·대상 익스체인지 양쪽의 타입을 존중하는 라우팅 확장이에요. 그래서 대상 익스체인지의 인그레스(수신) 메시지 속도 지표는 갱신되지 않아요. 대상 큐·스트림 지표는 소스 익스체인지에 바인딩됐든 대상 익스체인지에 바인딩됐든 갱신돼요.
대체 익스체인지는 적합한 바인딩이 없어 메시지를 라우팅하지 못한 익스체인지가, 라우팅을 다른 익스체인지에 위임할 수 있게 해 주는 기능이에요. 토폴로지 마이그레이션을 하거나 라우팅 불가 메시지를 수집할 때 유용해요.
RabbitMQ는 로깅·감사 목적으로 내장 익스체인지도 제공해요.
amq.rabbitmq.log— 옵트인 로깅 기능이 쓰는 시스템 토픽 익스체인지amq.rabbitmq.event— 내장 플러그인이 제공하고 내부 이벤트 메커니즘이 쓰는 시스템 토픽 익스체인지amq.rabbitmq.trace— 메시지 트레이싱 메커니즘이 사용
두 익스체인지 덕분에 AMQP 0-9-1 클라이언트 라이브러리만 있으면 커스텀 로그 수집·감사 애플리케이션을 개발할 수 있어요.
더 알아보기
- AMQP 0-9-1 모델 — 익스체인지·큐·바인딩·라우팅 키의 전체 그림
- 큐 (Queues) — 라우팅의 도착지가 되는 큐
- 확인과 인정 (Confirms) — 데이터 안전성과 퍼블리셔 확인
- 안정성 가이드 — 지속성·재전송 전반