콘텐츠로 바로가기

Pub-Sub & Fan-out Mechanics

하나의 메시지를 여러 구독자에게 동시에 전달하는 발행/구독 모델의 원리와 대규모 트래픽 분산을 위한 팬아웃 수리 메커니즘을 다루는 학습 노드입니다.

Article
M

Me

hyunyoun's Blog

network-communicationnetworkcommunicationdistributed-messagingevent-streamingpub-subfan-out-mechanicslearning10 min read

1. Overview

펍섭과 팬아웃 역학(Pub-Sub & Fan-out Mechanics)은 하나의 메시지를 여러 소비자에게 동시에 뿌려야 할 때, 애플리케이션 코드가 수십 번 반복해서 메시지를 복사하는 바보짓을 멈추고 네트워크 인프라 레벨에서 단 한 번의 전송으로 트래픽을 증폭시키는 라우팅 마법을 해부합니다.

학습자는 A가 B에게 몰래 쪽지를 건네는 '1<1> 통신(Point-to-Point)'의 한계를 넘어서, 사내 방송국처럼 모두에게 외치는 발행-구독(Pub/Sub) 아키텍처의 공간적 디커플링을 뜯어봅니다. 나아가 RabbitMQ의 뇌 역할을 하는 **익스체인지(Exchange)**를 통해, 묻지도 따지지도 않고 복사해 주는 Fanout, 특정 키워드만 쏙쏙 골라 배달하는 DirectTopic 라우팅의 정교한 분기 처리를 장악합니다. 마지막으로, 생산자(Producer)의 송신 비용을 O(N)O(N)에서 O(1)O(1)로 박살 내어 백엔드 서버의 CPU와 네트워크 대역폭을 보존하는 인프라 오프로딩(Offloading) 역량을 확보합니다.

2. Scope & Boundaries

In-Scope

  • Pub/Sub Pattern: 1 메시지 전달 모델, Publisher와 Subscriber의 물리적/논리적 분리.
  • AMQP Exchanges: RabbitMQ의 라우팅 컴포넌트 (Direct, Fanout, Topic, Headers).
  • Fan-out Architecture: 메시지 복제 및 분배를 애플리케이션이 아닌 브로커(인프라)가 담당하는 구조.
  • Routing Key & Binding: 익스체인지와 큐(Queue)를 연결하는 규칙(Binding)과 필터링(Routing Key).

Out-of-Scope

  • Kafka의 Pub/Sub 메커니즘: 카프카가 컨슈머 그룹(Consumer Group)을 통해 Pub/Sub을 흉내 내는 방식 \rightarrow 08-05-02 Event Streaming & Kafka 영역에서 기학습.
  • 웹 브라우저 클라이언트 푸시: 클라이언트에게 실시간으로 브로드캐스팅하는 기술 \rightarrow 08-04-03 WebSocket & SSE 영역으로 분리.

Boundaries

  • Point-to-Point vs Pub/Sub: Point-to-Point(1<1>) 큐는 100만 원 입금 메시지를 '회계 서버' 혼자 먹고 끝냅니다. 다른 서버는 못 봅니다(소비적). 반면 Pub/Sub(1)은 입금 메시지를 '회계 서버', '알림 서버', '통계 서버' 3곳이 동시에 복사해서 가져갑니다(비소비적 브로드캐스트). 전자는 일감 분배(Work Queue)에 쓰이고, 후자는 이벤트 전파(Event Notification)에 쓰인다는 도메인 역할의 차이를 명확히 경계 짓습니다.

