큐라고 다 같은 큐가 아니다 — Kafka · SQS · RabbitMQ · Cloudflare Queues 지형도
큐라고 다 같은 큐가 아니다
— Kafka · SQS · RabbitMQ · Cloudflare Queues 지형도
지난 글에서 "큐 패턴"으로 백엔드를 다시 짰다. 그런데 그 '큐'는 한 종류가 아니다. "왜 Kafka 안 썼어요?"라는 질문에서 시작한, 메시지 시스템 지형도 정리.
들어가며: "왜 Kafka 안 썼어요?"
지난 글에서 3분 걸리는 AI 호출을 백그라운드로 빼면서 큐 패턴을 도입한 이야기를 썼어요. Cloudflare Queues를 썼다고 했더니 돌아온 질문이 이거였습니다. "큐면 Kafka 아니에요? 왜 Kafka 안 썼어요?"
이 질문에는 흔한 오해가 하나 숨어 있어요. "큐 = Kafka"라는 등식. 사실 Kafka는 엄밀히 말하면 큐가 아니고, 시중의 메시지 시스템들은 생긴 건 비슷해 보여도 동작 모델이 꽤 다릅니다. 그래서 이번 글에서는 대표적인 네 가지 — Kafka, AWS SQS, RabbitMQ, Cloudflare Queues — 를 한 지도 위에 놓고 비교해보려 해요.
가장 중요한 한 갈래: 큐 vs 로그
다른 건 다 잊어도 이것만 기억하면 절반은 끝나요. 메시지 시스템은 크게 두 갈래입니다.
메시지 큐 (Queue)
메시지가 줄 서 있고, 소비자가 하나 꺼내서(ack) 처리하면 그 메시지는 사라집니다. 여러 소비자가 붙으면 일을 나눠 가져가요. 핵심 용도는 작업 분배(work distribution). "이 일 누가 하나 처리해줘"에 어울립니다. SQS · RabbitMQ · Cloudflare Queues가 여기 속해요.
이벤트 로그 (Log)
메시지가 append-only 로그에 차곡차곡 쌓이고, 읽어도 사라지지 않습니다. 각 소비자(그룹)는 자기 오프셋(offset)을 들고 "내가 어디까지 읽었나"를 기억하며 읽어요. 그래서 같은 데이터를 여러 소비자가 각자 독립적으로 읽을 수 있고, 과거 시점부터 재생(replay)도 됩니다. Kafka가 대표주자예요.
4개 시스템, 한 장 요약
Apache Kafka
분산 이벤트 로그
append-only 로그를 파티션으로 쪼개 초고처리량을 낸다. 오프셋 기반이라 재생·이벤트소싱·스트림 처리에 강하다. 대신 클러스터(브로커·코디네이션)를 운영해야 한다.
강점: 처리량 · 재생 · 다중 소비AWS SQS
완전 관리형 메시지 큐
AWS가 다 굴려주는 큐. 서버가 없다. Standard(순서 미보장·초고처리량)와 FIFO(순서·정확히 한 번) 두 종류. AWS 생태계 안이면 가장 손이 덜 간다.
강점: 무운영 · AWS 통합RabbitMQ
메시지 브로커 (AMQP)
익스체인지·라우팅 키로 복잡한 분배(fanout·topic·우선순위)를 정교하게 짠다. 라우팅 유연성이 최고. 대신 인스턴스를 직접(또는 매니지드로) 운영한다.
강점: 라우팅 유연성Cloudflare Queues
서버리스 메시지 큐
Workers에 바인딩 한 줄로 붙는 서버리스 큐. 토큰·엔드포인트 없이 env.JOBS.send()로 끝. 처리량 상한은 위 셋보다 낮지만 작은 트래픽엔 압도적으로 간편하다.
비교 표
같은 축으로 나란히 놓으면 성격 차이가 분명해져요. (숫자는 대략적 체감 — 버전·설정·플랜에 따라 달라집니다.)
| 축 | Kafka | SQS | RabbitMQ | CF Queues |
|---|---|---|---|---|
| 모델 | 이벤트 로그 | 메시지 큐 | 메시지 브로커 | 메시지 큐 |
| 운영 방식 | self-host / 매니지드(MSK·Confluent) | 완전 관리형 | self-host / 매니지드(CloudAMQP) | 완전 관리형(서버리스) |
| 처리량 | 매우 높음 (수십만~수백만/s) | 높음 (사실상 무제한, Standard) | 중~높음 (수만~십만/s) | 중 (작은~중간 트래픽 대상) |
| 순서 보장 | 파티션 내 보장 | Standard 미보장 / FIFO 보장 | 큐 내 대체로 보장 | 대체로 보장(배치 단위) |
| 재시도 / DLQ | 소비자가 오프셋 직접 관리 | visibility timeout + DLQ | ack/nack + DLX | retry() + DLQ 내장 |
| 메시지 보존 | 기간/크기 기준 유지 (재생 O) | 소비 시 삭제 (최대 14일) | 소비 시 삭제 | 소비 시 삭제 |
| 지연 | 낮음 (ms) | 낮음~중 | 매우 낮음 | 낮음~중 |
| 비용 성격 | 인프라 + 운영비 큼 | 요청 수 기준 과금 | 인스턴스 비용 | operation 기준, 저렴 |
| 러닝 커브 | 가파름 | 완만 | 중간 | 완만 |
언제 뭘 쓰나
질문 몇 개만 따라가면 대부분 답이 나와요.
- 여러 시스템이 같은 이벤트를 각자 소비 / 재생 / 이벤트 소싱 / 초고처리량 스트림 → Kafka
- 복잡한 라우팅(fanout·topic·우선순위) 또는 온프레미스 → RabbitMQ
- 단순 작업 큐 + AWS 생태계 → SQS
- 단순 작업 큐 + Cloudflare/서버리스 + 작은 트래픽 → Cloudflare Queues
그래서 나는 왜 Cloudflare Queues였나
지난 글의 요구사항을 이 지도 위에 올려보면 답이 거의 자동으로 나와요.
- 작업은 "한 번 처리하면 끝". AI 호출 결과를 만들고 저장하면 그 잡은 종료돼요. 같은 이벤트를 여러 소비자가 듣거나, 과거를 재생할 일이 없습니다. → 로그(Kafka)가 필요 없음.
- 라우팅은 단순. 잡 하나가 들어오면 컨슈머 하나가 처리. fanout·우선순위·토픽 라우팅이 없어요. → RabbitMQ의 강점이 안 쓰임.
- 나는 1인 개발자. 브로커 클러스터를 굴리거나 인스턴스를 운영할 여력이 없어요. 운영 부담 = 그대로 내 시간.
- 이미 Cloudflare에 다 모아뒀음. D1·R2·Workers가 한 곳에 있고, 큐도
env.JOBS.send()한 줄로 붙어요. 외부 토큰·엔드포인트·인증이 없습니다. - 트래픽이 작음. 출시 검증 단계라 처리량 상한이 병목이 될 일이 없어요. Kafka의 초고처리량은 지금 나에게 오버킬.
물론 조건이 바뀌면 답도 바뀌어요. 나중에 "분석 파이프라인이 같은 이벤트를 따로 소비"하거나 "사용자 행동 로그를 재생해 다시 처리"할 일이 생기면, 그때는 로그 계열을 진지하게 볼 거예요. 도구는 문제를 따라가는 거니까.
마무리: 큐는 도구지 목표가 아니다
"왜 Kafka 안 썼어요?"에 대한 가장 정직한 답은 "내 문제가 Kafka를 필요로 하지 않아서"예요. 메시지 시스템 선택에서 제일 흔한 실수는, 제일 강력해 보이는 걸 먼저 고르고 거기에 문제를 끼워 맞추는 거더라고요.
순서는 반대여야 합니다. 먼저 묻기 — 내 문제가 작업 분배인가 이벤트 재생인가? 그다음 — 운영을 누가 감당하나? 이 두 질문이면 네 후보 중 어디로 갈지 거의 정해져요. 화려한 스펙표는 그다음입니다.