학습 목표

이 도메인이 묻는 것

이 섹션의 전형적인 질문 형태
질문 형태실제로 확인하는 것
"ActiveControllerCount가 2다. 무슨 뜻인가?"이 값은 클러스터 전체에서 정확히 1이어야 함
"OfflinePartitionsCount가 5다. 먼저 무엇을 하는가?"리더 없는 파티션의 의미와 우선순위
"각 메트릭을 정상값과 연결하시오" (matching)0이어야 하는 것 vs 비율 지표 구분
"컨슈머 lag을 확인하는 방법을 모두 고르시오"CLI · 클라이언트 JMX · 브로커 측 오프셋
"RequestHandlerAvgIdlePercent가 0.05다"요청 처리 스레드 포화와 조치

핵심 개념 요약 — 4대 지표부터

Kafka 브로커는 JMX로 메트릭을 노출합니다. 수백 개가 있지만 대시보드 최상단에는 네 개만 두면 됩니다. 나머지는 이 네 개가 움직인 뒤에 봅니다.

핵심 메트릭 대시보드 — URP, UnderMinIsr, OfflinePartitions, ActiveController, 요청 처리 유휴율, 컨슈머 lag 여섯 개의 지표를 정상 기준과 함께 배치했습니다. UnderReplicatedPartitions 는 kafka.server type ReplicaManager 에 있고 정상값은 0 이며 0 이 아니면 ISR 이 전체 레플리카보다 적어 복제가 밀리는 상태입니다. UnderMinIsrPartitionCount 도 같은 빈에 있고 정상값 0 이며 min.insync.replicas 미달이므로 쓰기가 거부되기 시작합니다. OfflinePartitionsCount 는 kafka.controller type KafkaController 에 있고 정상값 0 이며 리더가 없는 파티션이 있으면 읽기와 쓰기가 모두 불가능합니다. ActiveControllerCount 는 클러스터 전체 합이 정확히 1 이어야 하고 0 이면 컨트롤러가 없고 2 이상이면 분열 상태입니다. RequestHandlerAvgIdlePercent 는 0 과 1 사이 값으로 0.3 이상을 권하며 0 에 가까우면 요청 처리 스레드가 포화된 것입니다. records-lag-max 는 컨슈머 쪽 지표로 얼마나 뒤처졌는지를 나타냅니다. IsrShrinksPerSec 는 UnderReplicated 보다 먼저 움직이는 조기 신호입니다. 핵심 메트릭 대시보드 — 이 여섯 개만 보면 클러스터 상태를 압니다 값은 정상 기준입니다. 하나라도 벗어나면 그 줄의 "의미"부터 확인하세요. UnderReplicatedPartitions kafka.server:type=ReplicaManager 정상: 0 ISR < 전체 레플리카 — 복제가 밀린다 UnderMinIsrPartitionCount kafka.server:type=ReplicaManager 정상: 0 ISR < min.insync.replicas — 쓰기 거부 시작 OfflinePartitionsCount kafka.controller:type=KafkaController 정상: 0 리더 없는 파티션 — 읽기·쓰기 모두 불가 ActiveControllerCount kafka.controller:type=KafkaController 정상: 클러스터 합 1 0 이면 컨트롤러 없음 · 2 이상이면 split brain RequestHandlerAvgIdlePercent kafka.server:type=KafkaRequestHandlerPool 정상: 0.3 이상 0 에 가까우면 요청 처리 스레드 포화 records-lag-max consumer-fetch-manager-metrics (클라이언트) 정상: 업무 기준 이내 컨슈머가 얼마나 뒤처졌는지 (클라이언트 지표) IsrShrinksPerSec 가 오르면 브로커 한 대가 뒤처지는 신호입니다 — UnderReplicated 보다 먼저 움직입니다. lag 은 브로커가 아니라 컨슈머 쪽 지표입니다 — CLI 로는 kafka-consumer-groups.sh --describe 로 봅니다. records-lag-max 의 전체 이름은 kafka.consumer:type=consumer-fetch-manager-metrics 입니다.
핵심 메트릭 대시보드 — URP · OfflinePartitions · ActiveController · RequestHandlerIdle 배치 예시
핵심 4대 지표
메트릭 정상값 이상 시 의미 먼저 볼 것
kafka.server:type=ReplicaManager,name=UnderReplicatedPartitions 0 ISR이 전체 레플리카보다 작은 파티션 수. 복제가 뒤처짐 어느 브로커가 ISR에서 빠졌는가, 디스크·네트워크, 남은 스로틀
kafka.controller:type=KafkaController,name=OfflinePartitionsCount 0 리더가 없는 파티션 수. 읽기·쓰기 모두 불가 가장 심각한 신호. 브로커 다운 수와 RF를 즉시 확인
kafka.controller:type=KafkaController,name=ActiveControllerCount 노드당 0 또는 1,
클러스터 합 정확히 1
합이 0이면 컨트롤러 없음(메타데이터 변경 불가), 2 이상이면 분열 의심 kafka-metadata-quorum.sh describe --status
kafka.server:type=KafkaRequestHandlerPool,name=RequestHandlerAvgIdlePercent 0~1 사이,
> 0.3 이상적
요청 처리 스레드가 포화. 모든 지연이 함께 나빠짐 num.io.threads(기본 8), 요청 급증 원인, 쿼터

