consumer group — topic을 여러 consumer가 나눠 읽는 팀
orders topic에 주문이 초당 수만 건 쏟아진다. consumer 하나로는 다 못 읽는다. consumer를 여럿 띄워 병렬로 읽고 싶다 — 하지만 같은 메시지를 두 consumer가 동시에 읽으면 중복이 생긴다. 이걸 해결하는 게 consumer group이다. 여러 consumer가 topic의 partition을 서로 겹치지 않게 나눠 읽는 팀이다.
이 글은 consumer group이 뭔지, 어떻게 partition을 나누는지, consumer가 들락날락할 때 일어나는 rebalance와 그 비용, 그리고 실제로 어떻게 구성하고 관리하는지까지 다룬다.
consumer group이란 — partition을 나눠 읽는 consumer 팀
consumer group은 같은 group 이름을 가진 consumer들의 모임이다. 핵심 규칙은 한 줄이다:
한 consumer group 안에서, partition 1개는 정확히 한 consumer가 담당한다.
| 구성 | 무슨 일 |
|---|---|
| partition 4개 + consumer 2명 | 각 consumer가 2 partition씩 |
| partition 4개 + consumer 4명 | 각 consumer가 1 partition씩 (최대 병렬) |
| partition 4개 + consumer 6명 | 4개만 일하고 2개는 놀음(idle) |
왜 "1 partition = 1 consumer"인가 — 같은 partition을 두 consumer가 동시에 읽으면 순서가 꼬이고 offset commit이 충돌한다. 그래서 한 partition은 한 consumer만 단독 소유. 병렬성의 상한 = partition 수다(장 02).
consumer group은 어떻게 쓰이나 — worked scenario
orders topic(partition 6개)을 consumer 3개로 확장:
flowchart TB
T["orders topic<br/>(partition 0 ~ 5)"] --> A["consumer A<br/>(p0, p1)"]
T --> B["consumer B<br/>(p2, p3)"]
T --> C["consumer C<br/>(p4, p5)"]
subgraph GP["group: order-processors"]
A
B
C
end
- consumer 3개를 같은 group(
order-processors)으로 띄운다. - Kafka가 partition을 나눠 줌 — A: p0,p1 / B: p2,p3 / C: p4,p5.
- 각 consumer가 자기 partition만 읽어 처리 → 3배 병렬, 중복 없음.
다른 group은 독립적:
order-processorsgroup과analyticsgroup은 서로 간섭 없이 같은orderstopic을 전부 각자 읽는다. group마다 자기 offset을 따로 관리한다.
consumer group 설정 — 어떻게 구성하나
consumer 설정 (Java)
# group 식별자 (핵심 — 같은 group.id = 같은 팀)
group.id=order-processors
# broker 연결
bootstrap.servers=localhost:9092
# 역직렬화
key.deserializer=org.apache.kafka.common.serialization.StringDeserializer
value.deserializer=org.apache.kafka.common.serialization.StringDeserializer
# auto-commit (신뢰성 필요시 false, 장 04)
enable.auto.commit=false
# partition 할당 전략
partition.assignment.strategy=org.apache.kafka.clients.consumer.CooperativeStickyAssignor
# rebalance 관련 (차세대 프로토콜 사용시 일부 무시)
session.timeout.ms=45000
heartbeat.interval.ms=3000
max.poll.interval.ms=300000
partition 할당 전략
| 전략 | 특징 |
|---|---|
| RangeAssignor | topic별로 partition을 범위로 나눔 (오랜 기본) |
| RoundRobinAssignor | round-robin으로 순환 분배 |
| StickyAssignor | 재할당 시 기존 할당 최대한 유지 (이동 최소화) |
| CooperativeStickyAssignor | sticky + 증분 교환 (KIP-429, 권장) |
차세대 rebalance 프로토콜(4.0 GA) 활성 시
partition.assignment.strategy는 사용 불가. 프로토콜이 자체 관리.
rebalance — consumer가 들락날락하면 partition을 다시 나눈다
consumer group의 구성원이 바뀌면 partition을 재분배한다(rebalance):
- consumer 합류(새 consumer 띄움) 또는 이탈(크래시·종료).
- 구독 topic/partition 변경.
rebalance의 비용 — stop-the-world
구형(eager) 프로토콜에선 rebalance 시작 시 모든 consumer가 partition을 내려놓고 전체를 다시 나눈다 — 끝날 때까지 아무도 소비 못함. consumer가 많을수록 멈춤이 길어진다. "consumer를 함부로 재시작하면 안 된다"는 이유.
cooperative rebalance — 변경분만 교체
Kafka 4.0에선 차세대 rebalance 프로토콜이 GA됐다 (consumer-rebalance-protocol.md):
- 유지 가능한 partition은 그대로, 변경이 필요한 partition만 교체.
- 나머지 consumer는 계속 소비 → 멈춤 최소화.
- 활성화:
group.protocol=consumer.
차세대 프로토콜 활성 시
heartbeat.interval.ms,session.timeout.ms,partition.assignment.strategy사용 불가.
ConsumerRebalanceListener — 상태 정리 핵심 훅
partition이 할당/해제될 때 콜백을 받아 상태를 정리한다:
consumer.subscribe(Arrays.asList("orders"), new ConsumerRebalanceListener() {
@Override
public void onPartitionsRevoked(Collection<TopicPartition> partitions) {
// partition을 잃기 전에 처리 중인 offset을 commit (유실 방지)
consumer.commitSync();
// state store 정리 등
}
@Override
public void onPartitionsAssigned(Collection<TopicPartition> partitions) {
// 새 partition 할당 시 초기화 (예: offset seek, 캐시 갱신)
}
});
이 훅이 rebalance 중 데이터 유실/중복을 막는 핵심이다. 멱등 처리와 함께 써야 at-least-once를 지킨다.
Kafka 4.3 실습 — 직접 확인하기
사전: KRaft 단일 노드,
grp-demotopic(--partitions 4), 메시지 다수 사전 produce.
group 상태와 할당 확인
# Kafka 4.3, KRaft 단일 노드
bin/kafka-consumer-groups.sh --describe --group g-state --state --bootstrap-server localhost:9092
COORDINATOR (ID) ASSIGNMENT-STRATEGY STATE #MEMBERS
localhost:9092 (0) range Stable 4
확인할 것: STATE(Stable/PreparingRebalance/CompletingRebalance), 멤버 수.
partition 할당 분포
bin/kafka-consumer-groups.sh --describe --group g-state --members --verbose --bootstrap-server localhost:9092
다중 consumer 병렬 실습
터미널 3개를 열어 같은 group으로 consumer를 각각 띄운다:
# 터미널 1
bin/kafka-console-consumer.sh --topic grp-demo --group demo-group --bootstrap-server localhost:9092
# 터미널 2 (같은 group)
bin/kafka-console-consumer.sh --topic grp-demo --group demo-group --bootstrap-server localhost:9092
# 터미널 3 (같은 group)
bin/kafka-console-consumer.sh --topic grp-demo --group demo-group --bootstrap-server localhost:9092
메시지를 produce하면 3개 consumer가 partition을 나눠 각자 다른 메시지를 받는다. 한 consumer를 종료(Ctrl+C)하면 → rebalance → 남은 consumer가 그 partition을 이어받는다.
차세대 rebalance 프로토콜 활성화
# consumer 설정에 추가
group.protocol=consumer
이 설정으로 4.0 차세대 프로토콜 활성 → rebalance 멈춤 최소화.
흔히 묻는 것, 흔히 틀리는 것
| 오해 | 정정 |
|---|---|
| "consumer를 늘리면 무조건 빨라진다" | partition 수가 상한. 초과분은 idle |
| "다른 consumer group은 메시지를 나눠 갖는다" | 각 그룹이 독립적으로 전체 소비 |
| "rebalance는 순식간이라 무시해도 된다" | 구형에선 stop-the-world. 빈번 재시작은 처리량 저하 |
| "partition.assignment.strategy는 항상 설정해야" | 차세대 프로토콜 활성 시 사용 불가 |
더 깊이
- static membership(KIP-345):
group.instance.id로 고정 identity. 재시작 시 rebalance 최소화 → 상태 저장 앱에 유리. - assignment 전략 선택: CooperativeStickyAssignor(권장)가 가장 적은 이동으로 rebalance.
- rebalance 리스너와 at-least-once:
onPartitionsRevoked에서 commit하지 않으면, partition 이관 시 미처리 메시지가 중복/유실.
요약 — 이 글의 결론
- consumer group = 같은 group 이름의 consumer 모임. partition을 겹치지 않게 나눠 읽음.
- 핵심 규칙: partition 1개 = consumer 1명. 병렬성 상한 = partition 수.
- group 간 독립: 각 group이 전체 topic을 따로 소비(자기 offset 관리).
- 설정:
group.id가 팀 식별자.partition.assignment.strategy로 할당 알고리즘 선택. - rebalance: 멤버십 변화 시 재분배. 구형=stop-the-world, 차세대(4.0 GA,
group.protocol=consumer)=변경분만 교체. - ConsumerRebalanceListener:
onPartitionsRevoked에서 commit+정리 → rebalance 중 유실/중복 방지.
생각해 볼 문제
- consumer group이 "partition을 겹치지 않게 나눠 읽는 팀"이라는 것이 왜 필요한가?
- partition 6개에 consumer 4개. 각 consumer는 몇 partition? 8개로 늘리면?
- 주문 처리 group과 분석 group이 같은 topic을 읽을 때 서로 간섭이 없는 이유는?
- rebalance가 일어나는 상황 세 가지. 구형에서 왜 "stop-the-world"가 문제인가?
- 차세대 rebalance 프로토콜(4.0)을 활성화하는 설정은?
- ConsumerRebalanceListener의
onPartitionsRevoked에서 해야 할 일은? - CooperativeStickyAssignor가 기본 RangeAssignor보다 나은 점은?
참고
- KafkaConsumer.java (consumer group, rebalance) - 접근 2026-07-09
- Consumer Rebalance Protocol (4.0 GA) - 접근 2026-07-09
- Consumer configs - 접근 2026-07-09
- KIP-429(cooperative rebalance), KIP-345(static membership), KIP-848(차세대 rebalance protocol)
'Tech Artifacts > Kafka' 카테고리의 다른 글
| Kafka - 07. log retention (0) | 2026.07.09 |
|---|---|
| Kafka - 06. replication (0) | 2026.07.09 |
| Kafka - 04. consumer (0) | 2026.07.09 |
| Kafka - 03. producer (0) | 2026.07.09 |
| Kafka - 02. topic and partition (0) | 2026.07.09 |
