티스토리 뷰

이전글: 2025.05.02 - [기술노트/Apach Kafka] - Kafka 기초3 - 컨슈머

이번 글에서는 여러 컨슈머가 협력하여 데이터를 병렬적으로 처리하는 강력한 기능인 컨슈머 그룹(Consumer Group) 에 대해 심도 있게 다뤄보겠다.

 

컨슈머 그룹(Consumer Group)이란?

그림1. 다수의 컨슈머가 하나의 논리적 그룹을 형성하여, 토픽의 파티션들로부터 데이터를 분담하여 소비하는 구조



카프카에서 컨슈머 그룹(Consumer Group) 이란 여러 컨슈머가 하나의 논리적인 그룹으로 묶여,
특정 토픽의 데이터를 분담해서 읽어오는 구조
를 말한다.

 

컨슈머 그룹을 사용하면 메시지 처리량을 확장하고, 시스템 장애 발생 시에도 안정적으로 데이터를 소비할 수 있다.

 

컨슈머 그룹의 가장 중요한 특징은 같은 그룹 내의 컨슈머들은 동일한 파티션의 데이터를 중복으로 소비하지 않는다는 점이다. 즉, 하나의 파티션은 해당 컨슈머 그룹 내에서 단 하나의 컨슈머에게만 할당된다.이를 통해 특정 파티션의 메시지는 그룹 내에서 정확히 한 번만 처리되도록 보장하여 작업의 중복을 피하고 효율성을 높인다.

 

예를 들어, 5개의 파티션으로 구성된 토픽이 있고, 이 토픽을 소비하는 컨슈머 그룹에 3명의 컨슈머가 있다고 가정해보자. 이 경우 파티션은 다음과 같이 분배될 수 있다:

  • 컨슈머 1: 파티션 0, 파티션 1 할당
  • 컨슈머 2: 파티션 2, 파티션 3 할당
  • 컨슈머 3: 파티션 4 할당

만약 그룹 내 컨슈머 수에 변동이 생기거나 (새 컨슈머 추가, 기존 컨슈머 이탈), 토픽의 파티션 구성이 변경되면 리밸런싱(Rebalancing) 과정을 통해 파티션 소유권이 재조정된다. 이 과정은 카프카의 그룹 코디네이터에 의해 자동으로 관리된다.

 

그룹 코디네이터(Group Coordinator)

 

카프카의 브로커 중 하나가 특정 컨슈머 그룹의 관리 역할을 맡게 되는데, 이 브로커를 해당 그룹의 그룹 코디네이터 라고 한다.

 

컨슈머그룹 하나 당 하나의 코디네이터 브로커가 지정되며,

코디네이터는 해당 그룹의 멤버십 관리, 파티션할당, 리밸런싱, 오프셋 관리를 담당한다.

역할 설명
그룹 멤버 관리 어떤 Consumer들이 그룹에 소속돼 있는지 관리
파티션 할당 각 파티션을 어떤 Consumer에게 할당할지 결정
리밸런싱 트리거 구성 변화(Consumer 추가/제거, 세션 만료) 발생 시 파티션 재분배 수행
오프셋 관리 컨슈머가 커밋한 오프셋(consume 위치)을 관리 (__consumer_offsets 토픽에 저장됨)

 

 

컨슈머 수와 파티션 수의 관계

 

컨슈머 그룹의 병렬 처리 능력은 그룹 내 컨슈머 수와 토픽의 파티션 수에 직접적인 관련이 있다.

그림2. 컨슈머와 파티션 수의 관계

  • 컨슈머 수 ≤ 파티션 수: 이 경우, 각 컨슈머는 하나 이상의 파티션에 할당되어 작업을 수행한다.
    만약 컨슈머 수와 파티션 수가 같다면, 각 컨슈머는 정확히 하나의 파티션을 담당하여 이상적인 병렬 처리가 가능하다.
  • 컨슈머 수 > 파티션 수: 이 경우, 파티션 수만큼의 컨슈머만 활성화되어 파티션을 할당받고, 파티션 수를 초과하는 컨슈머들은 어떠한 파티션도 할당받지 못한 채 비활성화(대기 상태) 된다. 이들은 메시지를 읽는 역할을 하지 않으며, 그룹 내 다른 컨슈머에 장애가 발생했을 때 대체 투입될 수 있는 예비 컨슈머 역할을 한다.

따라서, 컨슈머 그룹의 최대 병렬 처리 수준은 토픽의 파티션 수에 의해 결정된다.
처리량을 높이기 위해 컨슈머 수를 늘리더라도, 파티션 수 이상으로는 병렬성을 확보할 수 없다.

 

다중 컨슈머 그룹의 활용

하나의 토픽에 대해 여러 개의 독립적인 컨슈머 그룹이 존재할 수 있다.
다른 그룹에 영향을 주지 않고, 토픽의 전체 데이터를 처음부터 끝까지 독립적으로 소비할 수 있다.

 

예를 들어, '주문 발생'이라는 토픽이 있다고 가정한다.
이 토픽의 데이터는 다양한 서비스에서 필요로 할 수 있다.

그림3. 다중 컨슈머 그룹 활용 예시

  • consumer-group-location: 사용자의 위치 기반 서비스를 위해 주문 데이터를 소비
  • consumer-group-notification: 주문 완료 알림 발송을 위해 주문 데이터를 소비
  • consumer-group-analytics: 판매 통계 분석을 위해 주문 데이터를 소비

