메시지 큐 기초 (Message Queue Fundamentals)
메시지 큐 기초 (Message Queue Fundamentals)¶
난이도: ⭐⭐⭐
개요¶
메시지 큐는 분산 시스템에서 서비스 간 비동기 통신을 가능하게 하는 핵심 인프라입니다. 이 장에서는 동기와 비동기 통신의 차이, 큐와 토픽의 개념, 메시지 전달 보장 수준, 그리고 멱등성에 대해 학습합니다.
목차¶
1. 동기 vs 비동기 통신¶
동기 통신 (Synchronous)¶
요청 후 응답을 기다리는 방식입니다.
┌─────────────────────────────────────────────────────────────────────────┐
│ 동기 통신 (Request-Response) │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────┐ ┌──────────┐ │
│ │ Service A│ │ Service B│ │
│ └────┬─────┘ └────┬─────┘ │
│ │ │ │
│ │─────── HTTP Request ────────────────►│ │
│ │ │ │
│ │ (Service A 블로킹) │ 처리 중... │
│ │ 요청 스레드 대기 │ │
│ │ │ │
│ │◄────── HTTP Response ───────────────│ │
│ │ │ │
│ ▼ ▼ │
│ 다음 작업 계속 처리 완료 │
│ │
│ 특징: │
│ - 즉각적인 응답 필요 │
│ - 호출자가 응답 대기 │
│ - Service B 장애 시 Service A도 영향 │
│ │
└─────────────────────────────────────────────────────────────────────────┘
비동기 통신 (Asynchronous)¶
메시지를 보내고 즉시 다른 작업을 계속합니다.
┌─────────────────────────────────────────────────────────────────────────┐
│ 비동기 통신 (Message Queue) │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────┐ ┌──────────────┐ ┌──────────┐ │
│ │ Service A│ │ Message Queue│ │ Service B│ │
│ │(Producer)│ │ │ │(Consumer)│ │
│ └────┬─────┘ └──────┬───────┘ └────┬─────┘ │
│ │ │ │ │
│ │──── Send Msg ───►│ │ │
│ │◄─── ACK ─────────│ │ │
│ │ │ │ │
│ ▼ │ │ │
│ 다음 작업 계속 │◄─── Poll ────────│ │
│ (블로킹 없음) │──── Deliver ────►│ │
│ │ │ 처리 중... │
│ │◄─── ACK ─────────│ │
│ │ ▼ │
│ │ 처리 완료 │
│ │
│ 특징: │
│ - 발신자/수신자 독립적 │
│ - 느슨한 결합 │
│ - Service B 장애 시에도 Service A 정상 동작 │
│ │
└─────────────────────────────────────────────────────────────────────────┘
통신 방식 비교¶
| 특성 | 동기 | 비동기 |
|---|---|---|
| 응답 대기 | 필요 | 불필요 |
| 결합도 | 강함 | 느슨함 |
| 장애 전파 | 즉시 전파 | 격리됨 |
| 실시간성 | 즉시 | 지연 가능 |
| 복잡도 | 낮음 | 높음 |
| 처리량 | 제한적 | 높음 |
2. 메시지 큐의 이점¶
디커플링 (Decoupling)¶
┌─────────────────────────────────────────────────────────────────────────┐
│ 강결합 vs 느슨한 결합 │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ 강결합 (동기): │
│ ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐ │
│ │ A │────►│ B │────►│ C │────►│ D │ │
│ └─────┘ └─────┘ └─────┘ └─────┘ │
│ │ X 장애! │
│ ▼ │
│ A도 실패! (B 대기 → C 장애 → 전체 실패) │
│ │
├─────────────────────────────────────────────────────────────────────────┤
│ 느슨한 결합 (비동기): │
│ ┌─────────────┐ │
│ │ Message │ │
│ ┌─────┐ │ Queue │ ┌─────┐ │
│ │ A │───publish──►├─────────────┤◄──consume──│ B │ │
│ └─────┘ │ [msg][msg] │ └─────┘ │
│ │ │ [msg][msg] │ X 장애! │
│ ▼ └─────────────┘ │
│ A 계속 동작! │
│ (메시지는 큐에 보관, B 복구 후 처리) │
│ │
└─────────────────────────────────────────────────────────────────────────┘
부하 평준화 (Load Leveling)¶
┌─────────────────────────────────────────────────────────────────────────┐
│ 부하 평준화 │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ Without Queue (직접 호출): │
│ │
│ 요청량 │ ████ │
│ │ ████ ← 피크 시 서버 과부하! │
│ 처리용량 │ ───████───────────── │
│ │ ████ │
│ └────────────────────────► 시간 │
│ │
├─────────────────────────────────────────────────────────────────────────┤
│ With Queue (버퍼링): │
│ │
│ 요청량 │ ████ │
│ │ ████ │
│ 큐 크기 │ ───████████████── │
│ │ ████████████ │
│ 처리량 │ ═══════════════════════ ← 일정한 처리 │
│ └────────────────────────► 시간 │
│ │
│ 큐가 버퍼 역할을 하여: │
│ - 피크 트래픽을 흡수 │
│ - Consumer는 일정한 속도로 처리 │
│ - 시스템 안정성 향상 │
│ │
└─────────────────────────────────────────────────────────────────────────┘
확장성 (Scalability)¶
┌─────────────────────────────────────────────────────────────────────────┐
│ 수평 확장 │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌────────────┐ │
│ │ Message │ │
│ │ Queue │ │
│ ├────────────┤ │
│ Producer───►│ [m1][m2] │ │
│ │ [m3][m4] │ │
│ │ [m5][m6] │ │
│ └─────┬──────┘ │
│ │ │
│ ┌──────────┼──────────┐ │
│ ▼ ▼ ▼ │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │Consumer1│ │Consumer2│ │Consumer3│ │
│ │ (m1) │ │ (m2) │ │ (m3) │ │
│ └─────────┘ └─────────┘ └─────────┘ │
│ │
│ 처리량 증가 시: │
│ - Consumer만 추가하면 됨 │
│ - Producer 코드 변경 불필요 │
│ - 메시지는 Consumer들에게 자동 분배 │
│ │
└─────────────────────────────────────────────────────────────────────────┘
내구성 (Durability)¶
┌─────────────────────────────────────────────────────────────────────────┐
│ 메시지 영속성 │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────┐ ┌──────────────────────────┐ │
│ │ Producer │────►│ Message Queue (Durable) │ │
│ └──────────┘ ├──────────────────────────┤ │
│ │ 메모리 │ │
│ │ ┌──────────────────┐ │ │
│ │ │ [msg1] [msg2] │ │ │
│ │ └────────┬─────────┘ │ │
│ │ │ │ │
│ │ ▼ │ │
│ │ 디스크 (WAL) │ │
│ │ ┌──────────────────┐ │ │
│ │ │ msg1, msg2, ... │ │ │
│ │ └──────────────────┘ │ │
│ └──────────────────────────┘ │
│ │
│ 장애 복구: │
│ 1. 브로커 재시작 │
│ 2. 디스크에서 메시지 복원 │
│ 3. Consumer에게 재전송 │
│ → 메시지 유실 방지 │
│ │
└─────────────────────────────────────────────────────────────────────────┘
3. 큐 vs 토픽¶
Point-to-Point (Queue)¶
하나의 메시지는 하나의 Consumer만 처리합니다.
┌─────────────────────────────────────────────────────────────────────────┐
│ Point-to-Point (Queue) │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌───────────────────┐ │
│ ┌──────────┐ │ Queue │ │
│ │Producer 1│─────────►│ ┌───┬───┬───┬───┐ │ │
│ └──────────┘ │ │ A │ B │ C │ D │ │ │
│ │ └───┴───┴───┴───┘ │ │
│ ┌──────────┐ │ │ ┌──────────┐ │
│ │Producer 2│─────────►│ 각 메시지는 │─────────►│Consumer 1│ │
│ └──────────┘ │ 하나의 Consumer만 │ A,C └──────────┘ │
│ │ 처리 │ │
│ │ │ ┌──────────┐ │
│ │ │─────────►│Consumer 2│ │
│ │ │ B,D └──────────┘ │
│ └───────────────────┘ │
│ │
│ 사용 사례: │
│ - 작업 분배 (Work Queue) │
│ - 주문 처리 │
│ - 이메일 발송 큐 │
│ │
└─────────────────────────────────────────────────────────────────────────┘
Publish/Subscribe (Topic)¶
하나의 메시지가 모든 Subscriber에게 전달됩니다.
┌─────────────────────────────────────────────────────────────────────────┐
│ Publish/Subscribe (Topic) │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌───────────────────┐ │
│ ┌──────────┐ │ Topic │ ┌────────────┐ │
│ │Publisher │─────────►│ ┌───┬───┬───┬───┐ │────────►│Subscriber 1│ │
│ └──────────┘ │ │ A │ B │ C │ D │ │ A,B, │ (모든 메시지) │
│ │ └───┴───┴───┴───┘ │ C,D └────────────┘ │
│ │ │ │
│ │ 모든 Subscriber가 │ ┌────────────┐ │
│ │ 모든 메시지를 │────────►│Subscriber 2│ │
│ │ 받음 │ A,B, │ (모든 메시지) │
│ │ │ C,D └────────────┘ │
│ │ │ │
│ │ │ ┌────────────┐ │
│ │ │────────►│Subscriber 3│ │
│ │ │ A,B, │ (모든 메시지) │
│ └───────────────────┘ C,D └────────────┘ │
│ │
│ 사용 사례: │
│ - 이벤트 브로드캐스트 │
│ - 로그 수집 (여러 시스템이 같은 로그 수신) │
│ - 가격 업데이트 (모든 클라이언트에게 전파) │
│ │
└─────────────────────────────────────────────────────────────────────────┘
Consumer Group (하이브리드)¶
Kafka 스타일: Topic + 그룹 내 분산 처리
┌─────────────────────────────────────────────────────────────────────────┐
│ Consumer Group │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌───────────────────┐ │
│ │ Topic │ │
│ ┌──────────┐ │ ┌───┬───┬───┬───┐ │ │
│ │Publisher │─────────►│ │ A │ B │ C │ D │ │ │
│ └──────────┘ │ └───┴───┴───┴───┘ │ │
│ └─────────┬─────────┘ │
│ │ │
│ ┌───────────────────┼───────────────────┐ │
│ ▼ ▼ ▼ │
│ ┌───────────────────┐ ┌───────────────────┐ ┌───────────────────┐ │
│ │ Consumer Group 1 │ │ Consumer Group 2 │ │ Consumer Group 3 │ │
│ │ (Order Service) │ │ (Analytics) │ │ (Notification) │ │
│ ├───────────────────┤ ├───────────────────┤ ├───────────────────┤ │
│ │ ┌────┐ ┌────┐ │ │ ┌────┐ ┌────┐ │ │ ┌────┐ │ │
│ │ │C1-1│ │C1-2│ │ │ │C2-1│ │C2-2│ │ │ │C3-1│ │ │
│ │ │A,C │ │B,D │ │ │ │A,C │ │B,D │ │ │ │A,B,C,D│ │ │
│ │ └────┘ └────┘ │ │ └────┘ └────┘ │ │ └────┘ │ │
│ └───────────────────┘ └───────────────────┘ └───────────────────┘ │
│ │
│ 동작: │
│ - 각 그룹은 모든 메시지 수신 (Pub/Sub) │
│ - 그룹 내에서는 메시지 분산 (Point-to-Point) │
│ - 확장: 그룹 내 Consumer 추가 │
│ │
└─────────────────────────────────────────────────────────────────────────┘
패턴 비교¶
| 특성 | Queue (P2P) | Topic (Pub/Sub) | Consumer Group |
|---|---|---|---|
| 메시지 복사 | 1:1 | 1:N | 그룹당 1 |
| 부하 분산 | O | X | 그룹 내 O |
| 브로드캐스트 | X | O | 그룹간 O |
| 확장성 | Consumer 추가 | 제한적 | 유연함 |
4. 메시지 전달 보장¶
At-Most-Once (최대 한 번)¶
메시지가 유실될 수 있지만, 중복은 없습니다.
┌─────────────────────────────────────────────────────────────────────────┐
│ At-Most-Once │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────┐ ┌─────────┐ ┌──────────┐ │
│ │ Producer │ │ Queue │ │ Consumer │ │
│ └────┬─────┘ └────┬────┘ └────┬─────┘ │
│ │ │ │ │
│ │── Send(msg) ──►│ │ │
│ │ │── Deliver ───►│ │
│ │ │ X 처리 전 장애! │
│ │ │ │ │
│ │ │ (메시지 삭제) │ │
│ │ │ │ │
│ │ │ 재전송 없음 │ │
│ │ │ │ │
│ │
│ 구현: ACK 전에 메시지 삭제 │
│ │
│ 장점: │
│ - 중복 처리 불필요 │
│ - 가장 빠른 성능 │
│ │
│ 단점: │
│ - 메시지 유실 가능 │
│ │
│ 사용 사례: │
│ - 실시간 센서 데이터 (일부 유실 허용) │
│ - 로그 수집 (완전성보다 성능 중요) │
│ │
└─────────────────────────────────────────────────────────────────────────┘
At-Least-Once (최소 한 번)¶
메시지가 중복될 수 있지만, 유실은 없습니다.
┌─────────────────────────────────────────────────────────────────────────┐
│ At-Least-Once │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────┐ ┌─────────┐ ┌──────────┐ │
│ │ Producer │ │ Queue │ │ Consumer │ │
│ └────┬─────┘ └────┬────┘ └────┬─────┘ │
│ │ │ │ │
│ │── Send(msg) ──►│ │ │
│ │ │── Deliver ───►│ │
│ │ │ │ 처리 완료 │
│ │ │ X ACK 전 장애! │
│ │ │ │ │
│ │ │ (ACK 미수신) │ │
│ │ │ │ │
│ │ │── Redeliver ─►│ ← 재전송 (중복!) │
│ │ │◄── ACK ───────│ │
│ │ │ │ │
│ │
│ 구현: ACK 후에만 메시지 삭제 │
│ │
│ 장점: │
│ - 메시지 유실 없음 │
│ │
│ 단점: │
│ - 중복 처리 필요 (멱등성 필요) │
│ │
│ 사용 사례: │
│ - 결제 처리 (유실 불가, 멱등성 구현) │
│ - 주문 처리 │
│ - 이메일 발송 │
│ │
└─────────────────────────────────────────────────────────────────────────┘
Exactly-Once (정확히 한 번)¶
이론적으로 가장 이상적이지만, 구현이 복잡합니다.
┌─────────────────────────────────────────────────────────────────────────┐
│ Exactly-Once │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ 순수한 Exactly-Once는 분산 시스템에서 불가능! │
│ (Two Generals Problem) │
│ │
│ 실용적 구현: "Effectively Once" │
│ │
│ 방법 1: At-Least-Once + 멱등성 Consumer │
│ ┌──────────┐ ┌─────────┐ ┌──────────────────┐ │
│ │ Producer │────►│ Queue │────►│ Idempotent │ │
│ └──────────┘ └─────────┘ │ Consumer │ │
│ │ ┌──────────────┐ │ │
│ │ │Processed IDs │ │ │
│ │ │{id1, id2, ..}│ │ │
│ │ └──────────────┘ │ │
│ │ 이미 처리된 건 │ │
│ │ 무시 │ │
│ └──────────────────┘ │
│ │
│ 방법 2: 트랜잭션 기반 (Kafka Transactions) │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ Transaction │ │
│ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │
│ │ │ Read from │──│ Process │──│ Write to │ │ │
│ │ │ input topic │ │ │ │ output topic│ │ │
│ │ └─────────────┘ └─────────────┘ └─────────────┘ │ │
│ │ │ │
│ │ → 모두 성공 또는 모두 실패 │ │
│ └──────────────────────────────────────────────────────────┘ │
│ │
│ 사용 사례: │
│ - 금융 거래 │
│ - 재고 관리 │
│ - 스트림 처리 (Kafka Streams) │
│ │
└─────────────────────────────────────────────────────────────────────────┘
전달 보장 비교¶
| 보장 수준 | 유실 | 중복 | 성능 | 복잡도 |
|---|---|---|---|---|
| At-Most-Once | 가능 | 없음 | 최고 | 낮음 |
| At-Least-Once | 없음 | 가능 | 좋음 | 중간 |
| Exactly-Once | 없음 | 없음 | 낮음 | 높음 |
5. 멱등성 (Idempotency)¶
멱등성이란?¶
같은 연산을 여러 번 수행해도 결과가 동일한 성질입니다.
┌─────────────────────────────────────────────────────────────────────────┐
│ 멱등성 (Idempotency) │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ 멱등 연산: │
│ f(f(x)) = f(x) │
│ │
│ 예시: │
│ ┌────────────────────────────────────────────────────────────────┐ │
│ │ 연산 │ 멱등? │ 설명 │ │
│ ├────────────────────────────────────────────────────────────────┤ │
│ │ x = 5 │ O │ 여러 번 해도 x=5 │ │
│ │ DELETE /users/123 │ O │ 이미 삭제된 것 다시 삭제 │ │
│ │ PUT /users/123 {name:A} │ O │ 같은 값으로 덮어쓰기 │ │
│ ├────────────────────────────────────────────────────────────────┤ │
│ │ x = x + 1 │ X │ 할 때마다 증가 │ │
│ │ POST /orders │ X │ 호출마다 새 주문 생성 │ │
│ │ account.balance -= 100 │ X │ 호출마다 차감 │ │
│ └────────────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────┘
멱등성 구현 패턴¶
┌─────────────────────────────────────────────────────────────────────────┐
│ 멱등성 구현 방법 │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ 방법 1: Idempotency Key │
│ │
│ ┌──────────┐ ┌────────────────────────┐ │
│ │ Client │ │ Server │ │
│ └────┬─────┘ │ ┌──────────────────┐ │ │
│ │ │ │ Processed Keys │ │ │
│ │──POST /payment │ │ {key1, key2, ...}│ │ │
│ │ Idempotency-Key: abc123 │ └──────────────────┘ │ │
│ │ {amount: 100} │ │ │
│ │ │ 1. Check: abc123? │ │
│ │ │ 2. Not found → 처리 │ │
│ │ │ 3. Store abc123 │ │
│ │◄─ 200 OK ─────────────────────│ │ │
│ │ │ │ │
│ │──POST /payment (재시도) │ │ │
│ │ Idempotency-Key: abc123 │ │ │
│ │ {amount: 100} │ │ │
│ │ │ 1. Check: abc123? │ │
│ │ │ 2. Found → 기존 응답 │ │
│ │◄─ 200 OK (동일 응답) ─────────│ │ │
│ │ │ │ │
│ │
├─────────────────────────────────────────────────────────────────────────┤
│ 방법 2: 버전/조건부 업데이트 │
│ │
│ -- 비멱등적 UPDATE │
│ UPDATE accounts SET balance = balance - 100 WHERE id = 1; │
│ -- 실행할 때마다 100 감소 │
│ │
│ -- 멱등적 UPDATE (버전 사용) │
│ UPDATE accounts │
│ SET balance = balance - 100, version = 2 │
│ WHERE id = 1 AND version = 1; │
│ -- version이 1일 때만 실행 (한 번만 성공) │
│ │
├─────────────────────────────────────────────────────────────────────────┤
│ 방법 3: 절대값 설정 │
│ │
│ -- 비멱등적 │
│ INSERT INTO orders (user_id, amount) VALUES (1, 100); │
│ │
│ -- 멱등적 (UPSERT) │
│ INSERT INTO orders (order_id, user_id, amount) │
│ VALUES ('order-abc123', 1, 100) │
│ ON CONFLICT (order_id) DO NOTHING; │
│ │
└─────────────────────────────────────────────────────────────────────────┘
멱등성 Consumer 구현 예시¶
class IdempotentConsumer:
def __init__(self, redis_client, db):
self.redis = redis_client
self.db = db
def process_message(self, message):
message_id = message['id']
# 1. 이미 처리된 메시지인지 확인
if self.is_processed(message_id):
print(f"Message {message_id} already processed, skipping")
return
# 2. 비즈니스 로직 처리
try:
self.handle_business_logic(message)
# 3. 처리 완료 표시 (원자적으로)
self.mark_processed(message_id)
except Exception as e:
# 처리 실패 시 재시도 가능
raise
def is_processed(self, message_id):
# Redis SET 사용 (TTL 설정으로 메모리 관리)
return self.redis.sismember("processed_messages", message_id)
def mark_processed(self, message_id):
# 24시간 후 자동 삭제
self.redis.sadd("processed_messages", message_id)
self.redis.expire("processed_messages", 86400)
def handle_business_logic(self, message):
# 실제 비즈니스 로직
if message['type'] == 'payment':
self.process_payment(message['data'])
6. 메시지 큐 패턴¶
Work Queue (Task Queue)¶
작업을 여러 워커에게 분배합니다.
┌─────────────────────────────────────────────────────────────────────────┐
│ Work Queue Pattern │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────┐ │
│ │ Work Queue │ │
│ ┌──────────┐ │ ┌───┬───┬───┐ │ ┌──────────┐ │
│ │ Producer │───────►│ │T1 │T2 │T3 │ │────────►│ Worker 1 │ │
│ │ (Web) │ │ ├───┼───┼───┤ │ └──────────┘ │
│ └──────────┘ │ │T4 │T5 │T6 │ │ │
│ │ └───┴───┴───┘ │ ┌──────────┐ │
│ └─────────────────┘────────►│ Worker 2 │ │
│ └──────────┘ │
│ 사용 사례: ┌──────────┐ │
│ - 이미지 리사이징 ─────►│ Worker 3 │ │
│ - PDF 생성 └──────────┘ │
│ - 이메일 발송 │
│ │
└─────────────────────────────────────────────────────────────────────────┘
Request-Reply¶
비동기 요청-응답 패턴입니다.
┌─────────────────────────────────────────────────────────────────────────┐
│ Request-Reply Pattern │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────┐ ┌─────────────┐ ┌──────────┐ │
│ │ Requester│ │Request Queue│ │ Replier │ │
│ │ │ └─────────────┘ │ │ │
│ │ │ ┌─────────────┐ │ │ │
│ │ │ │Reply Queue │ │ │ │
│ └────┬─────┘ └──────┬──────┘ └────┬─────┘ │
│ │ │ │ │
│ │─Request(replyTo:Q1,correlationId:C1)─►│ │
│ │ │ │ │
│ │ │ │ 처리 │
│ │ │ │ │
│ │◄──Reply(correlationId:C1)──────────│ │
│ │ │ │ │
│ │
│ 메시지 구조: │
│ Request: { │
│ correlationId: "req-123", │
│ replyTo: "reply-queue-A", │
│ body: { ... } │
│ } │
│ │
│ Reply: { │
│ correlationId: "req-123", // 요청과 응답 매칭 │
│ body: { ... } │
│ } │
│ │
└─────────────────────────────────────────────────────────────────────────┘
Dead Letter Queue (DLQ)¶
처리 실패한 메시지를 보관합니다.
┌─────────────────────────────────────────────────────────────────────────┐
│ Dead Letter Queue │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────┐ │
│ ┌──────────┐ │ Main Queue │ ┌──────────┐ │
│ │ Producer │───────►│ ┌───┬───┬───┐ │────────►│ Consumer │ │
│ └──────────┘ │ │ A │ B │ C │ │ └────┬─────┘ │
│ │ └───┴───┴───┘ │ │ │
│ └────────┬────────┘ │ │
│ │ │ │
│ │ 처리 실패 │ │
│ │ (재시도 초과) │ │
│ ▼ ▼ │
│ ┌─────────────────┐ 실패! (B 메시지) │
│ │ Dead Letter Q │ │ │
│ │ ┌───┐ │◄─────────────┘ │
│ │ │ B │ │ │
│ │ └───┘ │ │
│ └────────┬────────┘ │
│ │ │
│ ▼ │
│ 수동 검토 / 재처리 │
│ │
│ DLQ 활용: │
│ - 실패 원인 분석 │
│ - 수동 재처리 │
│ - 알림/모니터링 │
│ │
└─────────────────────────────────────────────────────────────────────────┘
Priority Queue¶
우선순위에 따라 메시지를 처리합니다.
┌─────────────────────────────────────────────────────────────────────────┐
│ Priority Queue │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────┐ ┌─────────────────────┐ ┌──────────┐ │
│ │ Producer │ │ Priority Queue │ │ Consumer │ │
│ └────┬─────┘ │ │ └────┬─────┘ │
│ │ │ High ┌───┬───┐ │ │ │
│ │──(P:High)─│───────►│ A │ D │ │──────────│ │
│ │ │ └───┴───┘ │ │ │
│ │──(P:Med)──│ Medium ┌───┬───┐ │ │ │
│ │ │───────►│ B │ │ │ │ │
│ │ │ └───┴───┘ │ │ │
│ │──(P:Low)──│ Low ┌───┬───┐ │ │ │
│ │ │───────►│ C │ E │ │ │ │
│ │ │ └───┴───┘ │ │ │
│ │ └─────────────────────┘ │ │
│ │ │ │
│ │ 처리 순서: A → D → B → C → E │ │
│ │
│ 구현 방법: │
│ 1. 우선순위별 별도 큐 + 가중치 폴링 │
│ 2. 단일 큐 + 힙 정렬 │
│ 3. RabbitMQ: x-max-priority 설정 │
│ │
└─────────────────────────────────────────────────────────────────────────┘
7. 연습 문제¶
연습 1: 통신 방식 선택¶
다음 시나리오에서 동기/비동기 중 적절한 방식을 선택하세요:
- 사용자 로그인 인증
- 주문 후 확인 이메일 발송
- 결제 승인 요청
- 로그 수집
- 실시간 채팅 메시지
연습 2: 전달 보장 선택¶
다음 사용 사례에 적합한 전달 보장 수준을 선택하세요:
- IoT 센서 온도 데이터
- 은행 송금 요청
- 뉴스 피드 업데이트
- 주문 생성 이벤트
- 게임 플레이어 위치 업데이트
연습 3: 멱등성 설계¶
다음 연산을 멱등하게 만드는 방법을 설계하세요:
- 계좌에서 100원 출금
- 상품 재고 1개 감소
- 이메일 발송
- 포인트 적립
다음 단계¶
12_Message_System_Comparison.md에서 Kafka, RabbitMQ, AWS SQS/SNS 등 주요 메시지 시스템을 비교해봅시다!
참고 자료¶
- "Enterprise Integration Patterns" - Gregor Hohpe, Bobby Woolf
- RabbitMQ Official Documentation
- Apache Kafka Documentation
- AWS Messaging Services
- "Designing Data-Intensive Applications" - Martin Kleppmann