본문으로 건너뛰기
김신건의 로그

[Distributed] Message Broker 비교: Kafka / RabbitMQ / NATS / SQS / Redis Streams

· 수정 · 📖 약 3분 · 1,143자/단어 #message-broker #kafka #rabbitmq #nats #sqs #comparison #distributed
message broker comparison, Kafka vs RabbitMQ, broker selection, 메시지 브로커 비교, ActiveMQ, NATS JetStream

정의

Message Broker = 생산자(Producer)와 소비자(Consumer) 사이에서 메시지를 중계하는 미들웨어. 비동기 통신, 부하 분산, 시스템 디커플링의 핵심.

결정 트리

flowchart TD
    Q1{"사용 패턴"}
    Q1 -->|"event log + replay"| Kafka[Kafka]
    Q1 -->|"복잡 라우팅 + task queue"| Rabbit[RabbitMQ]
    Q1 -->|"마이크로서비스 가벼움"| NATS[NATS]
    Q1 -->|"AWS managed + 단순 큐"| SQS[SQS]
    Q1 -->|"Redis 위 fan-out / 짧은 큐"| RedisS[Redis Streams]
    Q1 -->|"레거시 JMS / 엔터프라이즈"| AMQ[ActiveMQ]
    Q1 -->|"클라우드 native pub-sub"| GCP["Google Pub/Sub"]

6가지 broker 매트릭스

항목KafkaRabbitMQNATSSQSRedis StreamsActiveMQ
모델logexchange-queuesubject pub-subqueuelogqueue/topic
영속항상옵션옵션 (JS)항상옵션항상
Throughput수백만/s수만/s수백만/s거의 무한수십만/s수만/s
Latency중간 (ms)낮음마이크로초수십 ms낮음낮음
운영 복잡도높음중간낮음없음낮음중간
라우팅partition by keyexchange 패턴subject 계층FIFO/standardconsumer grouptopic/queue
Re-play자유 (offset)한 번만JS 가능DLQ만가능 (XREAD)제한적
학습 곡선높음중간낮음낮음낮음중간
프로토콜자체AMQP 0-9-1NATSHTTP/SQSRESPAMQP/OpenWire

브로커별 아키텍처

Kafka: Log 모델

flowchart LR
    P1[Producer 1] --> T["Topic: orders\n(6 partitions)"]
    P2[Producer 2] --> T
    T --> P0["Partition 0\noffset 0,1,2..."]
    T --> P1b["Partition 1\noffset 0,1,2..."]
    T --> P2b["Partition 2\noffset 0,1,2..."]
    P0 --> CG1["Consumer Group A\nConsumer 1"]
    P1b --> CG1
    P2b --> CG2["Consumer Group B\nConsumer 1"]
    P0 --> CG2
  • 메시지는 삭제되지 않음 (retention 기간 동안)
  • 여러 Consumer Group이 독립적으로 같은 topic 소비
  • offset으로 임의 시점 replay 가능

RabbitMQ: Exchange-Queue 모델

flowchart LR
    P[Producer] --> EX["Exchange\n(direct/fanout/topic/headers)"]
    EX -->|"routing key: order.created"| Q1["Queue: order-processor"]
    EX -->|"routing key: order.*"| Q2["Queue: audit-log"]
    EX -->|"fanout"| Q3["Queue: notification"]
    Q1 --> C1[Consumer 1]
    Q2 --> C2[Consumer 2]
    Q3 --> C3[Consumer 3]
  • Exchange 타입: direct (정확 매칭), fanout (브로드캐스트), topic (패턴), headers
  • 메시지는 소비 후 삭제 (기본)
  • 복잡한 라우팅 로직을 브로커가 처리

처리량 / 지연 / 운영비용 (직관)

Broker 처리량 vs 지연 (가상 직관)
NATS = 지연 최저. Kafka = 처리량 최고. SQS = 무한 확장이지만 지연 큼.

ActiveMQ 상세

ActiveMQ (Apache)는 JMS(Java Message Service) 표준을 구현한 전통적인 엔터프라이즈 메시지 브로커.