URP와 UnderMinIsr — 헷갈리면 조치가 반대로 갑니다

ISR 관련 3개 메트릭의 정확한 조건
메트릭조건쓰기 가능?
UnderReplicatedPartitions |ISR| < |전체 레플리카| min.insync.replicas를 만족하면 가능
AtMinIsrPartitionCount |ISR| = min.insync.replicas 가능하지만 한 대만 더 빠지면 중단
UnderMinIsrPartitionCount |ISR| < min.insync.replicas 불가acks=all 쓰기가 거부됩니다

브로커 · 복제 메트릭

브로커 쪽 주요 메트릭
메트릭정상값의미
ReplicaManager,name=IsrShrinksPerSec
ReplicaManager,name=IsrExpandsPerSec
평시 0 브로커가 내려가면 축소, 복귀하면 확장이 일어납니다. 그 외에는 0이 기대값입니다.
ReplicaManager,name=FailedIsrUpdatesPerSec 0 ISR 갱신 실패. 컨트롤러 통신 문제를 의심합니다.
ReplicaFetcherManager,name=MaxLag,clientId=Replica produce 배치 크기에 비례 팔로워와 리더 사이의 최대 메시지 lag. 계속 커지면 복제가 못 따라갑니다.
FetcherLagMetrics,name=ConsumerLag,clientId=...,topic=...,partition=... 재할당 중 감소 추세 팔로워별 lag. 파티션 재할당이 진행되는지 판단하는 지표입니다.
ControllerStats,name=UncleanLeaderElectionsPerSec 항상 0 0이 아니면 데이터가 유실되었습니다. 사후 확인이 아니라 알림 대상입니다.
ControllerStats,name=UncleanLeaderElectionsPerSec 항상 0 ISR 밖 레플리카가 리더가 된 횟수. 리더 교체 빈도는 IsrShrinksPerSec/IsrExpandsPerSec로 봅니다. LeaderElectionRateAndTimeMs는 ZooKeeper 전용이라 KRaft에서 제거되었습니다.
KafkaController,name=PreferredReplicaImbalanceCount 평시 0 리더가 preferred가 아닌 파티션 수. 롤링 재시작 후 일시적으로 오릅니다.
SocketServer,name=NetworkProcessorAvgIdlePercent 0~1, > 0.3 네트워크 스레드 여유. 낮으면 num.network.threads(기본 3)를 검토합니다.
RequestMetrics,name=TotalTimeMs,request={Produce|FetchConsumer|FetchFollower} 워크로드 기준선 대비 요청 전체 시간. queue · local · remote · response send로 분해해서 봅니다.
RequestMetrics,name=RequestQueueTimeMs,... 낮게 유지 큐 대기 시간이 크면 처리 스레드 부족입니다.
SocketServer,name=ExpiredConnectionsKilledCount 재인증 사용 시 0 재인증하지 않고 만료된 연결을 계속 쓰는 클라이언트가 있다는 신호입니다.

컨트롤러 · 메타데이터 메트릭

KRaft 컨트롤러 메트릭
메트릭의미해석
KafkaController,name=MetadataErrorCount 이 노드가 메타데이터 로그 처리 중 만난 오류 수 0이 아니면 즉시 조사 대상입니다. 메타데이터 손상 가능성.
KafkaController,name=LastAppliedRecordLagMs 마지막으로 적용한 메타데이터 레코드의 지연 액티브 컨트롤러에서는 항상 0입니다. 스탠바이에서 이 값이 크면 뒤처진 것입니다.
KafkaController,name=LastAppliedRecordOffset
KafkaController,name=LastCommittedRecordOffset
적용·커밋된 메타데이터 오프셋 두 값의 차이가 계속 벌어지면 적용이 밀리고 있습니다.
KafkaController,name=TimedOutBrokerHeartbeatCount 브로커 하트비트 타임아웃 횟수 액티브 컨트롤러만 증가합니다. 늘어나면 브로커가 간헐적으로 끊기는 중입니다.

