Kafka

Kafka 운영 가이드 - 모니터링부터 장애 대응까지

백엔드 개발자 김승원 2026. 3. 31. 18:52

Kafka 운영, 왜 어려운가?

Apache Kafka는 대규모 실시간 데이터 파이프라인의 핵심 인프라로 자리 잡았습니다. 하지만 프로덕션 환경에서 Kafka를 안정적으로 운영하는 것은 단순히 클러스터를 띄우는 것과는 차원이 다른 문제입니다. Consumer Lag이 갑자기 치솟거나, 브로커가 다운되거나, 디스크가 가득 차는 상황에 빠르게 대응하려면 체계적인 모니터링과 장애 대응 전략이 필수입니다.

이 글에서는 실무에서 바로 적용할 수 있는 Kafka 운영 노하우를 모니터링, 장애 대응, 클러스터 관리 세 가지 축으로 정리합니다.

1. Consumer Lag 모니터링 - 운영의 첫 번째 관문

Consumer Lag은 프로듀서가 토픽에 쓴 최신 오프셋과 컨슈머가 실제로 읽은 오프셋의 차이를 의미합니다. Lag이 지속적으로 증가하면 데이터 처리 지연이 발생하고 있다는 신호이므로 가장 먼저 모니터링해야 할 지표입니다.

1-1. kafka-consumer-groups.sh로 Lag 확인

가장 기본적인 방법은 Kafka에 내장된 CLI 도구를 사용하는 것입니다.

# 특정 컨슈머 그룹의 Lag 확인
bin/kafka-consumer-groups.sh \
  --bootstrap-server kafka-broker1:9092 \
  --describe \
  --group my-consumer-group

# 출력 예시
# GROUP              TOPIC       PARTITION  CURRENT-OFFSET  LOG-END-OFFSET  LAG
# my-consumer-group  order-events  0          12340           12345           5
# my-consumer-group  order-events  1          9870            11200           1330
# my-consumer-group  order-events  2          15600           15602           2

위 결과에서 파티션 1의 Lag이 1330으로 비정상적으로 높습니다. 해당 파티션을 처리하는 컨슈머 인스턴스에 문제가 있을 가능성이 높으므로 즉시 조사가 필요합니다.

1-2. Burrow를 활용한 자동화된 Lag 모니터링

Burrow는 LinkedIn에서 개발한 오픈소스 Consumer Lag 모니터링 도구입니다. 단순히 Lag 수치만 보는 것이 아니라 Lag의 추세(trend)를 분석하여 상태를 판단합니다.

# Burrow 설정 (burrow.toml)
[zookeeper]
servers = ["zk1:2181", "zk2:2181", "zk3:2181"]

[kafka.my-cluster]
brokers = ["kafka1:9092", "kafka2:9092", "kafka3:9092"]

[httpserver.default]
address = ":8000"

# Burrow API로 컨슈머 그룹 상태 조회
curl http://localhost:8000/v3/kafka/my-cluster/consumer/my-consumer-group/lag

# 응답 예시
{
  "status": "OK",
  "complete": true,
  "partitions": [
    {"topic": "order-events", "partition": 0, "status": "OK"},
    {"topic": "order-events", "partition": 1, "status": "WARNING"},
    {"topic": "order-events", "partition": 2, "status": "OK"}
  ],
  "totallag": 1337
}

Burrow는 Lag 상태를 OK, WARNING, ERR, STOP으로 분류합니다. STOP은 컨슈머가 아예 커밋을 하지 않는 상태로, 컨슈머 프로세스가 죽었을 가능성이 높습니다.

2. Prometheus + JMX Exporter로 브로커 메트릭 수집

Kafka 브로커는 JMX를 통해 수백 가지 메트릭을 노출합니다. Prometheus JMX Exporter를 사용하면 이 메트릭을 Prometheus가 수집할 수 있는 형태로 변환할 수 있습니다.

2-1. JMX Exporter 설정

# jmx_exporter_config.yml
lowercaseOutputName: true
lowercaseOutputLabelNames: true
rules:
  # 브로커 요청 처리율
  - pattern: kafka.server<type=BrokerTopicMetrics, name=(MessagesInPerSec|BytesInPerSec|BytesOutPerSec)><>(Count|OneMinuteRate)
    name: kafka_server_brokertopicmetrics_$1_$2
    type: GAUGE

  # 요청 큐 사이즈
  - pattern: kafka.network<type=RequestChannel, name=RequestQueueSize>Value
    name: kafka_network_request_queue_size
    type: GAUGE

  # Under Replicated Partitions (매우 중요)
  - pattern: kafka.server<type=ReplicaManager, name=UnderReplicatedPartitions>Value
    name: kafka_server_under_replicated_partitions
    type: GAUGE

  # ISR Shrink/Expand Rate
  - pattern: kafka.server<type=ReplicaManager, name=(IsrShrinksPerSec|IsrExpandsPerSec)>Count
    name: kafka_server_replica_manager_$1
    type: COUNTER
