실시간 데이터 파이프라인에서 컨슈머 처리 속도가 프로듀서의 발행 속도를 따라가지 못하면 데이터 지연이 발생합니다. 이는 서비스의 실시간성을 파괴하고 비즈니스 의사결정에 치명적인 오류를 초래합니다.
이 글은 Prometheus 메트릭을 활용해 Consumer Lag을 정밀하게 감지하고, 서비스 중단 없이 파티션을 스케일 아웃하여 처리량을 확보하는 실무 아키텍처를 제시합니다.
TL;DR — Consumer Lag은 Kafka Lag Exporter와 Prometheus로 모니터링하며, 지연 발생 시 컨슈머 수와 파티션 수를 1:1 비율로 확장하여 병렬 처리량을 즉시 개선해야 합니다.
1. Kafka Consumer Lag의 기술적 정의
💡 비유로 이해하기: 맛집 대기 줄을 상상하십시오. 입구에서 번호표를 뽑는 손님(Producer)은 계속 늘어나는데, 테이블(Consumer)이 부족해 손님이 들어가지 못하고 밖에서 기다리는 시간의 차이가 바로 Lag입니다.
Kafka Consumer Lag은 특정 토픽 파티션의 최신 데이터 오프셋(Log End Offset)과 컨슈머 그룹이 마지막으로 읽은 오프셋(Current Offset) 사이의 거리입니다. 최신 버전 3.7.0 기준에서도 Lag은 시스템 부하를 측정하는 가장 핵심적인 지표로 작동합니다.
단순히 메시지 수가 쌓이는 것보다, "가장 오래된 메시지가 처리되기까지 걸리는 시간"인 Max Lag Time이 중요합니다. 메시지 유입량이 일시적으로 튀는 Burst traffic 상황에서 Lag이 선형적으로 증가한다면 시스템 처리 용량이 한계에 도달했음을 의미합니다.
2. 지연 모니터링이 필요한 실무 시나리오
이벤트 세일이나 마케팅 푸시 발송 시 프로듀서의 처리량이 평소보다 10배 이상 급증할 때 발생합니다. 컨슈머 내부 로직의 DB I/O 병목이나 외부 API 호출 지연이 겹치면 Lag은 기하급수적으로 늘어납니다. 이때 모니터링이 없다면 데이터 누락이 발생해도 인지하지 못하는 장애로 이어집니다.
컨슈머 그룹 내 특정 인스턴스가 비정상 종료되거나 네트워크 이슈로 인해 좀비 상태가 되는 경우에도 Lag이 발생합니다. 파티션 할당이 특정 컨슈머에게 몰리는 편중 현상을 감지하려면 각 파티션별 Lag 수치를 실시간으로 추적해야 합니다.
3. Prometheus로 Lag 감지 및 알람 구축하는 법
Kafka 자체 메트릭보다 Kafka Lag Exporter를 별도로 운영하는 방식이 효율적입니다. 클러스터 외부에서 컨슈머 그룹의 오프셋을 직접 조회하므로 브로커 부하를 줄이면서 정확한 데이터를 얻습니다.
Step 1. Kafka Lag Exporter 설정
Prometheus가 스크랩할 수 있도록 Exporter를 배포합니다. `application.conf` 파일에서 모니터링할 클러스터 정보를 설정합니다.
kafka-lag-exporter {
reporters.prometheus.port = 8000
clusters = [
{
name = "production-cluster"
bootstrap-brokers = "kafka-1:9092,kafka-2:9092"
}
]
}
Step 2. Prometheus AlertRule 정의
특정 컨슈머 그룹의 Lag이 100,000을 초과하고 5분간 유지될 경우 알람을 발생시키는 PromQL 예시입니다.
groups:
- name: KafkaAlerts
rules:
- alert: HighConsumerLag
expr: sum by (group) (kafka_consumergroup_group_lag) > 100000
for: 5m
labels:
severity: critical
annotations:
summary: "Consumer Group {{ $labels.group }} 지연 발생"
Step 3. 그라파나 대시보드 시각화
`kafka_consumergroup_group_max_lag_seconds` 메트릭을 사용하여 실제 비즈니스에 영향을 주는 지연 시간을 초 단위로 시각화합니다. 임계치 300초(5분) 초과 시 대시보드 색상을 변경하여 가시성을 확보합니다.
4. 정적 할당 vs 동적 파티션 스케일 아웃 비교
Kafka는 파티션 수가 곧 병렬 처리의 단위입니다. 트래픽에 따라 파티션을 어떻게 관리할지 결정해야 합니다.
| 비교 기준 | 정적 최대 할당 (Over-provisioning) | 동적 스케일 아웃 (On-demand) |
|---|---|---|
| 리소스 효율 | 낮음 (유휴 자원 발생) | 높음 (필요 시 확장) |
| 관리 복잡도 | 낮음 (설정 유지) | 높음 (스크립트/자동화 필요) |
| 장애 대응 속도 | 매우 빠름 (컨슈머만 늘리면 됨) | 중간 (파티션 확장 시간 소요) |
| 적합 규모 | 예측 가능한 트래픽 | 예측 불가능한 폭증 트래픽 |
트래픽 변동폭이 크다면 처음부터 파티션을 넉넉히(예: 예상치의 3배) 잡는 정적 방식이 유리하며, 비용 최적화가 중요하다면 `kafka-topics.sh`를 활용한 동적 확장을 선택합니다.
5. 리밸런스 폭풍과 성능 저하 주의사항
⚠️ 가장 자주 하는 실수: 파티션을 늘린다고 해서 즉시 성능이 좋아지지 않습니다. 컨슈머 그룹 내의 인스턴스 수가 파티션 수보다 적으면 남는 파티션은 놀게 됩니다.
파티션을 추가하면 전체 컨슈머 그룹이 중지되고 파티션을 다시 할당하는 Rebalance가 발생합니다. 이 과정에서 메시지 처리가 일시 중단되며, 파티션 수가 수천 개일 경우 리밸런스 시간이 수 분까지 길어지는 '리밸런스 폭풍' 현상이 나타납니다.
에러 메시지별 해결법
Error: CommitFailedException: Commit cannot be completed since the group has already rebalanced.
Cause: 컨슈머 처리 로직이 max.poll.interval.ms보다 길어 그룹에서 축출됨.
Solution: 처리 로직 최적화 또는 max.poll.records를 줄여 한 번에 가져오는 양 조절.
6. 실무 엔지니어를 위한 튜닝 팁
처리 성능을 높이려면 컨슈머의 `fetch.min.bytes`를 1MB 정도로 설정하여 한 번의 네트워크 요청으로 더 많은 데이터를 가져오게 합니다. 이는 CPU 사용량을 낮추고 처리량을 약 15% 개선합니다.
파티션 확장 시 키(Key) 기반 메시지 배포를 사용 중이라면 주의하십시오. 파티션 개수가 변하면 해시 결과값이 달라져 동일 키 메시지가 순서대로 처리되지 않을 수 있습니다. 순서가 중요하다면 확장 대신 컨슈머 내부에서 멀티스레딩 처리를 검토하십시오.
📌 핵심 요약
- Consumer Lag은 Kafka Lag Exporter를 통해 지연 시간 중심으로 모니터링한다.
- 파티션 스케일 아웃은 컨슈머 인스턴스 증설과 동시에 수행해야 효과가 있다.
- 리밸런스 시간을 최소화하기 위해 Cooperative Sticky Assignor 설정을 권장한다.
Frequently Asked Questions
Q. 파티션 개수는 무조건 많을수록 좋나요?
A. 아닙니다. 파티션이 너무 많으면 브로커의 파일 핸들 수가 증가하고 복구 시간이 길어집니다.
Q. 한 번 늘린 파티션을 다시 줄일 수 있나요?
A. Kafka 공식적으로 파티션 축소는 불가능합니다. 토픽을 새로 생성해야 합니다.
Q. Lag이 발생할 때 가장 먼저 확인해야 할 지표는?
A. 컨슈머 서버의 CPU 및 메모리 사용량과 Network I/O를 확인하십시오.
Post a Comment