지금껏 카프카를 단순 비동기 워커처럼 써왔던 입장으로써, 대략적인 개념이나 동작방식은 이해하고 있더라도 그 이상 깊이 가려하면 이전에 학습했던 지식들이 꼬여서 매번 헷갈린다.
- 카프카는 큐인가 로그인가?
- 컨슈머 그룹 내에서 메시지는 어떻게 처리되는가?
- 파티션 수와 성능은 항상 비례하는가?
- 타 메시지큐(이를테면 RabbitMQ)와의 근본적인 차이점은 무엇인가?
이번 글에선 단순 암기보단 동작 방식에 초점을 맞춰 카프카란 친구를 조금 더 이해해보고자 한다.
카프카란?

Apache Kafka is an open-source, distributed event streaming platform used for high-performance data pipelines, streaming analytics, and data integration
카프카는 분산 이벤트 스트리밍 플랫폼이다.
조금 실무적으로 풀어 얘기하자면, 서비스에서 발생한 이벤트를 append-only 로그에 계속 쌓아두고 해당 이벤트가 필요한 소비자가 각각 읽어가는 시스템이다.
타 메시지큐와 비교해 카프카의 핵심은, 이벤트를 로그에 기록하고 offset을 통해 읽어간다는 것이다.
이 말은 즉, 메시지가 소비 후 사라지지 않고 offset 조정을 통해 메시지를 다시 읽을 수 있음을 의미한다.
또한, append-only + offset의 조합은 카프카에 저장된 이벤트를 읽고 쓸 때 순차 disk I/O를 가능하게 해 메시지 처리량을 높인다.
카프카의 핵심 원리
카프카가 동작하는 핵심적인 원리는 생각보다 단순하다.
- Producer가 메시지를 Topic으로 보낸다.
- Broker가 Partition 로그 끝에 메시지를 append한다.
- Consumer는 자신이 가진 offset부터 순차적으로 메시지를 읽는다.
- 메시지는 소비 후 즉시 삭제되지 않고, retention 정책에 의해 얼마동안 유지된다.
다시 한 번 말하지만, 여기서 핵심은 "메시지 소비 후 삭제"가 아니라, 메시지를 "어디까지 읽었는지 기록하는 방식"이다.
이런 까닭에 재처리가 가능하고, 다중 소비자를 처리할 수 있는 것이다.
주요 개념 정리
카프카는 시스템을 구축하는 부품들이 꽤 많은데, 얘네들을 구분하는게 매번 헷갈린다.
한 판으로 정리를 해보자.
1) Topic (토픽)
이벤트를 분류하는 가장 큰 단위이다. 서비스에서 발행하는 이벤트 혹은 메시지를 토픽으로 발행한다고 표현한다. (ex. order.created, payment.failed, ...)
2) Partition (파티션)
Topic을 나눈 물리 단위이다. 카프카의 병렬 처리 시스템의 핵심이다.
파티션과 관련해 인지하고 있어야할 부분 중 하나는 파티션 내에서 토픽을 처리하는 순서이다.
- Topic 전체가 아닌 파티션 내부에서 순서 처리가 보장된다.
- 동일한 Key(파티션 키라고도 부른다)를 주면 동일한 Partition으로의 토픽 발행이 보장된다.
3) Offset (오프셋)
파티션 로그에서 레코드 위치를 나타내는 번호이다. 컨슈머는 Offset을 통해 "내가 어디까지 읽었는지"를 추적한다.
4) Consumer Group (컨슈머 그룹)
동일한 역할을 하는 컨슈머를 동일한 group id를 통해 하나의 그룹으로 묶을 수 있다.
동일 컨슈머 그룹 내부에서는 하나의 파티션을 하나의 컨슈머만 소비한다. 즉, 오프셋을 개인 컨슈머가 아닌 컨슈머 그룹 단위로 관리한다.
또한, 서로 다른 그룹은 동일한 메시지를 독립적으로 다시 소비할 수 있다.
위 두 가지 특징은 아래를 가능하게 한다.
- 순서 보장이 용이해진다.
- 동일한 메시지를 동시에 다르게 처리하는 것이 가능해진다.
- 주문 성공 메시지를 A 컨슈머 그룹에서 소비해 알림 프로세스를 수행하고, 동시에 B 컨슈머 그룹에서 소비해 주문 이력 적재 프로세스를 수행할 수 있다.
동시에 주의할 점도 있다.
컨슈머 그룹 내에서 컨슈마 하나가 파티션 하나를 맡는 구조이다보니, 파티션의 개수가 병렬 처리의 상한선이 된다.
즉, 파티션 개수가 2개인데 컨슈머 그룹이 총 5개의 컨슈머로 이루어져있다면 3개의 컨슈머는 놀게 된다.
5) Replication, Leader, Follower
카프카는 고가용성을 위해 파티션을 복제한다.
Leader 파티션은 실제 읽기와 쓰기를 처리하는 파티션이고, Follower는 Leader를 복제하는 파티션이다.
만약 Leader 파티션에 장애가 발생하면 Follower로 Failover 처리하여 고가용성을 유지한다.
6) Retention, Compaction
카프카가 데이터를 보관하는 방식을 일컫는다.
Retention을 시간 혹은 용량을 기준으로 데이터를 삭제하는 방식을 말하며, Compaction은 동일 Key의 최신 값을 남기는 정리 방식이다.
일반적으로 메시지의 전체 히스토리를 관리해야한다면 Retention을, 최신 상태가 중요한 메시지의 경우엔 Compaction을 사용해 데이터를 주기적으로 cleanup한다.
자주 헷갈리는 포인트
1) 파티션만 늘리면 성능도 계속 오른다?
파티션은 작업 병렬도를 올려주지만, 운영 복잡도를 함께 올린다.
파티션이 많아질수록 리밸런싱 비용, 메타데이터 관리 비용, 장애 복구 시간이 함께 커진다.
또한, 파티션은 늘리는 것이 가능하지만 한 번 늘어난 후엔 줄일 수 없으므로 무지성 증설은 안된다.
2) 컨슈머 그룹을 설정한 메시지는 무조건 1회 소비가 보장된다?
컨슈머 그룹 내부 기준으로는 맞는 말이다.
하지만 시스템 전체 기준으로 봤을 때, 그룹이 여러 개면 동일한 메시지가 여러 번 소비된다.
3) exactly-once는 카프카 기본 설정만으로 가능하다?
그렇지 않다. Producer의 Idempotence, Transaction, 소비 후 처리, 발행까지의 설계를 모두 고려해야한다. 데브원영님의 좋은 글
4) 다른 큐, 대표적으로 RabbitMQ와는 어떻게 다른가?
두 개의 큐는 철학이 다르다.
Kafka는 이벤트를 로그에 쌓아두고 필요할 때 읽을 수 있는 이벤트 스트리밍 플랫폼이며, RabbitMQ는 메시지를 라우팅해 워커가 처리하도록 하는 메시지 브로커이다.
Kafka는 어떤 Consumer가 어떤 메시지를 읽어야하는지에는 관심이 없지만, RabbitMQ는 메시지 라우팅 키를 통한 메시지 라우팅을 지원한다.