이처럼 동일한 데이터를 각기 다른 목적과 비즈니스 로직으로 처리해야 할 경우, 다중 컨슈머 그룹을 활용하면 각 서비스가 서로 간섭 없이 독립적으로 데이터를 소비하고 처리할 수 있다.

 

각 그룹은 아래 예시 표와 같이 자신만의 오프셋을 관리하므로,
한 그룹의 소비 상태가 다른 그룹에 영향을 미치지 않는다.

파티션 번호 consumer-group-location consumer-group-notification consumer-group-analytics
Partition 0 offset 120 offset 87 offset 134
Partition 1 offset 98 offset 44 offset 102
Partition 2 offset 105 offset 76 offset 118

 

컨슈머 오프셋 (Offset)

 

카프카는 각 컨슈머 그룹별로 해당 그룹이 특정 토픽의 각 파티션에서 어디까지 메시지를 읽었는지를 나타내는 위치 정보, 즉 오프셋(Offset)을 저장하고 관리한다.

 

이 오프셋 정보는 카프카 내의 특별한 내부 토픽인 __consumer_offsets 에 기록된다.
컨슈머는 poll() 메서드를 통해 데이터를 가져온 후, 자신이 처리한 메시지의 오프셋을 주기적으로 또는 명시적으로 커밋한다.

 

이러한 오프셋 관리 덕분에, 만약 컨슈머 애플리케이션에 장애가 발생하여 재시작되거나, 그룹 내 리밸런싱이 발생하여 다른 컨슈머가 파티션을 이어받더라도, 해당 파티션의 마지막으로 커밋된 오프셋부터 메시지를 이어서 읽을 수 있다.

 

이는 데이터 유실 없이 안정적인 메시지 처리를 가능하게 하는 중요한 메커니즘이다.

 

오프셋 커밋과 메시지 전달 의미론 (Message Delivery Semantics)

 

컨슈머가 오프셋을 언제, 어떻게 커밋하느냐에 따라 카프카의 메시지 전달 보장 수준, 즉 전달 의미론(Delivery Semantics) 이 달라진다. 이는 데이터 처리의 정확성과 신뢰성에 직접적인 영향을 미치므로 매우 중요하다.

(1) 최소 한 번 (At least once)

  • 이것은 카프카 컨슈머의 기본적인 오프셋 커밋 방식(enable.auto.commit=true이고, 자동 커밋 주기에 따라 메시지 처리 후 커밋) 또는 수동 커밋 시 메시지를 완전히 처리한 후 커밋하는 경우에 해당한다.
  • 컨슈머가 메시지를 가져와 성공적으로 처리한 후 오프셋을 커밋한다. 만약 메시지를 처리했지만, 커밋하기 전에 컨슈머에 장애가 발생하면, 재시작된 컨슈머는 마지막으로 커밋된 오프셋부터 다시 메시지를 읽게 된다. 이로 인해 이전에 처리했던 메시지가 중복으로 처리될 가능성이 있다.
  • 따라서 이 방식을 사용할 때는 메시지 처리가 멱등성(Idempotence)을 가지도록 설계하는 것이 중요하다. (즉, 동일한 연산을 여러 번 수행하더라도 결과가 같은 성질)

(2) 최대 한 번 (At most once)

  • 컨슈머가 메시지를 수신하자마자 (실제 처리하기 전) 오프셋을 먼저 커밋하는 방식이다. (예: enable.auto.commit=true이고, poll() 직후 자동 커밋되거나, 수동으로 poll() 직후 바로 커밋)
  • 만약 오프셋을 커밋한 후, 메시지를 실제로 처리하기 전에 컨슈머에 장애가 발생하면, 해당 메시지는 이미 처리된 것으로 간주되어 유실될 가능성이 있다.
  • 메시지 중복은 피할 수 있지만, 데이터 손실 위험이 있어 일반적인 서비스에서는 신중하게 사용해야 한다.

(3) 정확히 한 번 (Exactly once)

  • 메시지가 단 한 번만 정확하게 처리됨을 보장하는 가장 강력한 전달 의미론이다.
  • 이를 위해서는 카프카의 트랜잭션 API를 사용해야 한다. 프로듀서가 트랜잭션으로 데이터를 전송하고, 컨슈머는 트랜잭션 내에서 데이터를 읽고 처리한 후 오프셋을 커밋하는 "read-process-write" 패턴을 구현한다.
  • 주로 Kafka 내부 토픽 간의 데이터 이동(Kafka Streams 등)이나, 트랜잭션을 지원하는 외부 시스템과의 연동 시에 사용되며, 구현 복잡도가 다소 높을 수 있다.

애플리케이션의 요구사항과 데이터의 중요도에 따라 적절한 전달 의미론을 선택하고, 오프셋 커밋 전략을 신중하게 결정해야 한다.

 

맺음말

 

지금까지 카프카에서 데이터 소비의 확장성과 안정성을 높이는 핵심 요소인 컨슈머 그룹에 대해 자세히 알아보았다. 컨슈머 그룹의 동작 원리, 파티션 할당, 오프셋 관리, 그리고 다양한 메시지 전달 의미론을 이해하는 것은 대용량 데이터를 안정적으로 처리하는 분산 시스템을 구축하는 데 있어 매우 중요하다.

 

다음 글에서는 브로커에 대하여 알아보겠다.

 

참고 및 출처

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/08   »
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
31
글 보관함