항목ActiveMQ ClassicActiveMQ Artemis
프로토콜OpenWire, AMQP, STOMP, MQTTAMQP, STOMP, MQTT, OpenWire
성능중간Classic보다 높음
아키텍처단일 브로커고성능 비동기 코어
권장레거시 유지신규 프로젝트
<!-- Spring Boot + ActiveMQ Artemis -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-artemis</artifactId>
</dependency>
spring:
  artemis:
    mode: native
    host: localhost
    port: 61616
    user: admin
    password: admin

IMPORTANT

ActiveMQ는 JMS 기반 레거시 시스템 통합에 적합. 신규 마이크로서비스 아키텍처에서는 Kafka (이벤트 스트리밍) 또는 NATS (경량 pub-sub)를 권장.

시나리오별 추천

시나리오추천이유
Event sourcing (큰 로그)Kafkaretention + replay
마이크로서비스 commandsNATS 또는 RabbitMQ낮은 지연, 라우팅
AWS Lambda + 큐SQSmanaged, Lambda trigger
Sidekiq 같은 Ruby job queueRedis (list 기반)단순, 빠름
실시간 채팅 fan-outNATS 또는 Redis Pub/Sub마이크로초 지연
CDC (DB → search)Kafka + Debeziumlog 기반 변경 감지
트래픽 spike 자동 흡수SQS (managed)무한 확장
빠른 MVP / startupRedis Streams이미 Redis 쓰면 추가 비용 없음
레거시 JMS 통합ActiveMQJMS 표준 준수
복잡한 라우팅 규칙RabbitMQexchange 패턴

메시지 보장 비교

BrokerAt-most-onceAt-least-onceExactly-once
Kafka옵션기본EOS 가능
RabbitMQ옵션persistent + ack외부 idempotency 필요
NATS Core기본--
NATS JS-기본옵션
SQS-기본FIFO + 5분 dedup
Redis Streams-XACK로외부 idempotency
ActiveMQ옵션persistent + ackXA 트랜잭션

IMPORTANT

Exactly-once는 broker 내부에서만 의미 있음. *외부 시스템 (DB, API)*까지 완벽한 exactly-once는 불가능. idempotency + outbox가 현실적 정답. 자세한 건 outbox-pattern, idempotency-keys.

영속 / 재처리 비교

flowchart TD
    Kafka["Kafka\ndays~weeks retention\n임의 offset replay"]
    Rabbit["RabbitMQ\nqueue 안의 메시지\n소비 = 사라짐"]
    Nats["NATS JS\nretention 정책\n임의 시점 replay"]
    Sqs["SQS\n최대 14일\n한 번 소비 = 사라짐"]
    Stream["Redis Streams\nMAXLEN만큼\n임의 offset"]
    AMQ["ActiveMQ\nKahaDB / journal\n재처리 제한적"]

마이그레이션 비용

출발도착비용
Sidekiq (Redis)Kafka큼 (consumer group, exactly-once 재설계)
RabbitMQKafka중간 (라우팅 → topic 재설계)
KafkaNATS작음 (둘 다 log)
ActiveMQRabbitMQ작음 (둘 다 AMQP)
ActiveMQKafka큼 (JMS → Kafka API 전면 교체)
자체 호스팅Managed작음 (운영 측면 큰 이득)

운영자 시점 체크리스트

체크 항목                          관련 설정
----------------------------------------------
메시지 손실 허용?              acks, persistent, ack 정책
순서 보장 필요?                partition key, FIFO
재처리 가능?                   offset / position
DLQ + parking lot             실패 메시지 격리
Backpressure                  prefetch, max-in-flight
Monitoring                    lag, dead messages, throughput
Consumer auto-scaling         lag 기반 (KEDA)
Schema registry               Avro/Protobuf 스키마 진화

Dead Letter Queue (DLQ) 패턴

처리 실패 메시지를 격리해 재처리하거나 분석하는 패턴.

flowchart LR
    P[Producer] --> Q["Main Queue / Topic"]
    Q --> C[Consumer]
    C -->|"처리 실패 (N회)"| DLQ["Dead Letter Queue"]
    DLQ --> Alert["알림 / 모니터링"]
    DLQ --> Replay["수동 재처리"]