3. Counterexample

  • 애플리케이션 레벨 팬아웃의 CPU 학대: "회원 가입 완료" 이벤트를 메일 서버, 쿠폰 서버, 통계 서버 3곳에 전달해야 합니다. 개발자가 회원가입 서버 코드에 sendToMailQueue(), sendToCouponQueue(), sendToStatQueue() 함수를 3번 연속으로 호출하도록 짰습니다. 나중에 알림 서버, 추천 서버가 10개로 늘어나자, 회원가입 서버는 1명의 유저가 가입할 때마다 네트워크로 메시지를 10번씩 쏘느라 CPU와 대역폭(Bandwidth)이 터져나갔습니다. 브로커의 Fanout Exchange를 써서 1번만 쏘면 브로커가 10번 복사해 주는 인프라 확장을 몰랐던 처참한 하드코딩입니다.
  • 무지성 브로드캐스트의 큐 범람: 시스템의 모든 로그(INFO, WARN, ERROR)를 Fanout 익스체인지로 때려 박았습니다. 에러 로그만 보고 싶은 '알람 서버'의 큐에도 하루 1억 건의 INFO 로그가 같이 쏟아져 들어옵니다. 알람 서버는 쓸데없는 INFO 로그를 꺼내서 버리는(Drop) 헛수고를 하다가 진짜 ERROR 로그를 제때 처리하지 못하고 뻗어버렸습니다. 패턴 매칭(*.ERROR)으로 필요한 것만 라우팅해 주는 Topic Exchange를 쓰지 않아 발생한 끔찍한 네트워크 낭비입니다.

4. Prerequisites

  • Message Broker 기본 (Basic): 큐(Queue)와 비동기 통신. (08-05-01 Broker Physics)
  • 이벤트 기반 아키텍처 (Basic): 마이크로서비스 간의 이벤트 전파. (07-03-01 EDA)

5. Learning Map

Sequence Core Cluster Objective & Description Evidence (BoK)
1 The Pub/Sub Paradigm "누가 들을지 난 관심 없어, 일단 방송한다!" 생산자와 소비자의 존재 자체를 서로 숨겨버리는 극강의 공간적 디커플링을 쥡니다. P1
2 Fan-out Exchange (Broadcast) 생산자가 딱 1번 던진 메시지를 브로커가 복제술을 써서 수십 개의 큐로 동시에 꽂아버리는 인프라 증폭 마법을 해부합니다. P5
3 Direct Exchange (Targeting) 브로드캐스트의 낭비를 막기 위해, 라우팅 키(Routing Key)라는 꼬리표를 달아 정확히 일치하는 큐로만 저격(Targeting)하는 분기를 뜯어봅니다. Industry
4 Topic Exchange (Pattern Match) user.login.seoul 처럼 계층화된 꼬리표에 user.*# 같은 와일드카드 정규식을 섞어, 우아하게 트래픽을 분류하는 고급 라우팅을 장악합니다. Industry

6. Learning Topics

Basic

Core Topic 01: 허공에 외치기 (The Pub/Sub Paradigm)

  • Why to Learn: 메시지를 보낼 때 "저기 있는 알림 서버 큐에 넣어줘"라고 목적지를 지정(Point-to-Point)하는 낡은 결합을 버리고, 누가 듣든 말든 일단 방송(Publish)하고 보는 철저한 독립성을 통찰하기 위함입니다.
  • What to Learn:
    • Concepts: Publisher(발행자), Subscriber(구독자), Spatial Decoupling(공간적 디커플링), Event Notification.
    • Skills: 결제 완료 비즈니스 로직에서 '이메일 발송', '재고 차감' 등의 후속 작업(Subscriber)이 몇 개가 추가되든 결제 서버(Publisher)의 코드는 단 한 줄도 수정되지 않는 아키텍처 설계.
  • How to Learn:
    • 1단계: 공간적 결합 (Point-to-Point): A가 B의 큐 이름을 정확히 알아야만 보낼 수 있습니다. C라는 새로운 서버가 추가되어 같은 데이터를 원하면, A의 코드를 뜯어고쳐 C의 큐 이름도 추가해 줘야 합니다(OCP 위배).
    • 2단계: 허공의 메아리 (Pub/Sub): A는 이제 B나 C의 존재를 아예 모릅니다. A는 그냥 브로커의 로비(Exchange)에 "결제 1건 발생!" 하고 확성기로 외치고 뒤돌아섭니다. 이 소식을 듣고 싶은 B와 C는 브로커에게 미리 "결제 소식 나오면 나한테 복사해 줘(Subscribe)"라고 신청해 둡니다. A의 코드 변경 없이 D, E 서버를 무한대로 붙일 수 있는 공간적 해방을 뜯어봅니다.
  • Implement: Publisher-Subscriber 결합도 테스트 시뮬레이션. Publisher: publish('PAYMENT_DONE', {id: 1}). (큐 이름 모름). Sub_1(Mail): bind('PAYMENT_DONE'). Sub_2(Stock): bind('PAYMENT_DONE'). 시스템 가동 중 Sub_3(Stats)가 새로 추가되어 bind를 걸어도, Publisher 프로세스는 재시작이나 코드 수정 없이 즉각 3곳으로 데이터가 퍼져나가는(Broadcast) OCP(Open-Closed Principle) 충족 시각화.