# Kafka 브로커 시작 시 JMX Exporter 적용
export KAFKA_OPTS="-javaagent:/opt/jmx_exporter/jmx_prometheus_javaagent-0.20.0.jar=7071:/opt/jmx_exporter/jmx_exporter_config.yml"
bin/kafka-server-start.sh config/server.properties

2-2. 반드시 모니터링해야 할 핵심 메트릭

메트릭 설명 임계값
UnderReplicatedPartitions 복제가 뒤처진 파티션 수 0이 아니면 즉시 확인
ActiveControllerCount 클러스터의 활성 컨트롤러 수 정확히 1이어야 정상
RequestQueueSize 처리 대기 중인 요청 수 지속적으로 높으면 병목
LogFlushRateAndTimeMs 디스크 flush 소요 시간 급증 시 디스크 I/O 문제
NetworkProcessorAvgIdlePercent 네트워크 스레드 유휴율 30% 이하면 위험

3. Kafka UI로 클러스터 가시성 확보

Kafka-UI(현 Kafbat-UI)는 웹 기반의 Kafka 관리 도구로, 토픽, 컨슈머 그룹, 브로커 상태를 직관적으로 확인할 수 있습니다.

# docker-compose.yml
version: '3'
services:
  kafka-ui:
    image: provectuslabs/kafka-ui:latest
    ports:
      - "8080:8080"
    environment:
      KAFKA_CLUSTERS_0_NAME: production
      KAFKA_CLUSTERS_0_BOOTSTRAPSERVERS: kafka1:9092,kafka2:9092,kafka3:9092
      KAFKA_CLUSTERS_0_METRICS_PORT: 7071
      KAFKA_CLUSTERS_0_SCHEMAREGISTRY: http://schema-registry:8081
      # 읽기 전용 모드로 운영 환경 보호
      AUTH_TYPE: LOGIN_FORM
      SPRING_SECURITY_USER_NAME: admin
      SPRING_SECURITY_USER_PASSWORD: ${KAFKA_UI_PASSWORD}

운영 환경에서는 반드시 인증을 활성화하고, 토픽 삭제/생성 권한은 제한하는 것이 좋습니다.

4. 브로커 장애 대응 플레이북

4-1. 브로커 1대 다운 시 대응

Kafka는 복제(replication)를 통해 브로커 장애에 대한 내결함성을 제공합니다. replication.factor=3, min.insync.replicas=2로 설정되어 있다면 브로커 1대가 다운되어도 데이터 유실 없이 서비스가 지속됩니다.

# 1단계: Under Replicated Partitions 확인
bin/kafka-topics.sh --bootstrap-server kafka1:9092 \
  --describe --under-replicated-partitions

# 2단계: 리더 파티션 분포 확인
bin/kafka-topics.sh --bootstrap-server kafka1:9092 \
  --describe --topic order-events

# 3단계: 장애 브로커 복구 후 리더 리밸런싱
bin/kafka-leader-election.sh \
  --bootstrap-server kafka1:9092 \
  --election-type PREFERRED \
  --all-topic-partitions

# 4단계: 복구 확인
bin/kafka-broker-api-versions.sh \
  --bootstrap-server kafka1:9092,kafka2:9092,kafka3:9092

4-2. ISR(In-Sync Replica) 관련 장애

ISR이 줄어드는 현상은 팔로워 브로커가 리더를 따라가지 못한다는 의미입니다. 주요 원인과 대응법은 다음과 같습니다.

  • 네트워크 지연: 브로커 간 네트워크 대역폭 및 지연 확인
  • 디스크 I/O 병목: iostat으로 디스크 사용률 확인, SSD 교체 검토
  • replica.lag.time.max.ms 조정: 기본값 30초, 필요시 상향 (단, 너무 높이면 장애 감지 지연)
# 브로커 설정 조정 (server.properties)
replica.lag.time.max.ms=45000
num.replica.fetchers=4
replica.fetch.max.bytes=10485760

5. 파티션 리밸런싱과 클러스터 확장