조금 간단히 말하자면, RabbitMQ는 Kafka가 지향하는 분산 환경에서의 높은 처리량보다는 지정된 수신인에게 원하는 방식으로 신뢰성 높은 메시지를 전달하는 것에 더 초점이 맞춰져있다.
개념적 측면에서는 그렇고, 실무 관점에서의 가장 큰 차이점은 "RabbitMQ는 메시지 소비에 대한 ack를 수신하면 메시지를 큐에서 삭제한다"는 것이다.
이는 RabbitMQ가 전통적인 MessageQueue를 구현하고 있기 때문에 그런 것인데, 이런 특징 탓에 Kafka와 비교해 재처리 및 병렬 처리 작업을 설계하기 까다로운 측면이 있다.
Kafka가 유리한 경우
- 이벤트를 여러 시스템에서 재사용해야함
- 재처리 작업이 중요함
- 로그 / CDC / 분석 등의 파이프라인 작업이 필요함
- 대규모 트래픽 대응과 분산 환경 처리 시스템이 요구됨
RabbitMQ가 유리한 경우
- 작업 큐, 비동기 업무 처리, 요청-응답 패턴 중심
- 커스텀한 라우팅 규칙이 필수적인 작업
- 빠르고 간단한 구축 및 운영이 요구됨
- 장기적인 메시지 보관이 필요없고, 재처리에 대한 요구가 크지 않음