1. Consumer Group의 개념
카프카에서 모든 Consumer는 반드시 하나의 Consumer Group에 소속되어야 한다. Consumer Group은 하나 이상의 Consumer로 구성될 수 있으며, 토픽의 파티션과 Consumer 간의 관계를 정의하는 중요한 단위이다.
가장 핵심적인 원칙은 하나의 파티션은 같은 그룹 내의 단 하나의 Consumer에만 할당된다는 것이다. 즉, 동일한 Consumer Group 내에서는 특정 파티션의 메시지를 여러 Consumer가 동시에 읽을 수 없다. 이 원칙 덕분에 메시지의 중복 처리를 방지하고, 그룹 내에서 작업을 분산시킬 수 있다.
2. Consumer Group 구성의 다양한 경우의 수
Consumer Group을 구성하는 Consumer의 수와 토픽의 파티션 수에 따라 데이터 처리 방식이 어떻게 달라지는지 알아보자.
2.1. Consumer Group 내에 1개의 Consumer만 있을 경우

- 3개의 파티션(Partition #1, #2, #3, #4)을 가진 토픽이 있고, 하나의 Consumer Group에 단 하나의 Consumer만 존재하는 모습이다. 이 Consumer 하나가 모든 파티션(#1, #2, #3, #4)을 할당받아 처리한다. 화살표는 Consumer가 세 개의 파티션 모두로부터 데이터를 읽고 있음을 나타낸다.
- Consumer를 1개만 실행하더라도, 이 Consumer는 자동으로 자신의 Consumer Group(예: `group.id`로 지정된)에 속하게 된다. 이 경우 하나의 Consumer가 해당 토픽의 모든 파티션을 담당하게 된다.
2.2. Consumer 수가 파티션 수보다 적을 경우

- 3개의 파티션을 가진 토픽에 2개의 Consumer가 속한 Consumer Group의 모습이다. Consumer #1는 Partition #1과 #2을 할당받고, Consumer #2는 Partition #3과 #4를 할당받았다. 화살표는 각 Consumer가 담당하는 파티션을 연결하고 있다.
- Consumer Group 내에 Consumer가 추가되거나 제거될 때마다 파티션과 Consumer의 조합을 변경하는 리밸런싱(Rebalancing)이 발생한다. 이 경우 4개의 파티션을 2개의 Consumer가 나누어 처리하므로, 하나의 Consumer가 여러 파티션을 담당하게 된다.
2.3. Consumer 수와 파티션 수가 동일한 경우 (⭐)

- 3개의 파티션과 3개의 Consumer가 1:1로 정확히 매칭된 모습이다. Consumer #1는 Partition #1, Consumer #2는 Partition #2, Consumer #3는 Partition #3를 각각 하나씩 할당받아 처리한다. 모든 Consumer가 고르게 일을 하고 있으며, 이상적인 분산 처리 상태임을 나타낸다.
- 이 구성이 가장 이상적인 상태이다. 각 Consumer가 하나의 파티션을 전담하여 최대의 병렬 처리 효율을 낼 수 있다. Consumer Group 내에 Consumer 변화가 있을 때마다 리밸런싱이 발생하는 것은 동일하다.
2.4. Consumer 수가 파티션 수보다 많을 경우

- 4개의 파티션을 가진 토픽에 5개의 Consumer가 속한 Consumer Group의 모습이다. 4개의 파티션을 5개의 Consumer가 나누어 가지므로, Consumer #1, #2, #3만 각각 하나의 파티션을 할당받고, 나머지 Consumer #4와 #5는 할당받은 파티션 없이 유휴(Idle) 상태로 대기하고 있다. 이들은 어떤 파티션에도 연결되지 않은 채 점선으로 표현되어 있다.
- 파티션 개수보다 Consumer가 많아지면, 일부 Consumer는 파티션을 할당받지 못하고 유휴(Idle) 상태로 대기하게 된다. 즉, Partition #5는 존재하지 않으므로 Consumer #4와 Consumer #5 중 하나만 파티션을 할당받고, 나머지는 할당받지 못한다. 이것이 리밸런싱의 결과이다.
2.5. 여러 개의 Consumer Group이 하나의 토픽을 구독할 경우

- 하나의 토픽(3개 파티션)을 서로 다른 두 개의 Consumer Group(Group A, Group B)이 구독하고 있는 모습이다. Group A에는 2개의 Consumer, Group B에는 2개의 Consumer가 있다. 각 그룹은 독립적으로 파티션을 할당받는다.
- Group 1의 Consumer들은 A #1, A #2 파티션을, Group 2의 Consumer는 A #1, A #2파티션을 각각 할당받아 데이터를 읽는다. 서로 다른 그룹이므로 동일한 파티션(예: Partition 0)을 두 그룹의 Consumer(Group A의 Consumer와 Group B의 Consumer)가 동시에 읽을 수 있음을 보여준다.
서로 다른 Consumer Group은 완전히 독립적으로 동작한다. 따라서 하나의 파티션은 서로 다른 Consumer Group에 속한 여러 Consumer와 연결될 수 있다. 즉, 동일한 데이터를 다른 목적(예: 실시간 처리, 배치 분석)을 가진 여러 애플리케이션이 각자의 Consumer Group을 통해 중복 없이(그룹 내에서는 중복 없이, 그룹 간에는 독립적으로) 읽어갈 수 있다.
2.6. 핵심 정리
- Consumer Group은 최소 하나 이상 존재해야 한다.
- 하나의 Consumer Group에는 최소 하나 이상의 Consumer가 존재한다.
- 하나의 Consumer는 여러 개의 Partition을 할당받을 수 있다.
- 하나의 Partition은 같은 Consumer Group 내의 여러 Consumer와 연결될 수 없다. (즉, 그룹 내에서는 1:1 관계)
- 예를 들어, Consumer Group 1(Consumer #1, #2)과 Consumer Group 2(Consumer #1, #2)가 있을 때, Partition #4는 같은 그룹 내의 여러 Consumer와 연결될 수 없지만, Consumer Group 1의 Consumer #1과 Consumer Group 2의 Consumer #1이 동시에 연결되는 것은 가능하다. 즉, 파티션은 서로 다른 Consumer 그룹에 속한 Consumer라면 동시에 연결될 수 있다.
3. Consumer Group과 group.id

모든 Consumer는 고유한 그룹 아이디(`group.id`)를 가지는 Consumer Group에 소속되어야 한다. 이 `group.id`는 컨슈머를 정의하는 가장 중요한 설정 중 하나이며, 동일한 `group.id`를 가진 Consumer들은 하나의 그룹으로 묶여 파티션을 분배받게 된다.
4. CLI를 통한 Rebalancing 실습
4.1. 실습 [1]: Rebalancing 직접 확인하기
4.1.1. multipart-topic 생성
kafka-topics --bootstrap-server localhost:9092 --create --topic multipart-topic --partitions 3
4.1.2. 동일한 Consumer Group(`group_01`)을 가지는 Consumer 3개 실행
3개의 터미널 창을 열고, 각각 아래 명령어를 실행한다.
kafka-console-consumer --bootstrap-server localhost:9092 --group group_01 --topic multipart-topic \\
--property print.key=true --property print.value=true \\
--property print.partition=true

- 3개의 터미널 창이 나란히 있고, 각각 Consumer가 실행된 모습이다. 왼쪽 상단에는 카프카 브로커 로그가 표시된 또 다른 창이 있다. 브로커 로그 창에는 `[GroupCoordinator]: ... with 3 members`와 같은 메시지가 강조되어 있다. 이는 그룹에 3개의 멤버(Consumer)가 정상적으로 참여했음을 보여준다.
- 카프카 브로커의 로그를 확인해보면 `... with 3 members`라는 메시지를 통해 3개의 Consumer가 그룹에 참여했음을 확인할 수 있다.
4.1.3. Consumer 2개 종료 및 Rebalance 확인
실행 중인 3개의 Consumer 중 2개를 `Ctrl+C`로 종료한다. 브로커 로그에서 리밸런싱이 발생했음을 알리는 로그를 확인할 수 있다.

# Consumer Group 상태 확인
kafka-consumer-groups --bootstrap-server localhost:9092 --describe --group group_01
출력 결과를 보면 3개 중 2개가 종료되어 현재 그룹에는 1개의 Consumer만 존재하는 것을 확인할 수 있다.
4.1.4. Consumer 재추가 및 Rebalance 확인

종료했던 Consumer를 다시 하나 실행하여 총 2개로 만든다. 다시 `describe` 명령어로 확인하면 Consumer ID가 2개로 늘어나고 리밸런싱이 완료되었음을 알 수 있다. 마지막으로 하나를 더 실행하여 총 3개의 Consumer로 복원해보자. 리밸런싱이 다시 발생하고, Consumer ID가 새롭게 할당된다.

4.1.5. 메시지 전송 및 Consumer Group 상태 변화 확인

이제 프로듀서를 통해 메시지를 전송해보자.
kafka-console-producer --bootstrap-server localhost:9092 --topic multipart-topic \\
--property key.separator=: --property parse.key=true
>1:aaa
>2:bbb
>3:ccc
>4:ddd
각 메시지가 3개의 Consumer 창에 분산되어 출력되는 것을 확인할 수 있다. 또한 `kafka-consumer-groups --describe` 명령어로 확인하면 `CURRENT-OFFSET`, `LOG-END-OFFSET` 값이 변경된 것을 볼 수 있다. 메시지 수가 적어 변화를 확인하기 어렵다면, 대량의 메시지를 전송해보자.
4.1.6. 대량의 Key 메시지 전송 및 결과 확인

# keyload.log 파일 생성 및 2000개 메시지 기록
touch keyload.log
for i in {1..2000}
do
echo "$i:test key message sent test00000000000000 $i" >> keyload.log
done
# keyload.log 파일 기반 메시지 전송
kafka-console-producer --bootstrap-server localhost:9092 --topic multipart-topic \\
--property key.separator=: --property parse.key=true < keyload.log
이후 Consumer Group의 상태를 다시 확인하면 오프셋 관련 값들이 크게 변경된 것을 확인할 수 있다.
4.2. 실습 [2]: Consumer Group 삭제하기
4.2.1. Consumer Group 상태 확인
kafka-consumer-groups --bootstrap-server localhost:9092 --describe --group group_01
4.2.2. Consumer Group 제거
kafka-consumer-groups --bootstrap-server localhost:9092 --delete --group group_01
⚠️ 주의: Consumer Group을 삭제할 때는 해당 그룹에 단 하나의 Consumer도 실행 중이면 안 된다. 만약 Consumer가 존재하는 상태에서 삭제를 시도하면 실패한다.
4.2.3. 결과 확인
`kafka-consumer-groups --describe --group group_01` 명령어를 실행했을 때, `CONSUMER-ID`가 모두 -로 표시된 상태에서만 삭제가 가능하다. 삭제가 성공하면 Deletion of requested consumer groups ('group_01') was successful. 메시지를 확인할 수 있다.

터미널 화면에 `kafka-consumer-groups --delete --group group_01` 명령어를 실행한 결과가 출력되어 있다. 명령어 실행 전에는 CONSUMER-ID에 실제 ID 값들이 표시되지만, Consumer를 모두 종료한 후에는 모든 `CONSUMER-ID`가 `-`로 바뀐 모습을 보여준다. 이 상태에서 삭제 명령어를 실행하면 성공 메시지가 출력된다.
5. Consumer Group 핵심 요약
5.1. Consumer Group의 기본 원칙
- 모든 Consumer는 반드시 하나의 Consumer Group에 속해야 한다.
- 하나의 파티션은 같은 그룹 내의 오직 하나의 Consumer에게만 할당된다. (같은 그룹 내에서는 파티션과 Consumer가 1:1 관계)
- 이 원칙 덕분에 메시지 중복 없이 그룹 내에서 작업을 분산할 수 있다.
5.2. Consumer 수와 파티션 수에 따른 4가지 경우의 수
| 상황 | Consumer 수 | 파티션 수 | 결과 | 특징 |
| Case 1 | 1개 | N개 | 1개 Consumer가 모든 파티션 담당 | 단일 처리, 병렬성 없음 |
| Case 2 | 2개 | 4개 | 각 Consumer가 여러 파티션 담당 | 일부 병렬 처리, 부하 분산 |
| Case 3 (⭐최적) | 3개 | 3개 | 1:1 매칭 (각 Consumer가 하나씩) | 최대 병렬 처리, 이상적인 상태 |
| Case 4 | 5개 | 3개 | 3개만 할당받고 2개는 유휴(Idle) | 리소스 낭비, 불필요한 Consumer |
5.3. 여러 개의 Consumer Group
- 서로 다른 Consumer Group은 완전히 독립적으로 동작한다.
- 하나의 파티션을 여러 Group의 Consumer가 동시에 읽을 수 있다. (예: 실시간 처리 그룹 + 배치 분석 그룹)
5.4. 핵심 원칙 요약
- Consumer Group은 최소 하나 이상 존재해야 한다.
- 하나의 Consumer는 여러 파티션을 할당받을 수 있다.
- 하나의 파티션은 같은 그룹 내 여러 Consumer와 연결될 수 없다. (그룹 내에서는 1:1)
- 하나의 파티션은 서로 다른 그룹의 여러 Consumer와 연결될 수 있다. (그룹 간에는 N:M)
5.5. group.id의 역할
- 모든 Consumer는 group.id로 식별되는 Consumer Group에 속한다.
- 동일한 group.id를 가진 Consumer들은 하나의 그룹으로 묶여 파티션을 분배받는다.
'Kafka > Core' 카테고리의 다른 글
| [BASIC #8] Kafka: Java 클라이언트 구현 환경 구축 (0) | 2025.09.07 |
|---|---|
| [BASIC #7] Config 구분 및 이해: 카프카 설정의 계층 구조 파악하기 (0) | 2025.09.07 |
| [BASIC #5] Producer의 핵심: 직렬화와 파티셔닝 전략 (0) | 2025.09.07 |
| [BASIC #4] 메시지 전송의 시작: Producer와 Consumer (0) | 2025.09.07 |
| [BASIC #3] Kafka 3가지 핵심 요소: Topic, Partition, Offsets (0) | 2025.09.07 |