Core Topic 02: 복제술의 미학, 팬아웃 (Fan-out Exchange)

  • Why to Learn: 앱 1개가 네트워크 통신을 10번 하던 O(N)O(N)의 발송 오버헤드를, 브로커가 대신 복제해 주는 O(1)O(1)로 밀어버려 백엔드 서버의 성능을 극대화하기 위함입니다.
  • What to Learn:
    • Concepts: AMQP Exchange, Fanout Exchange, Binding, Message Cloning, Network Amplification.
    • Skills: 여러 부서가 동시에 받아봐야 하는 '전사 공지사항' 데이터를 쏠 때, RabbitMQ의 Fanout 익스체인지를 설정하여 묶여있는(Bound) 모든 큐에 조건 없이 복사해 넣는 파이프라인 구축.
  • How to Learn:
    • 1단계: AMQP 익스체인지(Exchange): RabbitMQ는 메시지를 큐에 바로 꽂지 않습니다. 무조건 '익스체인지'라는 우체국 분류 센터를 먼저 거칩니다.
    • 2단계: 무지성 복사 (Fanout): 익스체인지 타입을 Fanout으로 설정합니다. 여기에 큐 3개(A, B, C)를 연결(Binding)해 둡니다. 생산자가 메시지 1개를 이 익스체인지에 딱 던집니다. 익스체인지는 내용이나 꼬리표를 묻지도 따지지도 않고, 메시지를 3개로 복제해서 A, B, C 큐에 쑤셔 넣습니다. 생산자의 네트워크 카드(NIC)는 단 1번만 패킷을 쏘고, 나머지 3번의 증폭은 빵빵한 브로커 서버가 대신해 주는 인프라 오프로딩을 해부합니다.
  • Implement: Fanout Network I/O 절감 계산기. 메시지 크기 1MB. 구독자 수 100개(서버 100대). App-level Fanout: 앱 서버가 1MB를 100번 쏨 \rightarrow Outbound 100MB 소모, 대역폭 터짐. Broker-level Fanout: 앱 서버가 브로커에 1MB 딱 1번 쏨 \rightarrow Outbound 1MB. 브로커가 내부 메모리에서 복제하여 100MB로 증폭 발송. 앱 서버의 네트워크 부하를 1/100로 박살 내는 렌더링.

Practical

Core Topic 03: 표적 저격, 다이렉트 라우팅 (Direct Exchange)

  • Why to Learn: 무조건 다 복사해 주는 Fanout의 낭비를 막고, 내가 쏜 메시지가 "정확히 이 조건을 원하는 큐"에만 꽂히도록 라우팅 룰을 튜닝하기 위함입니다.
  • What to Learn:
    • Concepts: Direct Exchange, Routing Key, Binding Key, Exact Match, Unicast / Multicast.
    • Skills: 로그(Log)를 수집할 때 ERROR 라우팅 키를 단 메시지만 알람 서버 큐로 보내고, INFO 키를 단 메시지는 무시하거나 보관 서버 큐로만 꽂히게 하는 분기(Switching) 로직 작성.
  • How to Learn:
    • 1단계: 꼬리표 (Routing Key): 생산자가 메시지를 익스체인지에 던질 때 겉면에 포스트잇(Routing Key)을 붙입니다. 예: routing_key="ERROR".
    • 2단계: 정확한 매칭 (Direct): 익스체인지 타입을 Direct로 설정합니다. A 큐는 binding_key="ERROR"로 연결하고, B 큐는 binding_key="INFO"로 연결합니다. 익스체인지는 포스트잇에 적힌 글씨와 큐의 결속(Binding) 글씨가 완벽히 똑같은(Exact Match) 곳으로만 메시지를 던집니다. 즉 ERROR 쪽지가 오면 A 큐로만 가고 B 큐로는 안 갑니다. 불필요한 큐에 쓰레기 데이터가 쌓이는 걸 막아내는 세미 브로드캐스트(Targeting)를 뜯어봅니다.
  • Implement: Direct 라우팅 로직 모사 (Python). ExchangeType = DIRECT. Queue_Alarm 바인딩: [ERROR, FATAL]. Queue_Storage 바인딩: [INFO, WARN, ERROR, FATAL]. 수신 메시지 Msg(RoutingKey="WARN") \rightarrow Queue_Alarm은 무시됨, Queue_Storage에만 들어감. 수신 메시지 Msg(RoutingKey="FATAL") \rightarrow 두 큐 모두에 들어감(Multicast). 유연한 필터링 차트 시각화.