5-1. 브로커 추가 시 파티션 재배치

새 브로커를 추가해도 기존 파티션이 자동으로 이동하지 않습니다. kafka-reassign-partitions.sh를 사용하여 수동으로 재배치해야 합니다.

# 1단계: 재배치 계획 생성을 위한 토픽 목록 (topics-to-move.json)
{
  "topics": [
    {"topic": "order-events"},
    {"topic": "payment-events"},
    {"topic": "user-activity"}
  ],
  "version": 1
}

# 2단계: 재배치 계획 생성 (새 브로커 4번 포함)
bin/kafka-reassign-partitions.sh \
  --bootstrap-server kafka1:9092 \
  --topics-to-move-json-file topics-to-move.json \
  --broker-list "1,2,3,4" \
  --generate

# 3단계: 생성된 계획을 파일로 저장 후 실행
bin/kafka-reassign-partitions.sh \
  --bootstrap-server kafka1:9092 \
  --reassignment-json-file reassignment-plan.json \
  --execute \
  --throttle 50000000  # 50MB/s로 네트워크 부하 제한

# 4단계: 진행 상황 확인
bin/kafka-reassign-partitions.sh \
  --bootstrap-server kafka1:9092 \
  --reassignment-json-file reassignment-plan.json \
  --verify

--throttle 옵션은 매우 중요합니다. 대량의 파티션을 재배치할 때 네트워크 대역폭을 과도하게 사용하면 기존 프로듀서/컨슈머 트래픽에 영향을 줄 수 있기 때문입니다. 재배치 완료 후에는 반드시 throttle을 해제해야 합니다.

6. Retention 설정과 디스크 관리

디스크 공간 부족은 Kafka 운영에서 자주 발생하는 문제입니다. retention 정책을 적절히 설정하여 예방해야 합니다.

# 토픽별 retention 설정
bin/kafka-configs.sh --bootstrap-server kafka1:9092 \
  --alter --entity-type topics --entity-name order-events \
  --add-config retention.ms=604800000  # 7일

# 크기 기반 retention (토픽 파티션당 최대 10GB)
bin/kafka-configs.sh --bootstrap-server kafka1:9092 \
  --alter --entity-type topics --entity-name user-activity \
  --add-config retention.bytes=10737418240

# 현재 토픽 설정 확인
bin/kafka-configs.sh --bootstrap-server kafka1:9092 \
  --describe --entity-type topics --entity-name order-events

# 브로커 레벨 기본 설정 (server.properties)
log.retention.hours=168
log.retention.bytes=-1
log.segment.bytes=1073741824
log.retention.check.interval.ms=300000

디스크 사용률 알림 설정 (Prometheus AlertManager)

# prometheus_alerts.yml
groups:
  - name: kafka_disk
    rules:
      - alert: KafkaDiskUsageHigh
        expr: (1 - node_filesystem_avail_bytes{mountpoint="/data/kafka"} / node_filesystem_size_bytes{mountpoint="/data/kafka"}) > 0.75
        for: 5m
        labels:
          severity: warning
        annotations:
          summary: "Kafka 디스크 사용률 75% 초과 ({{ $labels.instance }})"
      - alert: KafkaDiskUsageCritical
        expr: (1 - node_filesystem_avail_bytes{mountpoint="/data/kafka"} / node_filesystem_size_bytes{mountpoint="/data/kafka"}) > 0.90
        for: 2m
        labels:
          severity: critical
        annotations:
          summary: "Kafka 디스크 사용률 90% 초과 - 즉시 대응 필요 ({{ $labels.instance }})"

7. 운영 체크리스트 요약

마지막으로 Kafka 운영 시 주기적으로 점검해야 할 항목을 정리합니다.

주기 점검 항목 도구
실시간 Consumer Lag, UnderReplicatedPartitions Burrow, Prometheus
매일 디스크 사용률, 브로커 로그 에러 Grafana, ELK
매주 파티션 리더 분포 균형, 컨슈머 그룹 상태 Kafka-UI
매월 토픽 retention 정책 검토, 클러스터 용량 계획 수동 점검

Kafka 운영은 예방이 최선의 대응입니다. 체계적인 모니터링 체계를 구축하고, 장애 대응 플레이북을 사전에 준비해 두면 장애 발생 시에도 빠르게 복구할 수 있습니다. 위에서 소개한 도구와 설정을 자신의 환경에 맞게 조정하여 안정적인 Kafka 클러스터를 운영하시기 바랍니다.