브로커/프로듀서/컨슈머 핵심 메트릭, Prometheus/Grafana 대시보드, 알림 설계, 용량 계획, 비용 최적화, 실전 아키텍처까지 실시간 파이프라인의 프로덕션 운영을 학습합니다.
모니터링의 첫 단계는 무엇을 측정할 것인가를 정의하는 것입니다. Kafka의 각 구성 요소별 핵심 메트릭을 살펴보겠습니다.
| 메트릭 | 의미 | 위험 신호 |
|---|---|---|
UnderReplicatedPartitions | ISR이 불완전한 파티션 수 | 0 초과 → 레플리케이션 지연 |
OfflinePartitionsCount | 리더가 없는 파티션 수 | 0 초과 → 즉시 대응 |
ActiveControllerCount | 활성 컨트롤러 수 | 1이 아니면 문제 |
RequestHandlerAvgIdlePercent | 요청 핸들러 유휴율 | 30% 미만 → 과부하 |
NetworkProcessorAvgIdlePercent | 네트워크 프로세서 유휴율 | 30% 미만 → 과부하 |
TotalTimeMs (Produce/Fetch) | 요청 처리 총 시간 | P99 급증 → 성능 문제 |
LogFlushLatency | 디스크 쓰기 지연 | 급증 → 디스크 I/O 병목 |
BytesInPerSec / BytesOutPerSec | 입출력 처리량 | 급변 → 트래픽 이상 |
[즉시 대응]
- OfflinePartitionsCount > 0 → 파티션에 접근 불가, 데이터 유실 위험
- ActiveControllerCount != 1 → 컨트롤러 장애, 클러스터 관리 불가
[주의 관찰]
- UnderReplicatedPartitions > 0 → 레플리케이션 지연, 내구성 저하
- RequestHandlerAvgIdlePercent < 30% → 브로커 과부하
[추세 분석]
- BytesInPerSec 증가 추세 → 용량 계획 필요
- LogFlushLatency 점진적 증가 → 디스크 교체 검토| 메트릭 | 의미 | 위험 신호 |
|---|---|---|
record-send-rate | 초당 전송 레코드 수 | 급감 → 프로듀서 장애 |
record-error-rate | 초당 전송 실패 수 | 0 초과 → 전송 실패 발생 |
record-retry-rate | 초당 재시도 수 | 지속적 증가 → 브로커 문제 |
request-latency-avg | 평균 전송 지연 | 급증 → 네트워크/브로커 문제 |
batch-size-avg | 평균 배치 크기 | 너무 작으면 비효율 |
compression-rate-avg | 압축률 | 1에 가까우면 압축 미적용 |
buffer-available-bytes | 사용 가능한 버퍼 | 0 → 프로듀서 블로킹 |
| 메트릭 | 의미 | 위험 신호 |
|---|---|---|
records-lag | 파티션별 처리 지연 레코드 수 | 지속 증가 → 처리 속도 부족 |
records-lag-max | 최대 처리 지연 | 급증 → 특정 파티션 병목 |
records-consumed-rate | 초당 소비 레코드 수 | 0 → 소비 중단 |
commit-rate | 오프셋 커밋 빈도 | 급감 → 처리 지연 |
rebalance-rate | 리밸런싱 빈도 | 잦은 리밸런싱 → 불안정 |
fetch-latency-avg | 평균 fetch 지연 | 급증 → 브로커 응답 지연 |
**Consumer Lag(컨슈머 랙)**은 실시간 파이프라인에서 가장 중요한 단일 메트릭입니다. 컨슈머 랙이 지속적으로 증가하면 파이프라인이 유입 속도를 따라가지 못하는 것이며, 이는 데이터 지연의 직접적 원인입니다. 랙 모니터링 없이 실시간 파이프라인을 운영하는 것은 속도계 없이 운전하는 것과 같습니다.
| 메트릭 | 의미 | 위험 신호 |
|---|---|---|
numRecordsInPerSecond | 초당 입력 레코드 수 | 급감 → 소스 문제 |
numRecordsOutPerSecond | 초당 출력 레코드 수 | 입력 대비 급감 → 처리 병목 |
isBackPressured | 백프레셔 발생 여부 | true → 하류 병목 |
checkpointDuration | 체크포인트 소요 시간 | 급증 → 상태 크기 증가 |
checkpointFailureCount | 체크포인트 실패 횟수 | 0 초과 → 복구 위험 |
lastCheckpointSize | 마지막 체크포인트 크기 | 급증 → 상태 관리 필요 |
numberOfFailedCheckpoints | 연속 실패 수 | 누적 → 즉시 대응 |
currentInputWatermark | 현재 워터마크 | 정체 → 이벤트 도착 지연 |
Flink는 내장 웹 UI를 통해 실시간 모니터링을 제공합니다. 각 오퍼레이터의 처리량, 백프레셔 상태, 체크포인트 이력을 시각적으로 확인할 수 있습니다.
Flink Dashboard (기본: http://jobmanager:8081)
├── Overview: 실행 중인 작업, 슬롯 현황
├── Running Jobs
│ ├── Job Graph: DAG 시각화, 오퍼레이터별 처리량
│ ├── Checkpoints: 체크포인트 이력, 크기, 소요 시간
│ ├── Backpressure: 오퍼레이터별 백프레셔 수준
│ └── Metrics: 상세 메트릭 조회
└── Task Managers: 리소스 사용량lowercaseOutputName: true
lowercaseOutputLabelNames: true
rules:
# 브로커 토픽 메트릭
- pattern: kafka.server<type=BrokerTopicMetrics, name=(.+), topic=(.+)><>Count
name: kafka_server_brokertopicmetrics_$1_total
labels:
topic: $2
# 파티션 관련 메트릭
- pattern: kafka.server<type=ReplicaManager, name=(.+)><>Value
name: kafka_server_replicamanager_$1
# 요청 처리 시간
- pattern: kafka.network<type=RequestMetrics, name=(.+), request=(.+)><>Count
name: kafka_network_requestmetrics_$1_total
labels:
request: $2
# 컨슈머 그룹 메트릭
- pattern: kafka.server<type=FetcherLagMetrics, name=(.+), clientId=(.+), topic=(.+), partition=(.+)><>Value
name: kafka_server_fetcherlagmetrics_$1
labels:
client_id: $2
topic: $3
partition: $4# flink-conf.yaml
metrics.reporter.prom.factory.class: org.apache.flink.metrics.prometheus.PrometheusReporterFactory
metrics.reporter.prom.port: 9249효과적인 대시보드는 계층적으로 구성합니다.
Level 1 — 개요 대시보드
파이프라인 전체의 건강 상태를 한눈에 파악합니다.
Level 2 — 컴포넌트 대시보드
개별 컴포넌트의 상세 메트릭입니다.
[Kafka 대시보드]
Row 1: 브로커 현황
- 활성 브로커 수 | UnderReplicated 파티션 | 컨트롤러 상태
Row 2: 처리량
- Messages In/sec (토픽별) | Messages Out/sec (토픽별)
- Bytes In/sec | Bytes Out/sec
Row 3: 지연 시간
- Produce 요청 P99 지연 | Fetch 요청 P99 지연
- LogFlush 지연
Row 4: 리소스
- 디스크 사용량 (브로커별) | 네트워크 처리량 | CPU 사용률[Flink 대시보드]
Row 1: 작업 현황
- 작업 상태 | 업타임 | 재시작 횟수
Row 2: 처리량
- 오퍼레이터별 Records In/Out
- 종단간 지연 (이벤트 시간 - 처리 시간)
Row 3: 체크포인트
- 체크포인트 소요 시간 | 체크포인트 크기 | 실패 횟수
Row 4: 백프레셔
- 오퍼레이터별 백프레셔 비율효과적인 알림은 다음 원칙을 따릅니다.
groups:
- name: kafka-critical
rules:
# P1: 즉시 대응
- alert: KafkaOfflinePartitions
expr: kafka_server_replicamanager_offlinepartitionscount > 0
for: 1m
labels:
severity: critical
annotations:
summary: "오프라인 파티션 감지"
description: "{{ $value }}개 파티션에 리더가 없습니다. 데이터 접근 불가."
runbook: "https://wiki.internal/runbook/kafka-offline-partitions"
- alert: KafkaConsumerLagCritical
expr: sum(kafka_consumer_lag) by (consumer_group) > 100000
for: 5m
labels:
severity: critical
annotations:
summary: "컨슈머 랙 임계치 초과"
description: "컨슈머 그룹 {{ $labels.consumer_group }}의 랙이 {{ $value }}입니다."
- name: kafka-warning
rules:
# P2: 업무 시간 대응
- alert: KafkaUnderReplicatedPartitions
expr: kafka_server_replicamanager_underreplicatedpartitions > 0
for: 10m
labels:
severity: warning
annotations:
summary: "언더레플리케이션 파티션 감지"
description: "{{ $value }}개 파티션의 레플리케이션이 불완전합니다."
- alert: KafkaDiskUsageHigh
expr: kafka_log_size_bytes / kafka_log_max_size_bytes > 0.8
for: 30m
labels:
severity: warning
annotations:
summary: "디스크 사용량 80% 초과"
- name: flink-critical
rules:
- alert: FlinkCheckpointFailing
expr: flink_jobmanager_job_numberOfFailedCheckpoints > 3
for: 5m
labels:
severity: critical
annotations:
summary: "Flink 체크포인트 연속 실패"
description: "체크포인트가 연속 실패하고 있습니다. 장애 복구가 불가능해질 수 있습니다."
- alert: FlinkJobNotRunning
expr: flink_jobmanager_job_uptime == 0
for: 2m
labels:
severity: critical
annotations:
summary: "Flink 작업 중단"모든 Critical 알림에는 Runbook 링크를 포함하세요. 새벽 3시에 호출을 받은 당직자가 문서 없이 문제를 해결하는 것은 어렵습니다. Runbook에는 문제 확인 방법, 일반적 원인, 단계별 해결 절차를 기록합니다.
[입력 데이터]
- 일일 메시지 수: 1억 건
- 평균 메시지 크기: 1KB
- 보존 기간: 7일
- 레플리카 팩터: 3
[산출]
- 일일 데이터량: 100M x 1KB = 100GB
- 7일 보존: 100GB x 7 = 700GB
- 레플리카: 700GB x 3 = 2.1TB
- 안전 마진 (30%): 2.1TB x 1.3 = 2.73TB
→ 브로커 3대, 각 1TB 디스크면 여유 있음
→ 성장률 고려 시 각 2TB 권장[입력 데이터]
- 초당 메시지: 10,000 msg/sec
- 상태 크기: 윈도우 5분, 키 100만 개
- 체크포인트 간격: 30초
[산출]
- TaskManager 당 처리 능력: ~3,000 msg/sec (경험치, 로직 복잡도에 따라 상이)
- 필요 병렬도: 10,000 / 3,000 = 4 (여유 포함 6)
- 상태 메모리: 키 100만 x 상태 크기 100B = 100MB (RocksDB 사용 시 디스크)
- TaskManager 메모리: 4GB~8GB (상태 + 네트워크 버퍼 + 프레임워크 오버헤드)
→ TaskManager 3대, 각 2슬롯 (총 6 병렬도)
→ 메모리: 각 8GB| 지표 | 확장 시점 |
|---|---|
| 컨슈머 랙 | 지속적 증가 추세 (30분 이상) |
| CPU 사용률 | 평균 70% 초과 |
| 디스크 사용률 | 80% 초과 |
| 네트워크 대역폭 | 70% 초과 |
| 체크포인트 시간 | 체크포인트 간격의 50% 초과 |
1. 데이터 보존 기간 최적화
# 토픽별 보존 기간을 용도에 맞게 차등 설정
kafka-configs.sh --alter --topic hot-data \
--add-config retention.ms=86400000 # 1일 (실시간 처리용)
kafka-configs.sh --alter --topic warm-data \
--add-config retention.ms=604800000 # 7일 (단기 분석용)
kafka-configs.sh --alter --topic audit-log \
--add-config retention.ms=-1 # 무제한 (감사 로그)2. 압축으로 저장 공간 절약
# 토픽 수준 압축 설정
kafka-configs.sh --alter --topic orders \
--add-config compression.type=zstd
# Compacted 토픽: 키별 최신 값만 유지
kafka-configs.sh --alter --topic user-profiles \
--add-config cleanup.policy=compact3. 티어드 스토리지(Tiered Storage)
오래된 세그먼트를 비용이 낮은 스토리지(S3)로 자동 이전합니다. 로컬 디스크에는 최신 데이터만 유지하여 비용을 절감합니다.
StateTtlConfig ttlConfig = StateTtlConfig.newBuilder(Time.hours(1))
.setUpdateType(StateTtlConfig.UpdateType.OnCreateAndWrite)
.setStateVisibility(StateTtlConfig.StateVisibility.NeverReturnExpired)
.cleanupFullSnapshot() // 체크포인트 시 만료 상태 정리
.build();
ValueStateDescriptor<UserSession> descriptor =
new ValueStateDescriptor<>("session", UserSession.class);
descriptor.enableTimeToLive(ttlConfig);비용 최적화의 핵심은 데이터의 온도(hotness)에 따른 차등 관리입니다. 실시간 처리에 필요한 "뜨거운" 데이터는 빠른 저장소(로컬 SSD, 메모리)에, 분석용 "미지근한" 데이터는 S3 같은 객체 스토리지에, 감사용 "차가운" 데이터는 Glacier 같은 아카이브 스토리지에 배치합니다.
이 시리즈에서 학습한 모든 기술을 조합한 프로덕션 아키텍처를 살펴보겠습니다.
이 아키텍처의 각 구성 요소가 시리즈의 어떤 장에서 다뤄졌는지 정리하면 다음과 같습니다.
| 구성 요소 | 관련 장 | 핵심 포인트 |
|---|---|---|
| Kafka (KRaft) | 3장 | ZooKeeper 없는 메타데이터 관리 |
| 프로듀서/컨슈머 | 4장 | Exactly-once, DLQ |
| Kafka Connect | 5장 | 코드 없는 데이터 통합 |
| Apache Flink | 6장 | 상태 기반 스트림 처리, 체크포인팅 |
| Spark Streaming | 7장 | 배치-스트리밍 통합 (대안) |
| Debezium CDC | 8장 | WAL 기반 실시간 변경 캡처 |
| Schema Registry | 9장 | 스키마 호환성 관리 |
| 신뢰성 설계 | 10장 | Exactly-once, 멱등성, 백프레셔 |
| 모니터링 | 11장 (본 장) | Prometheus/Grafana, 알림 |
프로덕션 배포 전에 확인해야 할 핵심 항목을 체크리스트로 정리합니다.
11장에 걸쳐 실시간 데이터 파이프라인의 이론과 실전을 다루었습니다. 이벤트 드리븐 아키텍처의 기초부터 Kafka, Flink, CDC, 스키마 관리, 신뢰성 설계, 프로덕션 운영까지 파이프라인의 전체 수명 주기를 살펴보았습니다.
실시간 데이터 파이프라인은 단순히 도구를 조합하는 것이 아닙니다. 비즈니스 요구사항을 정확히 이해하고, 적절한 기술을 선택하며, 장애에 대비한 설계를 하고, 지속적으로 모니터링하고 개선하는 전체 과정이 중요합니다.
이 시리즈가 실시간 데이터 파이프라인을 설계하고 운영하는 데 실질적인 도움이 되기를 바랍니다.
기술은 빠르게 진화합니다. Kafka의 KRaft 모드, Flink CDC의 발전, 레이크하우스의 스트리밍 통합 등 새로운 변화를 지속적으로 팔로우하세요. 공식 문서, 커뮤니티 블로그, 컨퍼런스 발표가 최신 동향을 파악하는 가장 좋은 자료입니다.
이 글이 도움이 되셨나요?
관련 주제 더 보기
At-least-once/At-most-once/Exactly-once 비교, Kafka 트랜잭션과 Flink 체크포인트의 조합, 멱등성 설계, DLQ, 백프레셔, 장애 복구 전략까지 프로덕션 신뢰성을 학습합니다.
스키마 진화의 필요성, Confluent Schema Registry, Avro/Protobuf/JSON Schema 비교, 호환성 규칙, 데이터 계약 개념까지 스키마 관리 전략을 체계적으로 학습합니다.
CDC의 원리와 WAL 기반 변경 캡처, Debezium 아키텍처, PostgreSQL/MySQL CDC 실습, Flink CDC 3.6, 아웃박스 패턴, 이벤추얼 컨시스턴시까지 데이터 통합의 핵심을 학습합니다.