컨슈머 lag 측정 3방법

같은 lag을 세 경로로 볼 수 있고, 세 경로가 보는 것이 미묘하게 다릅니다. 이 차이가 시험 문항이 됩니다.

lag 측정 3방법 비교
방법 경로 장점 한계
① CLI kafka-consumer-groups.sh --describe --groupLAG 열 (= LOG-END-OFFSETCURRENT-OFFSET) 컨슈머에 손대지 않고 커밋된 오프셋 기준으로 즉시 확인 단발성 조회. 커밋 기준이라 처리했지만 아직 커밋 안 한 분량이 lag으로 보입니다
② 컨슈머 클라이언트 JMX kafka.consumer:type=consumer-fetch-manager-metrics,client-id={client-id}records-lag-max 컨슈머 실시간 상태. 대시보드·알림에 적합 컨슈머가 발행하는 메트릭입니다. 컨슈머가 죽으면 값 자체가 사라집니다
③ 브로커 측 오프셋 kafka.log:type=Log,name=LogEndOffset,topic=...,partition=...과 커밋 오프셋을 조합해 직접 계산 컨슈머가 없어도 토픽의 증가 속도를 볼 수 있습니다 lag을 얻으려면 커밋 오프셋을 따로 가져와 계산해야 합니다

필수 CLI 명령어

lag 확인 — 가장 자주 쓰는 명령
# 파티션별 CURRENT-OFFSET / LOG-END-OFFSET / LAG
bin/kafka-consumer-groups.sh --bootstrap-server localhost:9092 --describe --group order-workers

# 활성 멤버와 각 멤버가 가진 파티션 수
bin/kafka-consumer-groups.sh --bootstrap-server localhost:9092 \
    --describe --group order-workers --members

# 멤버별 실제 할당 파티션까지
bin/kafka-consumer-groups.sh --bootstrap-server localhost:9092 \
    --describe --group order-workers --members --verbose

# 그룹 상태 요약: 코디네이터 / 할당 전략 / STATE / 멤버 수
bin/kafka-consumer-groups.sh --bootstrap-server localhost:9092 \
    --describe --group order-workers --state
메타데이터 계층 상태 확인
# 리더 · 에폭 · HighWatermark · MaxFollowerLag · voter/observer
bin/kafka-metadata-quorum.sh --bootstrap-server localhost:9092 describe --status

# 노드별 LogEndOffset / Lag / LastFetchTimestamp / LastCaughtUpTimestamp / Status
bin/kafka-metadata-quorum.sh --bootstrap-server localhost:9092 describe --replication
복제 상태 판독 — URP를 파티션 단위로 좁히기
# Isr 가 Replicas 보다 짧은 파티션을 눈으로 찾습니다
bin/kafka-topics.sh --bootstrap-server localhost:9092 --describe

# 그룹 종류를 통합 조회 (Consumer / Share / Streams)
bin/kafka-groups.sh --bootstrap-server localhost:9092 --list
브로커 로그 레벨을 재시작 없이 올리기
# 특정 로거만 DEBUG 로 (조사 후 반드시 원복)
bin/kafka-configs.sh --bootstrap-server localhost:9092 --broker-logger 0 \
    --alter --add-config kafka.server.ReplicaManager=DEBUG

# 현재 로거 레벨 확인
bin/kafka-configs.sh --bootstrap-server localhost:9092 --broker-logger 0 --describe

반드시 외워야 할 값 — 임계값과 관련 설정