BrokerDLQ 지원
Kafka별도 topic 수동 구현 또는 Kafka Streams
RabbitMQx-dead-letter-exchange 설정
SQS자동 DLQ 연결 (maxReceiveCount 설정)
NATS JSMaxDeliver 초과 시 별도 subject
# SQS DLQ 설정 예시 (AWS CDK)
const dlq = new sqs.Queue(this, 'DLQ');
const mainQueue = new sqs.Queue(this, 'MainQueue', {
  deadLetterQueue: {
    queue: dlq,
    maxReceiveCount: 3,   # 3회 실패 후 DLQ로
  },
});

Schema Registry와 메시지 진화

Kafka 등에서 메시지 스키마를 중앙 관리:

flowchart LR
    P[Producer] -->|"Avro/Protobuf 직렬화"| SR["Schema Registry"]
    SR -->|"schema_id 포함"| K[(Kafka)]
    K --> C[Consumer]
    C -->|"schema_id로 역직렬화"| SR
  • Confluent Schema Registry: Kafka 생태계 표준
  • AWS Glue Schema Registry: AWS 관리형
  • 스키마 진화 규칙: backward / forward / full compatibility

흔한 함정

WARNING

  1. Kafka를 단순 큐로 쓰기: Kafka는 log 기반. 단순 task queue라면 RabbitMQ나 SQS가 더 적합.
  2. RabbitMQ에서 replay 기대: 소비된 메시지는 사라짐. replay가 필요하면 Kafka.
  3. NATS Core에서 영속성 기대: NATS Core는 fire-and-forget. 영속성이 필요하면 NATS JetStream.
  4. partition 수 부족: Kafka에서 consumer 수 > partition 수면 일부 consumer idle. 처음부터 충분히 설정.
  5. 메시지 크기 과대: Kafka 기본 최대 1MB. 큰 payload는 S3에 저장 후 reference만 전송.
  6. DLQ 모니터링 없음: DLQ에 메시지가 쌓여도 알림 없으면 데이터 손실 인지 불가.

관련 위키

이 글의 용어 (8개)
[AWS] SQS: managed queue, FIFO, DLQcloud
정의 SQS (Simple Queue Service) = AWS 의 완전 관리형 메시지 큐. infinite scale, no provisioning, pay-per-reques…
[Distributed] Kafka Consumer Group: rebalancing, offset, lagdistributed-systems
정의 Consumer Group = 같은 를 가진 consumer들이 함께 한 topic을 분담 소비. partition 단위로 분배. 핵심 특성: - 한 partition → …
[Distributed] Kafka: 분산 로그, partition, consumer groupdistributed-systems
정의 Apache Kafka = 분산 commit log. 고처리량 (수백만 msg/s), 영속, 수평 확장. event-driven 아키텍처 의 de facto. 핵심 개념: …
[Distributed] NATS: 가벼움, JetStream, subject 라우팅distributed-systems
정의 NATS = 극도로 가벼운 메시징 시스템. core NATS = at-most-once Pub/Sub + request-reply. JetStream = 영속 / at-le…
[Distributed] RabbitMQ: exchange, queue, routing keydistributed-systems
정의 RabbitMQ = AMQP 0.9.1 기반 traditional message broker. exchange → queue 라우팅, workload distribution…
[Pattern] Idempotency Keys: 중복 요청 안전 처리distributed-systems
정의 Idempotency = 같은 요청을 N번 보내도 결과가 1번과 동일. 분산 시스템 / 결제 / API 의 안전망. [!IMPORTANT] 네트워크는 항상 timeout /…
[Pattern] Outbox Pattern: DB + 메시지의 원자성distributed-systems
정의 Outbox Pattern = DB 변경 + 메시지 발행 의 원자성 보장. 이중 쓰기 (dual write) 문제 의 표준 해결. 문제: Dual Write | 시나리오 |…
[Redis] Pub/Sub vs Streams: 휘발 신호 vs 영속 로그database-internals
정의 - Pub/Sub ( / ): 지금 듣고 있는 구독자 에게만 메시지가 전달되는 휘발성 신호. 영속 없음, ACK 없음. fan-out. - Streams ( / / / ):…

💬 댓글

사이트 검색 / 명령어

검색

스크롤 = 확대/축소 · 드래그 = 이동 · 0 = 원래 크기 · ESC = 닫기