Kafka Shallow Dive - 운영 — 모니터링, 튜닝, 장애 케이스
Published:
개념 다 끝났으니 마지막 주는 운영. 무엇을 봐야 하고, 어디를 튜닝하고, 어떤 장애가 자주 나는지. 이 글은 “나중에 새벽에 불려나왔을 때 다시 찾아볼 체크리스트” 용도로 정리.
무엇을 모니터링하나
Broker 레벨
| 지표 (JMX) | 의미 | 임계 |
|---|---|---|
UnderReplicatedPartitions | ISR이 RF보다 적은 파티션 수 | > 0 지속되면 문제 |
OfflinePartitionsCount | 사용 불가 파티션 | > 0 = 장애 |
ActiveControllerCount | 클러스터에 컨트롤러 수 | 정확히 1이어야 |
RequestHandlerAvgIdlePercent | I/O 스레드 여유율 | < 0.3 = 과부하 |
NetworkProcessorAvgIdlePercent | 네트워크 스레드 여유율 | < 0.3 = 과부하 |
BytesInPerSec / BytesOutPerSec | 초당 in/out 바이트 | 용량 계획 |
LeaderCount | 이 브로커가 leader인 파티션 수 | 브로커 간 균형 확인 |
PartitionCount | 이 브로커가 가진 파티션 총수 | 균형 확인 |
IsrShrinksPerSec / IsrExpandsPerSec | ISR 변동 주기 | 잦으면 네트워크/디스크 이슈 |
가장 먼저 봐야 할 빨간불 3개: UnderReplicatedPartitions, OfflinePartitionsCount, ActiveControllerCount.
Producer
record-error-rate/record-retry-rate— 재시도/에러 비율request-latency-avg/-max— 브로커 응답 지연buffer-available-bytes— accumulator 여유batch-size-avg— 배치 크기 (너무 작으면 효율↓)
Consumer
- Consumer lag — 가장 중요
records-consumed-rate— 초당 소비 레코드fetch-latency-avgcommit-latency-avgrebalance-rate-per-hour— 잦으면 문제
Lag은 kafka-consumer-groups.sh --describe 또는 Prometheus의 kafka-exporter / kafka-lag-exporter로 수집.
모니터링 스택 예시
Kafka brokers ── JMX ──▶ Prometheus JMX Exporter ──▶ Prometheus ──▶ Grafana
│
Consumer apps ── Micrometer ──────────────────────────────┤
│
kafka-exporter (lag/offsets) ─────────────────────────────┘
Grafana 대시보드는 Confluent/LinkedIn에서 공식적으로 공개한 템플릿들이 있고 대부분 그거 쓰면 됨 (Grafana 대시보드 ID 7589 같은 공개 템플릿).
용량 계획 감 잡기
대충의 계산:
필요 디스크 = (BytesInPerSec) × (retention 시간) × (replication factor)
예: 초당 50 MB 수신, 7일 보존, RF=3
50 * 1024 * 1024 * 3600 * 24 * 7 * 3
≈ 90 TB (클러스터 전체)
노드 수는 “한 노드 I/O 한계”와 “파티션 수” 기준. 2025년 시점 기준 SSD 노드 한 대가 초당 100~300MB 정도 안정권. 여기에 replication 트래픽까지 더해지니 여유를 꽤 둬야 함.
파티션 수 가이드 (경험칙):
- 브로커당 2,000~4,000 파티션이 안정권 (KRaft에선 더 가능)
- 한 topic이 너무 많은 파티션(> 수백)은 피하기 — consumer rebalance 비용
튜닝 체크리스트
OS
- 디스크: XFS 권장 (ext4도 OK).
noatime마운트 - 스왑:
vm.swappiness=1 - 파일 핸들:
ulimit -n 100000+ - 네트워크:
net.core.rmem_max,wmem_max증대 - 페이지 캐시를 크게 쓰니 메모리 넉넉히. Kafka JVM heap은 6~8GB면 충분, 나머진 OS 페이지 캐시로 (큰 힙은 GC 때문에 역효과)
JVM
-Xms6g -Xmx6g
-XX:MetaspaceSize=96m
-XX:+UseG1GC
-XX:MaxGCPauseMillis=20
-XX:InitiatingHeapOccupancyPercent=35
-XX:G1HeapRegionSize=16M
-XX:MinMetaspaceFreeRatio=50
-XX:MaxMetaspaceFreeRatio=80
G1GC + 작은 힙. ZGC도 옵션이지만 운영 노하우는 G1이 많음.
Kafka
num.network.threads=8
num.io.threads=16
socket.send.buffer.bytes=1048576
socket.receive.buffer.bytes=1048576
socket.request.max.bytes=104857600
num.replica.fetchers=4 # follower fetch 병렬도
replica.fetch.max.bytes=10485760
log.flush.interval.messages=Long.MAX # OS에 맡김 (기본)
log.segment.bytes=1073741824 # 1GB
log.retention.hours=168
Flush는 OS에 맡기는 게 기본. Kafka가 직접 fsync하지 않아도 replication으로 내구성 확보.
자주 나는 장애 패턴
1. 디스크 꽉 참
증상: 쓰기 실패, broker 다운
log.retention.*가 topic 증가율보다 여유 있는지 확인- 특정 topic이 예상 외로 커졌는지 (파이프라인 버그 가능성)
- compacted topic인데 compaction이 안 돌고 있진 않은지 (
LogCleanerManager)
대응: 긴급엔 retention 축소 후 삭제 대기. 근본은 파티션 이동(kafka-reassign-partitions.sh) + 노드 추가.
2. Under-replicated 폭증
증상: UnderReplicatedPartitions > 0이 계속
- 네트워크 병목 (특히 follower fetch)
- 디스크 I/O 병목 (특히 한 브로커)
- follower GC pause
num.replica.fetchers부족
대응: 병목 노드 식별 → num.replica.fetchers 증대, rack 분포 재확인, 필요 시 파티션 재분배.
3. Consumer rebalance loop
증상: consumer group이 계속 rebalance 반복, lag이 톱니파
max.poll.interval.ms초과 — 처리 시간이 한계 넘음session.timeout.ms/heartbeat.interval.ms조합 이상- Eager assignor를 쓰고 있어서 스케일링마다 stop-the-world
- consumer OOM/크래시 반복
대응: cooperative sticky로 전환, max.poll.records 축소, 긴 작업은 별도 스레드+pause/resume, 인스턴스 메모리 확보.
4. Hot partition
증상: 특정 파티션에만 lag, 한 브로커 CPU/디스크만 100%
- Key가 편중됨 (예: 특정 tenant가 메시지 대부분)
- partitioner가 잘 못 분배함
대응: key 설계 재검토 (예: user_id → user_id:<random_salt>로 일부 분산), 파티션 수 조정, custom partitioner.
5. 프로듀서가 터짐 — “Broker failed the request due to duplicate sequence number”
- 주로 idempotent producer 쓰면서 retry 설정이 꼬였을 때
- producer 재시작 간격이
transactional.id.expiration.ms보다 길어서 coordinator가 다른 tx를 진행 중일 때 transactional.id를 인스턴스마다 다르게 부여 + 안정적 이름 전략 필요
6. ZK → KRaft 마이그레이션 실패
- 절차 건너뛰면 cluster id 불일치
- 공식 문서의 단계대로. production 이전엔 staging에서 반드시 리허설
- 롤백 경로 사전 테스트
운영 도구
공식 CLI
# 파티션 재분배 계획 생성
kafka-reassign-partitions.sh --bootstrap-server ... --generate ...
# 실행
kafka-reassign-partitions.sh --bootstrap-server ... --execute --reassignment-json-file plan.json
# consumer lag
kafka-consumer-groups.sh --bootstrap-server ... --describe --group <g>
# topic 정책 변경 (retention 등)
kafka-configs.sh --bootstrap-server ... --alter --entity-type topics --entity-name orders \
--add-config retention.ms=86400000
# under-replicated partition 한 방 확인
kafka-topics.sh --bootstrap-server ... --describe --under-replicated-partitions
UI/모니터링
- Kafka UI (provectus) — 무료, 가볍고 실무에 충분
- Confluent Control Center — 상용, 기능 풍부
- AKHQ — 오픈소스 UI
- CMAK (구 Kafka Manager) — 전통적이지만 관리 중심
로그 compaction 주의
Compacted topic(cleanup.policy=compact)은 다르게 동작:
- 같은 key의 오래된 값을 삭제
- tombstone(value=null)으로 명시적 삭제 표현
__consumer_offsets,__transaction_state, Streams의 changelog 등이 전부 compacted- Log cleaner 스레드가 따로 돌아서 compact 수행 — 밀리면 디스크 폭주 원인
모니터링: LogCleanerRunning, log-cleaner-work-queue-size
시리즈 정리
10주간 Kafka를 처음부터 끝까지 훑었다. 큰 그림:
- 개요 / 아키텍처 — Kafka가 뭐고, 내부 구조(log, partition)가 어떻게 생겼는지
- Producer / Consumer — API와 그 뒤의 튜닝 포인트
- Replication / Exactly-once — 분산 시스템으로서의 보장
- Streams / Connect — Kafka 위에 얹히는 도구
- Schema Registry — 포맷/스키마 관리
- 운영 — 모니터링, 튜닝, 장애 케이스
출발점에서 “로그인 실패했을 때 오프셋이 왜 꼬이지” 같은 단편 질문에 머물렀다면, 이제는 “이 파이프라인에서 지키고 싶은 보장이 뭐고, 거기에 맞는 acks/min.isr/consumer 전략/스키마 모드는 뭔가”로 질문이 바뀌었다. 개별 옵션이 아니라 조합으로 보게 되는 게 핵심.
앞으로 할 것:
- 직접 장애 시뮬레이션 (tc로 네트워크 지연, 디스크 꽉 채우기)
- Outbox 패턴으로 end-to-end EOS 구현해보기
- Kafka Streams로 실제 집계 파이프라인 만들기
시리즈 끝.