알림 임계값과 대응 설정
지표 임계 기준 움직였을 때 볼 설정 기본값
UnderReplicatedPartitions > 0 지속 시 경고 num.replica.fetchers / replica.lag.time.max.ms 1 / 30000
UnderMinIsrPartitionCount > 0 즉시 사고 min.insync.replicas 1
OfflinePartitionsCount > 0 즉시 사고 default.replication.factor, unclean.leader.election.enable 1 / false
ActiveControllerCount 합계 ≠ 1 즉시 사고 controller.quorum.fetch.timeout.ms 2000
UncleanLeaderElectionsPerSec > 0 즉시 사고 (유실 발생) unclean.leader.election.enable false
RequestHandlerAvgIdlePercent < 0.3 경고 num.io.threads, queued.max.requests 8 / 500
NetworkProcessorAvgIdlePercent < 0.3 경고 num.network.threads 3
PreferredReplicaImbalanceCount 지속적으로 > 0이면 경고 auto.leader.rebalance.enable, leader.imbalance.check.interval.seconds true / 300
LastAppliedRecordLagMs (스탠바이) 지속 증가 시 경고 metadata.log.dir 디스크 성능 null (첫 log.dirs)
컨슈머 lag 서비스 SLO 기준 max.poll.records, max.poll.interval.ms 500 / 300000

장애 시나리오와 대응

시나리오 1 — 컨슈머가 죽었는데 lag 알림이 오지 않았다

  1. 알림이 records-lag-max(컨슈머 발행 메트릭) 하나에만 걸려 있는지 확인합니다.
  2. 컨슈머가 죽으면 그 메트릭도 사라집니다. 값이 커지는 게 아니라 없어지는 것입니다.
  3. 즉시 조치: kafka-consumer-groups.sh --describe --group으로 현재 lag을 확인합니다.
  4. 구조 개선: 메트릭 부재 자체(no data)에 알림을 걸고, 동시에 브로커에서 커밋 오프셋 기준 lag을 주기적으로 수집합니다.
  5. 그룹의 활성 멤버 수(--members)에도 알림을 걸면 "컨슈머가 사라진 것"을 직접 감지할 수 있습니다.

시나리오 2 — 모든 요청 지연이 동시에 나빠졌다

  1. RequestHandlerAvgIdlePercent를 봅니다. 0.3 미만이면 처리 스레드가 포화입니다.
  2. RequestQueueTimeMs가 커졌는지 확인합니다. 큐 대기가 지연의 대부분이면 스레드 부족이 확정입니다.
  3. NetworkProcessorAvgIdlePercent도 함께 봅니다. 이쪽이 낮으면 네트워크 스레드가 원인입니다.
  4. 원인 트래픽을 특정합니다 — 쿼터 메트릭으로 사용자·클라이언트별 사용량을 봅니다.
  5. 단기 조치는 num.io.threads 상향(cluster-wide라 재시작 불필요), 중기 조치는 쿼터 부여입니다.

시나리오 3 — ActiveControllerCount 합계가 0이 되었다

  1. 즉시 kafka-metadata-quorum.sh --bootstrap-controller ... describe --status를 실행합니다.
  2. 리더가 없다면 쿼럼 과반이 살아 있는지 확인합니다. 과반을 잃으면 리더가 뽑히지 않습니다.
  3. 기존 파티션의 읽기·쓰기는 한동안 계속되지만 메타데이터 변경은 전부 실패합니다. 이 점을 관계자에게 먼저 알립니다.
  4. 컨트롤러 노드 간 네트워크를 확인합니다. controller.quorum.fetch.timeout.ms(기본 2000)를 넘기면 선거가 반복됩니다.
  5. MetadataErrorCount가 올라 있으면 메타데이터 손상 가능성이 있으므로, 노드를 다시 포맷하기 전에 describe --replication으로 과반의 데이터 보유를 확인합니다.

시나리오 4 — URP가 0으로 돌아오지 않는다

  1. 어느 브로커·파티션인지 kafka-topics.sh --describe로 좁힙니다.
  2. ReplicaFetcherManager MaxLag가 커지는 추세인지 봅니다. 커지면 복제가 뒤처지는 중입니다.
  3. 남아 있는 스로틀을 확인합니다. 재할당 후 --verify를 생략했다면 여기서 걸립니다.
  4. IsrShrinksPerSec/IsrExpandsPerSec가 반복되면 특정 브로커의 디스크·네트워크를 봅니다.
  5. num.replica.fetchers(기본 1)를 올려 팔로워 fetch 병렬성을 확보합니다.

자주 나오는 함정

관련 케이스 스터디

메트릭 전체 목록은 JMX 메트릭 치트시트, 운영 배경은 11장 운영 기초, lag 모니터링 실습은 예제 10에 있습니다. 이 지표들을 실제 조치로 잇는 방법은 Troubleshooting에서 다룹니다.

미니 퀴즈

메트릭 이름과 정상값 매칭이 중심입니다.

공식 문서 출처