Advanced

Core Topic 04: 정규식의 마법, 토픽 익스체인지 (Topic Exchange)

  • Why to Learn: Direct 방식의 1<1> 텍스트 매칭을 넘어, 계층화된 문자열과 와일드카드(*, #)를 조합해 무한대의 다이내믹 라우팅 룰을 브로커 단에서 구현하는 극강의 유연성을 장악하기 위함입니다.
  • What to Learn:
    • Concepts: Topic Exchange, Hierarchical Routing Key (a.b.c), Wildcards (* 한 단어 매치, # 0개 이상 다중 단어 매치).
    • Skills: device.seoul.sensor1, device.busan.sensor2 처럼 날아오는 수백만 개의 IoT 데이터 중, 서울 지역의 모든 장비(device.seoul.*) 데이터만 모으는 큐를 동적으로 바인딩하기.
  • How to Learn:
    • 1단계: 계층형 꼬리표: 라우팅 키를 점(.)으로 구분해서 만듭니다. [카테고리].[지역].[장비]. 예: log.asia.server1.
    • 2단계: 와일드카드 (Topic): 익스체인지 타입을 Topic으로 바꿉니다. A 큐는 아시아 전체 로그를 원하므로 log.asia.*로 바인딩합니다(*는 딱 한 단어 매칭). B 큐는 지역 상관없이 모든 로그를 다 원하므로 log.#으로 바인딩합니다(#은 뒤에 몇 단어가 오든 다 매칭).
    • 3단계: 만약 log.asia.server1 메시지가 오면 A 큐와 B 큐 둘 다 들어갑니다. 하지만 log.europe.server2가 오면 A 큐는 거르고 B 큐에만 들어갑니다. 애플리케이션 코드에 복잡한 if/else 정규식을 짤 필요 없이, 브로커 인프라가 알아서 트래픽을 분류하고 필터링해 주는 예술적 라우팅을 해부합니다.
  • Implement: Topic Exchange 패턴 매칭 엔진 모사. 입력 메시지 RoutingKey = "kr.seoul.gangnam.temp". Queue_1 Binding = "kr.*.*.temp" \rightarrow Match OK (별이 딱 2개). Queue_2 Binding = "kr.#" \rightarrow Match OK (하위 모두 허용). Queue_3 Binding = "kr.seoul.*" \rightarrow Match FAIL (별 1개인데 단어는 2개 남음). 문자열 토크나이저(Tokenizer)가 인프라 레벨에서 트래픽을 가려내는 고속 정규식 렌더링.

7. Terminology

Term (EN / ko, abbr) 1문장 정의 단계(기본/권장/실무/심화) 역할/맥락 관련 개념 유사/대비/함께 사용 오해 포인트 Evidence(Primary/Secondary/Industry) Flags(core)
Pub/Sub (발행/구독 모델) 메시지를 보내는 놈(Publisher)과 받는 놈(Subscriber)이 서로 누군지 전혀 알 필요 없이, 중간에 방송국(Broker)을 두고 허공에 외치는 완벽한 공간적 디커플링 패턴입니다. 기본 1 메시지 브로드캐스팅 Decoupling / Event-Driven Point-to-Point (1<1> 큐) Pub/Sub은 기본적으로 한 번 방송하고 끝나는 휘발성이 강하므로, 못 받은 수신자를 위해 데이터를 남겨두려면 큐(Queue)나 로그(Kafka)와 결합해야 함 P1:CS2023 core
Exchange (익스체인지) RabbitMQ(AMQP)로 들어온 모든 메시지가 큐에 도달하기 전 무조건 거쳐가야 하는 우체국 분류 센터로, 라우팅 룰(타입)에 따라 메시지를 찢거나 복사해 줍니다. 권장 인프라 레벨의 메시지 라우팅 엔진 AMQP / Routing Key / Binding Queue (저장소) 익스체인지 자체는 데이터를 '저장'하는 곳이 절대 아니며, 연결된 큐가 없으면 메시지를 바로 쓰레기통에 버림(Drop) P5:SFIA core
Fanout (팬아웃) 1개의 입력을 N개의 출력으로 무식하게 복제해 내는 동작으로, 앱 서버가 네트워크를 100번 탈 일을 브로커가 대신 100배로 증폭시켜 주는 인프라 최적화 기술입니다. 실무 O(1) 네트워크 오버헤드로 브로드캐스트 Broadcast / Exchange Type Direct / Topic (필터링) 조건 필터링이 아예 없기 때문에, 무분별하게 Fanout을 쓰면 원치 않는 큐까지 트래픽이 쏟아져 들어가 시스템 대역폭을 낭비함 Industry core
Topic Exchange (토픽 익스체인지) *.ERRORKR.# 처럼 와일드카드 기호를 사용해 계층화된 문자열을 판별하고, 정규식에 일치하는 큐로만 메시지를 분기시키는 가장 똑똑한 라우팅 타입입니다. 심화 패턴 매칭 기반 동적 라우팅 Hierarchical Routing Key / Wildcard Direct Exchange (완전 일치) 별표(*)는 정확히 한 단어(점과 점 사이)만 매칭하고, 샵(#)은 0개 이상의 다중 단어를 매칭한다는 문법적 차이를 헷갈리면 라우팅이 꼬임 Industry core

8. References

Primary

  • [P1] CS2023 - Software Engineering (SE) - Event-Driven and Asynchronous Architectures
  • [P5] SFIA - Systems Integration (SINT) - Pub/Sub and Messaging Topologies

Secondary

  • [Enterprise Integration Patterns] Gregor Hohpe - Publish-Subscribe Channel, Routing Slip
  • [RabbitMQ in Action] Alvaro Videla - Exchanges, Routing, and Beyond

Industry

  • [RabbitMQ Documentation] - Tutorials: Publish/Subscribe, Routing, Topics
  • [AWS Architecture Blog] - Fanout SQS message routing with SNS

9. Final Checklist

Primary

  • 생산자(Publisher)가 수신자(Subscriber)의 주소나 큐 이름을 직접 알 필요 없이 이벤트를 발행함으로써, 시스템이 거대해져도 생산자 코드가 단 한 줄도 수정되지 않는(OCP) 공간적 디커플링의 원리를 설명할 수 있는가?
  • 메시지를 10곳으로 보내기 위해 애플리케이션 단에서 send()를 10번 호출하는 O(N)O(N) 병목을, 브로커의 Fanout Exchange를 이용해 O(1)O(1)의 송신 비용으로 덜어내는(Offloading) 아키텍처적 이점을 증명할 수 있는가?

Secondary

  • Direct Exchange를 사용하여 수만 건의 로그 트래픽 중 Routing Key가 정확히 "ERROR"와 일치(Exact Match)하는 메시지만 특정 알람 큐로 스위칭(Switching)하여 불필요한 큐 범람을 막아낼 수 있는가?
  • 계층형 라우팅 키 체계(예: region.service.level)에서 Topic Exchange의 와일드카드(*, #)를 활용하여, 아시아 지역의 모든 경고 로그(asia.*.WARN)를 하나의 큐로 동적 바인딩(Binding)하는 필터링 룰을 해부할 수 있는가?

Industry

  • 클라우드 인프라(AWS) 환경에서 SNS(Simple Notification Service)를 Pub/Sub의 익스체인지(Fanout)로 삼고, 그 뒤에 SQS(Simple Queue Service) 여러 개를 붙여 마이크로서비스 확장에 유연하게 대처하는 SNS-SQS Fan-out 파이프라인을 설계할 수 있는가?
  • RabbitMQ에서 익스체인지에 연결된 큐가 단 한 개도 없을 때 발행된 메시지가 '블랙홀'처럼 조용히 증발(Drop)해버리는 현상을 방지하기 위해, Alternate ExchangeMandatory 플래그를 설정하여 버려진 메시지를 회수하는 안전망을 논증할 수 있는가?

Distributed Messaging & Event Streaming

3 / 4