백엔드 데이터 인프라 97편. Kafka Consumer 설정 25가지 — group.id·auto.offset.reset·enable.auto.commit·session.timeout·max.poll.interval·fetch.min.bytes·max.poll.records·partition.assignment.strategy·isolation.level 등 카테고리별 튜닝 핵심을 풀어쓴 학습 노트.
이 글은 백엔드 데이터 인프라 시리즈 130편 중 97편이에요. 96편 에서 Producer 설정을 잡았다면, 이번 97편은 그 반대편으로 Consumer 설정 25가지 를 짚어요. 87편 Design·92편 API 와 직결되는 튜닝 핵심이에요.
Consumer Config가 어렵게 느껴지는 이유
Consumer 설정(메시지 받는 쪽 설정)은 Producer 보다 훨씬 까다로워요. 다음 4가지 영역이 서로 맞물리거든요.
- Group membership (session·heartbeat·rebalance)
- Offset commit (auto·sync·async)
- Fetch tuning (min·max·timeout)
- Partition assignment (strategy)
설정 하나가 다른 설정에 영향을 줘요. session.timeout 을 늘리면 heartbeat 도 같이 늘려야 하는 식의 조정 규칙이 곳곳에 깔려 있어요.
이 글에서는 25가지 설정을 카테고리로 묶어서 살펴보고, 권장 조합과 함정도 함께 정리해요.
1. 필수 (4개)
bootstrap.servers=kafka1:9092,kafka2:9092
group.id=order-workers
key.deserializer=org.apache.kafka.common.serialization.StringDeserializer
value.deserializer=org.springframework.kafka.support.serializer.JsonDeserializer
group.id 는 consumer group 식별자예요. 같은 group 안의 consumer 들이 partition 을 나눠 가져요.
2. Offset (5개)
auto.offset.reset
auto.offset.reset=latest # 기본, 새 group = 현재 시점부터
# 또는
auto.offset.reset=earliest # 새 group = 처음부터
# 또는
auto.offset.reset=none # offset 없으면 에러 (수동 처리)
개발 환경에서는 earliest 로 모든 메시지를 보고, 운영 환경에서는 상황에 맞춰 골라요.
enable.auto.commit
enable.auto.commit=true # 기본 (위험)
# 운영 권장
enable.auto.commit=false
true 면 자동 commit 이어서 메시지 손실 위험이 있어요(92편). 운영 환경에서는 false 가 안전해요.
auto.commit.interval.ms
auto.commit.interval.ms=5000 # 5초 (기본)
enable.auto.commit=true 일 때만 의미가 있어요.
isolation.level
isolation.level=read_uncommitted # 기본
# 또는 EOS 환경
isolation.level=read_committed
EOS(exactly-once semantics, 정확히 한 번 처리) 깊이는 88편에서 다뤄요. Transactional 메시지를 처리하는 자리예요.
exclude.internal.topics
exclude.internal.topics=true # 기본
__consumer_offsets 같은 internal topic 을 제외해요.
3. Group Membership (8개)
session.timeout.ms
session.timeout.ms=45000 # 45초 (기본)
Broker 가 이 consumer 의 죽음을 판단하는 시간이에요. 처리가 길면 늘려 잡아요.
권장:
- 짧은 처리 (수 ms) = 30~60초
- 긴 처리 (수 분) = 120~180초
heartbeat.interval.ms
heartbeat.interval.ms=3000 # 3초 (기본)
Consumer 가 broker 에 heartbeat 를 보내는 주기예요. 보통 session.timeout.ms / 3 으로 잡아요.
max.poll.interval.ms
max.poll.interval.ms=300000 # 5분 (기본)
두 poll() 사이의 최대 간격이에요. 이걸 넘기면 consumer 가 죽은 걸로 보고 rebalance 가 일어나요.
처리 시간이 긴 환경에서는 10분·30분·1시간으로 늘려 잡기도 해요.
max.poll.records
max.poll.records=500 # 기본
한 poll() 의 최대 메시지 수예요. 이 메시지들을 max.poll.interval.ms 안에 다 처리해야 해요.
처리 시간이 길면 50~100 으로 적게, 짧으면 1000+ 으로 많이 잡아요.
group.instance.id
group.instance.id=worker-1
87편에서 다룬 Static Membership(고정 멤버십, rebalance 회피)이에요. 재시작이나 rolling deploy 때 불필요한 rebalance 를 피해요.
대규모거나 상태가 큰 환경에서는 반드시 설정해요.
partition.assignment.strategy
partition.assignment.strategy=\
org.apache.kafka.clients.consumer.CooperativeStickyAssignor # Kafka 2.4+ 권장
# 또는
partition.assignment.strategy=\
org.apache.kafka.clients.consumer.StickyAssignor # 2.4 이전
# 또는
partition.assignment.strategy=\
org.apache.kafka.clients.consumer.RangeAssignor # 기본
| Strategy | 특징 |
|---|---|
| Range (기본) | partition 범위 분배, 한 consumer 가 많이 가질 수 있음 |
| RoundRobin | 균등 분배 |
| Sticky | 균등 + rebalance 시 이전 할당 유지 시도 |
| CooperativeSticky | Sticky + 점진적 rebalance (멈춤 시간 ↓) |
대부분의 환경에서는 CooperativeSticky 를 골라요. Kafka 2.4+ 에서 권장되고, rebalance 영향이 가장 적어요.
group.protocol
group.protocol=consumer # 기본
# 또는
group.protocol=classic # 옛 protocol
Kafka 4.0+ 의 새 Consumer Group Protocol 인 KIP-848(차세대 consumer 프로토콜) 이에요. 아직 덜 알려졌지만 점진적으로 도입되는 중이에요.
group.remote.assignor
group.remote.assignor=range
새 KIP-848 protocol 의 broker-side assignor 예요.
4. Fetch (6개)
fetch.min.bytes
fetch.min.bytes=1 # 1 (기본)
# 처리량 우선
fetch.min.bytes=10240 # 10KB
Broker 가 최소 N 바이트가 모일 때까지 기다려요. 처리량은 늘고 지연은 늘어나요.
fetch.max.wait.ms
fetch.max.wait.ms=500 # 500ms (기본)
fetch.min.bytes 가 안 채워졌어도 max.wait 이 지나면 반환해요. Long polling 의 한계예요.
fetch.max.bytes
fetch.max.bytes=52428800 # 50MB (기본)
한 fetch 의 최대 응답 크기예요.
max.partition.fetch.bytes
max.partition.fetch.bytes=1048576 # 1MB (기본)
Partition 한 개에서 fetch 하는 최대 크기예요. 한 메시지가 이보다 크면 consumer 가 진행을 못 해요.
여기서 시험 함정이 하나 있어요. 이 값이 broker max.message.bytes 와 topic max.message.bytes 보다 작으면 큰 메시지를 받을 수 없어요. 세 값의 일관성을 늘 챙겨야 해요.
receive.buffer.bytes
receive.buffer.bytes=65536 # 64KB (기본)
TCP receive buffer 예요.
send.buffer.bytes
send.buffer.bytes=131072 # 128KB (기본)
TCP send buffer 예요.
5. Connection·Network (3개)
request.timeout.ms
request.timeout.ms=30000 # 30초 (기본)
Broker 응답을 기다리는 최대 시간이에요.
connections.max.idle.ms
connections.max.idle.ms=540000 # 9분 (기본)
Idle 상태가 길어지면 connection 을 닫아요.
reconnect.backoff.ms · reconnect.backoff.max.ms
reconnect.backoff.ms=50
reconnect.backoff.max.ms=1000
Reconnect 사이의 exponential backoff 를 잡아요.
6. Identity·Monitoring (2개)
client.id
client.id=order-worker-1
운영 모니터링에서 가독성을 높여요. 같은 group 안에서 각 consumer 의 고유 id 역할이에요.
metrics.recording.level
metrics.recording.level=INFO # 기본
# DEBUG = 더 자세한 메트릭
운영 환경 권장 조합
일반 백엔드 (균형)
bootstrap.servers=kafka1:9092,kafka2:9092,kafka3:9092
group.id=order-workers
key.deserializer=org.apache.kafka.common.serialization.StringDeserializer
value.deserializer=org.springframework.kafka.support.serializer.JsonDeserializer
# Offset
auto.offset.reset=earliest
enable.auto.commit=false
# Group
session.timeout.ms=60000
heartbeat.interval.ms=20000
max.poll.interval.ms=300000
max.poll.records=500
partition.assignment.strategy=org.apache.kafka.clients.consumer.CooperativeStickyAssignor
# Fetch
fetch.min.bytes=1024
fetch.max.wait.ms=500
# Identity
client.id=order-worker-prod-1
group.instance.id=order-worker-prod-1
처리 시간 긴 환경 (예: ML 추론)
session.timeout.ms=120000
heartbeat.interval.ms=40000
max.poll.interval.ms=1800000 # 30분
max.poll.records=10 # 적게
매우 빠른 처리량 (메트릭·로그)
fetch.min.bytes=102400 # 100KB
fetch.max.wait.ms=100
max.poll.records=5000 # 많이
enable.auto.commit=true # 손실 OK
auto.commit.interval.ms=1000
EOS (Kafka Streams 등)
isolation.level=read_committed
enable.auto.commit=false
Spring Boot 적용
spring:
kafka:
bootstrap-servers: kafka1:9092,kafka2:9092
consumer:
group-id: order-workers
auto-offset-reset: earliest
enable-auto-commit: false
key-deserializer: org.apache.kafka.common.serialization.StringDeserializer
value-deserializer: org.springframework.kafka.support.serializer.JsonDeserializer
max-poll-records: 500
properties:
session.timeout.ms: 60000
heartbeat.interval.ms: 20000
max.poll.interval.ms: 300000
partition.assignment.strategy: org.apache.kafka.clients.consumer.CooperativeStickyAssignor
group.instance.id: ${HOSTNAME}
client.id: order-worker
listener:
ack-mode: MANUAL
concurrency: 3 # 한 application 에 3 consumer
설정 상호작용 — 함정 모음
1. heartbeat.interval.ms 와 session.timeout.ms 비율
heartbeat = session / 3 이 권장 비율이에요. 두 값이 같으면 heartbeat 한 번만 놓쳐도 죽은 걸로 처리돼요.
2. max.poll.interval.ms < 실제 처리 시간
처리 도중에 consumer 가 죽은 걸로 판정되면 rebalance 가 일어나요. 처리는 안 끝났는데 다른 consumer 가 같은 메시지를 다시 받아 중복 처리가 발생해요.
3. max.partition.fetch.bytes < 큰 메시지
해당 partition 이 아예 진행을 못 해요. broker·topic 의 max.message.bytes 와 일관되게 잡아야 해요.
4. enable.auto.commit=true + 메시지 처리 실패
commit 은 됐는데 처리는 못 한 상태가 되면 메시지가 영구 손실돼요. 운영 환경에서는 false 로 두고 manual commit 을 써요.
5. group.instance.id 중복
FencedInstanceIdException 으로 종료돼요. 각 instance 가 고유한 id 를 가져야 해요.
6. Range Assignor 의 불균등
partition 7개에 consumer 3명이면 [3, 3, 1] 로 갈려요(Range 는 균등하지 않아요). CooperativeSticky 를 권장해요.
모니터링 메트릭
JMX(Java Management Extensions, 자바 모니터링 표준):
records-consumed-rate— 초당 메시지 수records-lag-max— 최대 lagrecords-lag-avg— 평균 lagfetch-rate— fetch 횟수commit-rate— commit 횟수heartbeat-rate— heartbeat
가장 중요한 건 records-lag-max 예요. consumer 가 따라가지 못하고 있다는 신호거든요.
시험 직전 한 번 더 — Kafka Consumer Config 함정 압축 노트
- 필수 =
bootstrap.servers·group.id·key/value.deserializer - Offset —
auto.offset.reset (latest/earliest/none)·enable.auto.commit·isolation.level (read_uncommitted/read_committed) - 운영 환경 =
enable.auto.commit=false - EOS =
isolation.level=read_committed - Group Membership —
session.timeout.ms (45초)·heartbeat.interval.ms (3초)·max.poll.interval.ms (5분)·max.poll.records (500) - 권장 비율 =
heartbeat = session / 3 - 처리 시간 긴 환경 =
max.poll.interval.ms늘림 group.instance.id= Static Membership, rebalance 회피- 대규모·상태 큰 = 필수
partition.assignment.strategy— Range·RoundRobin·Sticky·CooperativeSticky (권장 2.4+)- CooperativeSticky = 점진적 rebalance, 멈춤 시간 ↓
- KIP-848 =
group.protocol=consumer(Kafka 4.0+) - Fetch —
fetch.min.bytes·fetch.max.wait.ms·fetch.max.bytes·max.partition.fetch.bytes max.partition.fetch.bytes와 broker·topicmax.message.bytes일관성client.id= 운영 모니터링 가독성- 운영 환경 권장 조합 — 일반·긴 처리·고처리량·EOS
- Spring =
spring.kafka.consumer.*+listener.ack-mode=MANUAL+concurrency - 함정 —
heartbeat = session같으면 한 번 놓침에 죽음 - 함정 —
max.poll.interval.ms< 실제 처리 → 중복 폭증 - 함정 —
max.partition.fetch.bytes< 큰 메시지 → 진행 못 함 - 함정 —
enable.auto.commit=true+ 처리 실패 = 영구 손실 - 함정 —
group.instance.id중복 = FencedInstanceIdException - 함정 — Range Assignor 불균등 분배
- 모니터링 = JMX 의
records-lag-max(가장 중요)
공식 문서: Kafka Consumer Configs 에서 모든 설정의 자세한 사양을 확인할 수 있어요.
시리즈 다른 편 (앞뒤 글 모음)
이전 글:
- 92편 — Kafka Consumer API 깊이 (Commit · Rebalance · Seek)
- 93편 — Kafka Admin Client API (Topic·ACL·Consumer Group 관리)
- 94편 — Kafka Broker 설정 30가지 (실무 핵심)
- 95편 — Kafka Topic 설정 (Retention · Compression · Cleanup)
- 96편 — Kafka Producer 설정 20가지 (Batching · Retries · Idempotence)
다음 글: