이 페이지 구조

30초 트리아지

신고를 받으면 클러스터가 문제인지 클라이언트가 문제인지부터 가릅니다. 순서를 지키세요. 아래 네 명령이 전부 깨끗하면 클러스터는 정상이고 문제는 클라이언트 쪽입니다.

클러스터 건강 검진 — 위에서 아래로
export BS=localhost:9092

# 1) 읽기·쓰기가 아예 불가한 파티션 (최고 심각도)
bin/kafka-topics.sh --bootstrap-server $BS --describe --unavailable-partitions

# 2) acks=all 쓰기가 막힌 파티션
bin/kafka-topics.sh --bootstrap-server $BS --describe --under-min-isr-partitions

# 3) 복제가 뒤처진 파티션 (아직 쓰기는 됨)
bin/kafka-topics.sh --bootstrap-server $BS --describe --under-replicated-partitions

# 4) 컨트롤러 쿼럼이 살아 있는가
bin/kafka-metadata-quorum.sh --bootstrap-server $BS describe --status
트리아지 결과 해석
결과판정다음 단계
1번에 출력이 있다 클러스터 장애 · 최고 심각도. 해당 파티션은 읽기·쓰기 모두 불가 브로커 트리로. 모든 레플리카가 오프라인인지 확인
2번에만 출력이 있다 acks=all 프로듀서가 NotEnoughReplicasException을 받고 있습니다 죽은 브로커 복구가 정답. 급하면 min.insync.replicas 한시 하향(내구성 포기)
3번에만 출력이 있다 복제 지연. 여유가 줄었지만 서비스는 정상 롤링 재시작 중이면 정상입니다. 15분 이상 지속되면 조사
4번에서 리더가 없다 컨트롤러 쿼럼 문제. 메타데이터 변경이 전부 실패합니다 컨트롤러 노드의 디스크·네트워크·ActiveControllerCount 확인
전부 깨끗하다 클러스터는 정상. 클라이언트 또는 설정 문제입니다 컨슈머 트리 또는 프로듀서 트리

의사결정 트리 ① 컨슈머가 안 읽는다

트러블슈팅 결정 트리 — 컨슈머가 메시지를 읽지 않을 때 컨슈머가 읽지 않는 상황을 위에서 아래로 좁혀 가는 결정 트리입니다. 마름모는 판단, 사각형은 조치이며 각 판단에는 확인할 CLI 명령이 함께 적혀 있습니다. 첫째, 그룹에 멤버가 있는지 kafka-consumer-groups.sh --describe --members 로 확인합니다. 멤버가 없으면 프로세스 상태와 group.id, subscribe 대상을 봅니다. 둘째, LOG-END-OFFSET 이 멈춰 있으면 읽을 데이터가 없는 것이므로 프로듀서 쪽 문제입니다. 셋째, 그룹 상태가 PreparingRebalance 를 반복하면 리밸런스 루프이므로 max.poll.interval.ms 와 max.poll.records 를 조정합니다. 넷째, 컨슈머 수가 파티션 수보다 많으면 남는 컨슈머는 유휴 상태이므로 파티션을 늘립니다. 다섯째, LAG 이 0 인데 기대한 데이터가 없으면 새 group.id 와 auto.offset.reset=latest 조합으로 과거 데이터를 건너뛴 경우이므로 오프셋을 되돌립니다. 여섯째, isolation.level 이 read_committed 이면 진행 중인 트랜잭션이 LSO 를 막고 있을 수 있습니다. 마지막으로 권한 오류를 확인합니다. 컨슈머가 메시지를 읽지 않는다 마름모 = 판단 · 사각형 = 조치. 위에서 아래로 순서대로 좁혀 갑니다. 그룹에 멤버가 없다? --describe --members 컨슈머가 붙지 못한 상태 · 프로세스 생존 · group.id 오타 확인 · subscribe 대상 토픽 확인 · bootstrap.servers 확인 → D-101 아니오 LOG-END-OFFSET 이 안 늘어난다? kafka-get-offsets.sh 읽을 데이터 자체가 없다 · 프로듀서 쪽 문제 → D-121 · 토픽·파티션을 잘못 보고 있는지 확인 아니오 PreparingRebalance 반복? --describe --state 리밸런스 루프 · max.poll.records 를 줄인다 · max.poll.interval.ms 를 올린다 · 원인 분석은 D-111 (case02) 아니오 컨슈머 수 > 파티션 수? --describe --members 남는 컨슈머는 유휴 상태 · 한 파티션 = 한 컨슈머 · kafka-topics.sh --alter --partitions N · 파티션은 줄일 수 없다 아니오 LAG 0 인데 데이터가 없다? --describe --group G 과거 데이터를 건너뛴 상태 · 새 group.id + latest 조합 → D-110 · --reset-offsets --to-earliest --execute 아니오 isolation.level=read_committed? 컨슈머 설정 확인 트랜잭션이 LSO 를 막는 중 · 커밋 안 된 트랜잭션 뒤는 안 보임 · 커밋·중단 또는 타임아웃을 기다림 아니오 여기까지 모두 아니라면 kafka-acls.sh --list 권한을 확인한다 · TOPIC / GROUP_AUTHORIZATION_FAILED · 토픽 Read + 그룹 Read 둘 다 필요 모든 kafka-consumer-groups.sh 명령에는 --bootstrap-server 가 필요합니다. 원인은 대개 클라이언트 쪽입니다 — 브로커 장애부터 의심하지 마세요.
컨슈머가 읽지 못할 때의 분기 — 그룹에 멤버가 있는가 → lag이 늘어나는가 → 리밸런스 루프인가 → 오프셋이 잘못됐는가 → 권한·read_committed 문제인가
컨슈머 트리 — 위에서부터 순서대로 확인
#확인명령그렇다면
1 그룹에 멤버가 있는가 --describe --group G --members 없으면 애플리케이션이 죽었거나 group.id가 다릅니다. 배포 로그부터 확인
2 그룹 상태가 Stable인가 --describe --group G --state PreparingRebalance가 계속되면 리밸런스 루프입니다 → 4번으로
3 파티션 수 ≥ 컨슈머 수인가 --describe --group G --members --verbose 컨슈머가 더 많으면 남는 컨슈머는 아무 파티션도 받지 못합니다(정상 동작). 파티션을 늘리거나 Share Group을 검토
4 처리 시간이 max.poll.interval.ms를 넘는가 애플리케이션 로그에서 CommitFailedException 검색 넘으면 브로커가 멤버를 제외합니다 → max.poll.records를 줄이거나 max.poll.interval.ms를 늘리세요 (케이스 2)
5 lag이 있는데 진행이 없는가 --describe --group G를 10초 간격으로 두 번 CURRENT-OFFSET이 그대로면 poll 루프가 블록되어 있습니다. 스레드 덤프를 뜨세요
6 LAG이 -로 나오는가 --describe --group G 커밋된 오프셋이 없습니다. 새 그룹이거나 offsets.retention.minutes 만료 → auto.offset.reset이 결정합니다 (케이스 1)
7 데이터가 애초에 있는가 kafka-get-offsets.sh --topic T --time latest 모든 파티션이 0이면 프로듀서 문제입니다 → 프로듀서 트리
8 토픽에 데이터가 있는데 컨슈머만 못 읽는가 kafka-console-consumer.sh --topic T --from-beginning --max-messages 1 콘솔로는 읽힌다면 애플리케이션의 역직렬화·권한·isolation.level 문제입니다
9 read_committed를 쓰는가 컨슈머 설정 확인 그렇다면 멈춘 트랜잭션이 LSO를 막고 있을 수 있습니다 → kafka-transactions.sh find-hanging --topic T
10 권한이 있는가 kafka-acls.sh --list --topic T 컨슈머는 토픽 READ + 그룹 READ가 모두 필요합니다. 하나만 있으면 GroupAuthorizationException
11 쿼터에 걸려 있는가 JMX fetch-throttle-time-avg 0이 아니면 consumer_byte_rate 쿼터입니다. "브로커는 한가한데 컨슈머만 느림"의 흔한 원인
리밸런스 루프인지 확인하는 가장 빠른 방법
# 상태를 5초 간격으로 6번 — Stable 이 아닌 상태가 반복되면 리밸런스 루프
for i in $(seq 6); do
  bin/kafka-consumer-groups.sh --bootstrap-server $BS --describe --group my-group --state \
    | awk 'NR>1 { print strftime("%H:%M:%S"), $0 }'
  sleep 5
done

의사결정 트리 ② 프로듀서 전송 실패

트러블슈팅 결정 트리 — 프로듀서 전송이 실패할 때 프로듀서 전송 실패를 예외 유형에서 출발해 좁혀 가는 결정 트리입니다. 마름모는 판단, 사각형은 조치입니다. RecordTooLargeException 이면 프로듀서 max.request.size 와 브로커·토픽 쪽 상한을 함께 확인합니다. NotEnoughReplicas 계열이면 ISR 이 min.insync.replicas 보다 적은 것이므로 --under-min-isr-partitions 로 확인합니다. TimeoutException 이면 delivery.timeout.ms 예산 안에서 전송을 마치지 못한 것이므로 메타데이터 조회 경로와 브로커 응답 지연을 봅니다. send 호출 자체가 블록되면 buffer.memory 가 고갈되어 max.block.ms 를 기다리는 상황입니다. TOPIC_AUTHORIZATION_FAILED 면 쓰기 권한을, UnknownTopicOrPartitionException 이면 토픽 존재 여부와 auto.create.topics.enable 을 확인합니다. 마지막으로 순서가 어긋나면 멱등성 설정과 max.in.flight.requests.per.connection 을 점검합니다. 프로듀서 전송이 실패한다 먼저 예외 유형을 봅니다. 예외 이름이 곧 원인 분류입니다. RecordTooLargeException? kafka-configs.sh 크기 상한 불일치 · 프로듀서 max.request.size 1048576 · 브로커 message.max.bytes 1048588 · 토픽까지 함께 올린다 → D-119 아니오 NotEnoughReplicas 계열? --under-min-isr ISR 이 min.insync 미달 · 브로커 장애 또는 복제 지연 · ISR 회복을 기다린다 → D-115 아니오 TimeoutException? delivery.timeout.ms 확인 전송 예산을 넘겼다 · 메타데이터를 못 받았을 수 있다 · advertised.listeners 오설정 → D-101 아니오 send() 가 블록된다? buffer-available-bytes buffer.memory 고갈 · max.block.ms(60000) 뒤 예외 · 생산 속도 > 전송 속도 아니오 TOPIC_AUTHORIZATION_FAILED? kafka-acls.sh --list 쓰기 권한이 없다 · 토픽 Write 권한 필요 · 트랜잭션은 TransactionalId 도 필요 아니오 UnknownTopicOrPartition? kafka-topics.sh --list 토픽이 없다 · 자동 생성이라도 첫 전송은 실패 가능 · 토픽을 미리 만든다 아니오 순서가 어긋난다? producer 설정 확인 재시도로 순서가 뒤집혔다 · 멱등성 false + max.in.flight > 1 · 기본값(true · 5)이면 순서 보장 프로듀서 예외는 재시도 가능과 불가능으로 갈립니다 — RecordTooLarge 는 재시도해도 성공하지 않습니다. 콜백 onCompletion() 의 exception 을 꼭 로깅하세요. 예외 이름을 못 보면 판단을 시작할 수 없습니다.
프로듀서 전송이 실패할 때의 분기 — 예외가 무엇인가 → 재시도 가능(retriable)인가 → 크기·ISR·권한·타임아웃 중 무엇인가 → 멱등성·트랜잭션 상태가 깨졌는가
프로듀서 트리 — 예외에서 출발합니다
#증상 · 예외확인조치
1 TimeoutException: Topic not present in metadata 토픽이 존재하는가, bootstrap.servers가 맞는가 토픽 생성 또는 오타 수정. auto.create.topics.enable=false면 자동 생성되지 않습니다
2 TimeoutException: Expiring N record(s) delivery.timeout.ms가 만료됐습니다. 브로커가 응답을 못 주고 있습니다 URP·ISR 확인. 네트워크·advertised.listeners 확인. 버퍼가 가득 찼는지도 확인
3 RecordTooLargeException 네 곳의 크기 설정 프로듀서 max.request.size, 토픽 max.message.bytes, 브로커 message.max.bytes, 브로커 replica.fetch.max.bytes전부 맞춰야 합니다 (케이스 10)
4 NotEnoughReplicasException --describe --under-min-isr-partitions ISR이 min.insync.replicas 미달입니다. 브로커 복구가 정답 (케이스 6)
5 TopicAuthorizationException kafka-acls.sh --list --topic T 프로듀서는 WRITE + DESCRIBE가 필요합니다. --producer 편의 옵션이 함께 부여합니다
6 ClusterAuthorizationException (멱등 프로듀서) 멱등성이 켜져 있는가 (4.x 기본 true) 구버전 브로커에서는 Cluster IdempotentWrite 권한이 필요합니다. --idempotent 옵션 참고
7 ConfigException (기동 시) 설정 조합이 모순되지 않는가 대표적으로 enable.idempotence=true + max.in.flight.requests.per.connection > 5, 또는 acksall이 아닌 조합
8 OutOfOrderSequenceException 멱등 프로듀서의 시퀀스가 끊겼습니다 브로커가 이전 상태를 잃은 경우(로그 절단, PID 만료)입니다. 프로듀서를 재생성해야 합니다. producer.id.expiration.ms도 확인
9 ProducerFencedException 같은 transactional.id로 새 프로듀서가 등록됐습니다 정상 동작입니다(좀비 펜싱). 이 인스턴스는 종료해야 합니다. 두 인스턴스가 같은 transactional.id를 쓰고 있지 않은지 확인
10 InvalidTxnStateException 트랜잭션 API 호출 순서 initTransactions()beginTransaction()send()commitTransaction() 순서를 지켜야 합니다
11 send()가 블록되어 돌아오지 않는다 버퍼 고갈 또는 메타데이터 조회 실패 max.block.ms만큼 블록한 뒤 예외가 납니다. buffer.memory와 브로커 도달성 확인
12 예외는 없는데 데이터가 안 들어간다 콜백에서 예외를 삼키고 있지 않은가 send()는 비동기입니다. 콜백 또는 Future.get()으로 결과를 확인하지 않으면 실패가 조용히 사라집니다. JMX record-error-rate 확인

실패가 조용히 사라집니다. send()는 즉시 반환하고, 브로커가 거부해도 애플리케이션은 알지 못합니다.

Producer.java
producer.send(record);
// 아무것도 확인하지 않음

콜백에서 예외를 반드시 처리합니다. retriable / non-retriable을 구분해 대응합니다.

Producer.java
producer.send(record, (metadata, exception) -> {
    if (exception == null) return;
    if (exception instanceof RetriableException) {
        // 클라이언트가 이미 delivery.timeout.ms 까지 재시도한 결과입니다.
        // 여기 도달했다면 재시도로는 해결되지 않았다는 뜻입니다.
        log.error("전송 최종 실패 (retriable 소진): {}", record.key(), exception);
    } else {
        // RecordTooLargeException, TopicAuthorizationException 등
        // 재시도해도 절대 성공하지 않습니다. DLQ 또는 알림으로 보냅니다.
        log.error("전송 실패 (재시도 불가): {}", record.key(), exception);
    }
    failureCounter.increment();
});

의사결정 트리 ③ 브로커 성능 저하

트러블슈팅 결정 트리 — 브로커 성능이 저하될 때 브로커 성능 저하를 메트릭에서 출발해 좁혀 가는 결정 트리입니다. RequestHandlerAvgIdlePercent 가 0.3 아래면 요청 처리 스레드가 부족하므로 num.io.threads 와 디스크 상태를 봅니다. NetworkProcessorAvgIdlePercent 가 낮으면 num.network.threads 를 검토합니다. UnderReplicatedPartitions 가 0 이 아니면 복제가 밀린 상태이므로 num.replica.fetchers 와 네트워크·디스크를 확인합니다. OfflinePartitionsCount 가 0 이 아니면 리더가 없는 파티션이 있어 읽기와 쓰기가 모두 막힙니다. ActiveControllerCount 의 클러스터 합이 1 이 아니면 컨트롤러 쿼럼 문제입니다. 로그 flush 지연이 크면 디스크가 병목이고, 리더가 한 브로커에 몰려 있으면 preferred 리더 선출로 균형을 되돌립니다. 브로커가 느리다 · 응답이 밀린다 추측하지 말고 메트릭부터 봅니다. 각 판단 아래가 확인할 지표입니다. RequestHandlerAvgIdle < 0.3? RequestHandlerPool 요청 처리 스레드 포화 · num.io.threads 를 올린다 · 디스크 지연이 원인이면 효과 없음 아니오 NetworkProcessorAvgIdle 낮음? SocketServer 메트릭 네트워크 스레드 포화 · num.network.threads 검토 · 리스너마다 별도 풀이다 아니오 UnderReplicatedPartitions > 0? --under-replicated 복제가 밀리는 중 · num.replica.fetchers · 대역폭 확인 · IsrShrinksPerSec 동반 상승 확인 아니오 OfflinePartitionsCount > 0? KafkaController 리더 없는 파티션 — 최우선 · 읽기·쓰기가 모두 막힌다 · --unavailable-partitions 로 범위 확인 아니오 ActiveControllerCount 합 ≠ 1? kafka-metadata-quorum 컨트롤러 쿼럼 이상 · 정확히 한 대만 1 이어야 한다 · describe --status 로 lag 확인 아니오 로그 flush 지연이 크다? LogFlushRateAndTimeMs 디스크가 병목 · kafka-log-dirs.sh --describe · 한 디스크에 로그 디렉터리 여러 개 금지 아니오 리더가 한 브로커에 몰렸다? --describe Leader 열 리더 편중 · kafka-leader-election.sh --election-type preferred · 재배치는 kafka-reassign-partitions.sh 정상 기준: URP 0 · UnderMinIsrPartitionCount 0 · OfflinePartitionsCount 0 · ActiveController 합 1. RequestHandlerAvgIdlePercent 는 0~1 값이며 공식 문서는 0.3 이상을 권합니다.
브로커가 느릴 때의 분기 — TotalTimeMs를 큐·로컬·원격·응답 구간으로 분해해 스레드 부족 / 디스크 / 복제 지연 / 네트워크 중 무엇인지 가르는 흐름
브로커 트리 — 지연을 구간으로 분해합니다
#확인지표그렇다면
1 어느 구간이 느린가 RequestMetrics,name=TotalTimeMs를 큐·Local·Remote·Response로 분해 지배적인 구간 하나를 고르고 아래로 내려갑니다 (지연 분해 표)
2 RequestQueueTimeMs가 크다 RequestHandlerAvgIdlePercent < 0.3 I/O 스레드 포화 → num.io.threads 상향(디스크 수 이상)
3 ResponseQueueTimeMs가 크다 NetworkProcessorAvgIdlePercent < 0.3 네트워크 스레드 포화 → num.network.threads 상향. TLS·압축 부하도 여기 걸립니다
4 LocalTimeMs가 크다 LogFlushRateAndTimeMs, OS의 디스크 대기 디스크가 병목입니다. flush.messages를 임의로 낮췄는지 확인 → Kafka는 복제로 내구성을 얻습니다
5 RemoteTimeMs가 크다 MaxLag,clientId=Replica, URP acks=all에서 복제를 기다린 것입니다. 클라이언트가 아니라 복제 쪽을 보세요
6 복제 throttle이 남아 있는가 kafka-configs.sh --describe --entity-type topics --entity-name T *.replication.throttled.replicas가 남아 있으면 재할당 후 --verify를 안 돌린 것입니다
7 리더가 편중됐는가 LeaderCount가 브로커 간에 크게 다름 kafka-leader-election.sh --election-type preferred --all-topic-partitions
8 디스크가 차 있는가 kafka-log-dirs.sh --describe, OfflineLogDirectoryCount 즉시 조치로 리텐션 하향. 원래 값을 반드시 기록하고 나중에 되돌리세요
9 GC가 길어졌는가 GC 로그, IsrShrinksPerSec/IsrExpandsPerSec가 장애 없이 0이 아님 긴 GC는 하트비트를 끊어 ISR 플래핑과 리더 선거를 유발합니다. 힙과 GC 옵션 검토
10 파티션이 너무 많은가 GlobalPartitionCount, EventQueueTimeMs 파티션 총수는 컨트롤러 메모리·페일오버 시간·파일 디스크립터에 직접 영향합니다 (케이스 5)
11 메시지 포맷 변환이 일어나는가 {Produce|Fetch}MessageConversionsPerSec, TemporaryMemoryBytes 0이 아니면 구버전 클라이언트 때문에 브로커가 변환을 하고 있습니다. zero-copy가 깨져 CPU를 씁니다
12 쿼터가 걸려 있는가 kafka.server:type={Produce|Fetch},…throttle-time 브로커는 한가한데 클라이언트만 느린 전형적 원인입니다

증상 → 확인 명령 → 원인 후보 → 조치

증상 기반 색인 (24항목)
증상 확인 명령 · 지표 원인 후보 조치
배포 후 컨슈머가 과거 데이터를 전부 다시 읽는다 --describe --group G에서 LAG이 갑자기 거대 group.id가 바뀜 / 커밋 만료 / auto.offset.reset=earliest group.id를 되돌리거나 오프셋을 원하는 지점으로 리셋 (케이스 1)
배포 후 컨슈머가 최근 데이터를 건너뛴다 LAG이 - 였다가 0이 됨 새 그룹 + auto.offset.reset=latest(기본값) --reset-offsets --to-datetime으로 되돌려 재처리
컨슈머가 계속 리밸런스만 한다 --describe --group G --statePreparingRebalance 반복 처리 시간 > max.poll.interval.ms / 컨슈머가 반복 재시작 / 네트워크 불안정 max.poll.records 하향, group.instance.id로 정적 멤버십 (케이스 2)
lag이 특정 파티션만 큰다 JMX records-lag (파티션별) 핫키 편중 / 그 파티션 리더 브로커가 느림 키 설계 재검토 (케이스 4). 리더 브로커 지표 확인
컨슈머를 늘렸는데 처리량이 그대로다 --describe --group G --members --verbose 컨슈머 수 > 파티션 수 — 남는 컨슈머는 유휴 파티션을 늘리거나 Share Group(4.2+)을 검토
메시지가 중복 처리된다 애플리케이션 로그의 중복 키 at-least-once의 정상 동작 / 리밸런스 시 커밋 전 재시작 / EOS 경계 밖의 외부 시스템 컨슈머 멱등성을 직접 구현하세요. Kafka EOS는 Kafka 안에서만 성립합니다 (케이스 7)
메시지 순서가 뒤바뀐다 키가 지정되어 있는가, 파티션 수가 바뀌었는가 키 없음 / 파티션 증설로 키→파티션 매핑 변경 / max.in.flight > 1 + 멱등성 off 키를 지정하세요. 순서 보장 단위는 파티션입니다 (4장)
트랜잭션 컨슈머가 아무것도 못 읽는다 kafka-transactions.sh find-hanging --topic T 멈춘 트랜잭션이 LSO를 막고 있음 원인 프로듀서를 정리한 뒤 최후 수단으로 kafka-transactions.sh abort
프로듀서가 갑자기 타임아웃한다 --describe --under-min-isr-partitions ISR 부족 / 리더 이동 / 네트워크 브로커 복구. 프로듀서 delivery.timeout.ms는 증상이 아니라 시간 상한일 뿐입니다
특정 크기 이상 메시지만 실패한다 브로커 BytesRejectedPerSec 4개 크기 설정 중 하나가 낮음 프로듀서 · 토픽 · 브로커 · replica.fetch 네 곳을 모두 맞추세요 (케이스 10)
디스크가 예상보다 빨리 찬다 kafka-log-dirs.sh --describe 세그먼트 크기가 커서 삭제가 지연 / RF 계산 누락 / 압축 미적용 디스크 = 처리량 × 보관기간 × RF × (1 − 압축률). segment.bytes·segment.ms도 함께 조정 (7장)
리텐션을 낮췄는데 디스크가 안 줄어든다 NumLogSegments, log.retention.check.interval.ms 활성 세그먼트는 삭제되지 않음 / 검사 주기 대기 / cleanup.policy=compact segment.ms를 낮춰 롤링을 유도하세요
컴팩션 토픽에서 오래된 키가 안 사라진다 min.cleanable.dirty.ratio, log.cleaner.enable dirty 비율 미달 / cleaner 스레드 부족 / min.compaction.lag.ms 컴팩션은 즉시가 아니라 조건 충족 시 일어납니다 (7장)
cleanup.policy를 바꿨는데 옛 데이터가 그대로다 kafka-configs.sh --describe --entity-type topics 정책 변경은 소급 적용되지 않음 변경 시점 이후 세그먼트에만 적용됩니다 (케이스 8)
브로커 재시작 후 리더가 한쪽에 몰린다 LeaderCount, PreferredReplicaImbalanceCount 재시작 순서 / auto.leader.rebalance.enable=false kafka-leader-election.sh --election-type preferred --all-topic-partitions
재할당이 끝났는데 복제가 계속 느리다 토픽 설정에 *.replication.throttled.replicas --verify를 실행하지 않아 throttle이 남음 --verify 실행 또는 --delete-config로 직접 제거
클라이언트가 브로커에 붙지 못한다 (Docker · K8s) 브로커 로그, advertised.listeners 컨테이너 내부 주소를 광고 중 클라이언트가 도달할 수 있는 주소로 광고하세요 (리스너 패턴 5가지)
CLI가 이유 없이 타임아웃한다 --command-config를 넘겼는가 SASL·SSL 클러스터에서 인증 설정 누락 인증 실패가 명확한 에러가 아니라 타임아웃으로 보이는 경우가 많습니다
인증은 되는데 특정 작업만 거부된다 kafka-acls.sh --list 인가(ACL) 문제 — 인증과 별개 필요한 오퍼레이션 조합을 확인하세요 (ACL 표)
컨슈머가 역직렬화에서 죽고 다시 시작해도 같은 곳에서 죽는다 애플리케이션 로그의 RecordDeserializationException 포이즌 메시지. 커밋을 못 하니 같은 레코드를 계속 읽습니다 에러 핸들링 역직렬화기로 감싸 DLQ로 보내거나, 해당 오프셋을 seek로 건너뛰세요
Streams 앱이 재시작마다 오래 걸린다 state.dir가 영속 볼륨인가 상태 저장소가 사라져 changelog를 전부 다시 읽음 state.dir를 영속화하고 num.standby.replicas=1을 두세요
Connect 커넥터가 FAILED로 떨어진다 GET /connectors/{name}/status 변환·컨버터 오류 / 대상 시스템 장애 / errors.tolerance=none trace를 확인하고 DLQ를 설정하세요 (Connect 치트시트)
Connect 재시작 요청이 409로 거부된다 워커 로그의 rebalance 리밸런스 진행 중 리밸런스 완료 후 재시도. 리밸런스 자체가 태스크를 재시작하므로 불필요할 수도 있습니다
메트릭은 정상인데 사용자는 느리다고 한다 쿼터 throttle-time, 클라이언트 request-latency-avg 쿼터 / 클라이언트 GC / 클라이언트 네트워크 브로커 TotalTimeMs와 클라이언트 request-latency-avg차이가 네트워크 구간입니다

예외 사전

클래스명은 Apache Kafka 4.3 소스 (org.apache.kafka.common.errors, org.apache.kafka.common.protocol.Errors, org.apache.kafka.clients.consumer)에서 확인했습니다. 재시도 열은 프로토콜 에러 코드의 retriable 플래그입니다 — true면 클라이언트가 자동으로 재시도하며, 그래도 여기 도달했다면 재시도 예산이 소진된 것입니다.

자주 보는 예외 46개 — 클래스명은 Kafka 4.3 소스 확인
예외 클래스 재시도 원인 조치 관련
TimeoutException 메타데이터 조회 실패, delivery.timeout.ms 만료, Admin 요청 타임아웃 등 여러 상황 메시지 본문을 반드시 읽으세요. "Topic not present in metadata"와 "Expiring N record(s)"는 원인이 완전히 다릅니다 프로듀서 트리
RecordTooLargeException 아니오 레코드(배치)가 허용 크기를 초과. 프로토콜 MESSAGE_TOO_LARGE 프로듀서 max.request.size, 토픽 max.message.bytes, 브로커 message.max.bytes, replica.fetch.max.bytes전부 조정 케이스 10
RecordBatchTooLargeException 아니오 배치가 서버의 세그먼트 크기보다 큼. 프로토콜 RECORD_LIST_TOO_LARGE batch.size를 줄이거나 segment.bytes를 검토
NotEnoughReplicasException ISR 수가 min.insync.replicas 미달. acks=all일 때만 발생 브로커 복구가 정답. --describe --under-min-isr-partitions로 대상 확인 케이스 6
NotEnoughReplicasAfterAppendException 로그에는 기록됐지만 ISR이 요구치 미달. 재시도하면 중복이 생길 수 있습니다 멱등 프로듀서(4.x 기본 true)면 중복이 제거됩니다. 껐다면 이 예외가 중복의 원인이 됩니다 6장
NotLeaderOrFollowerException 요청을 받은 브로커가 그 파티션의 리더가 아님. 리더 이동 중 클라이언트가 메타데이터를 갱신해 자동 복구합니다. 지속되면 리더 선거가 반복되는 것
LeaderNotAvailableException 리더 선거 중이어서 리더가 없음 보통 자동 해소됩니다. 지속되면 --unavailable-partitions 확인
UnknownTopicOrPartitionException 이 브로커가 해당 토픽-파티션을 호스팅하지 않음. 토픽 오타 또는 아직 생성되지 않음 토픽 존재 확인. auto.create.topics.enable=false면 자동 생성되지 않습니다
UnknownTopicIdException 토픽 ID가 이 브로커에 없음. 토픽이 삭제·재생성된 경우 동명 토픽을 재생성하면 ID가 바뀝니다. 클라이언트 재시작
OutOfOrderSequenceException 아니오 멱등 프로듀서의 시퀀스 번호가 끊김. 브로커가 이전 상태를 잃음 프로듀서를 재생성해야 합니다. producer.id.expiration.ms와 리텐션이 너무 짧지 않은지 확인 4장
DuplicateSequenceException 아니오 브로커가 같은 시퀀스 번호를 다시 받음 멱등성이 정상 동작하며 중복을 걸러낸 결과입니다
UnknownProducerIdException 아니오 브로커가 해당 producer ID의 메타데이터를 찾지 못함. 리텐션으로 관련 레코드가 삭제된 경우 등 프로듀서 재생성. 리텐션이 프로듀서 유휴 시간보다 짧은 구성인지 확인
ProducerFencedException 아니오 같은 transactionalId더 새로운 프로듀서가 등록되어 이 프로듀서가 펜싱됨 설계된 동작입니다. 이 인스턴스는 프로듀서를 닫고 종료해야 합니다. 두 인스턴스가 같은 ID를 쓰고 있는지 확인 6장
InvalidProducerEpochException 아니오 오래된 epoch로 produce를 시도 펜싱과 같은 계열입니다. 트랜잭션을 중단하고 프로듀서를 재초기화
InvalidTxnStateException 아니오 잘못된 트랜잭션 상태에서 API를 호출 initTransactions()beginTransaction()send()commitTransaction() 순서를 지키세요 예제 5
TransactionAbortedException 트랜잭션이 중단되어 해당 send()가 완료되지 못함 중단의 원인이 되는 다른 예외를 로그에서 찾으세요. 이것은 결과입니다
TransactionAbortableException 아니오 트랜잭션을 중단해야 하는 오류가 발생 abortTransaction()을 호출하고 다시 시작하세요
ConcurrentTransactionsException 같은 트랜잭션에 대해 다른 작업이 진행 중 클라이언트가 재시도합니다. 지속되면 트랜잭션 코디네이터 부하 확인
CommitFailedException 아니오 커밋 시점에 이미 파티션 소유권을 잃음. 대개 poll() 간격이 max.poll.interval.ms를 초과. 예외 메시지가 원인과 조치를 그대로 알려 줍니다아래 전문 max.poll.records를 줄이거나 max.poll.interval.ms를 늘리세요. 처리를 별도 스레드로 옮기는 것도 방법 케이스 2
RebalanceInProgressException 아니오 그룹이 리밸런스 중이라 재조인이 필요 다음 poll()에서 자동 처리됩니다. 빈번하면 리밸런스 원인을 찾으세요
FencedInstanceIdException 아니오 같은 group.instance.id로 다른 member.id가 등록됨 (정적 멤버십) 두 인스턴스가 같은 group.instance.id를 쓰고 있습니다. 배포 설정 확인
UnknownMemberIdException 아니오 코디네이터가 이 멤버를 모름. 세션 타임아웃으로 이미 제거된 경우 클라이언트가 재조인합니다. 반복되면 session.timeout.ms·GC 확인
IllegalGenerationException 아니오 generation ID가 낡음. 리밸런스가 이미 지나갔음 재조인으로 해소됩니다
InvalidGroupIdException 아니오 group.id가 없거나 비어 있는데 그룹 기능(커밋·구독)을 사용 subscribe()·commitSync()group.id가 필요합니다. assign()만 쓸 거면 커밋도 직접 관리하세요 5장
GroupMaxSizeReachedException 아니오 그룹 멤버 수가 group.max.size를 초과 브로커 group.max.size 확인. 컨슈머를 무한정 늘려도 파티션 수 이상은 무의미합니다
OffsetOutOfRangeException 아니오 요청 오프셋이 파티션의 보관 범위 밖. 리텐션으로 삭제된 구간을 읽으려 함 auto.offset.reset이 설정되어 있으면 자동 리셋됩니다. none이면 예외가 그대로 올라옵니다. JMX records-lead-min으로 조기 감지 케이스 1
NoOffsetForPartitionException 아니오 커밋된 오프셋이 없고 auto.offset.reset=none 의도적인 안전장치입니다. 어디서부터 읽을지 명시적으로 결정하세요
RecordDeserializationException 아니오 레코드 역직렬화 실패. 포이즌 메시지 커밋을 못 하므로 같은 레코드에서 무한 반복합니다. 에러 핸들링 역직렬화기로 감싸거나 seek로 건너뛰세요 예제 6
SerializationException 아니오 직렬화·역직렬화 실패의 상위 예외. 스키마 불일치도 여기로 옵니다 스키마 호환성 모드와 배포 순서를 확인하세요 (8장) 케이스 9
IllegalStateException: Subscription to topics, partitions and pattern are mutually exclusive 아니오 한 컨슈머에서 subscribe(토픽 목록), subscribe(패턴), assign(파티션)섞어 호출했습니다 세 방식은 배타적입니다. 하나만 쓰세요. 전환하려면 먼저 unsubscribe()를 호출해야 합니다 5장
TopicAuthorizationException 아니오 토픽에 대한 권한 없음 프로듀서는 WRITE+DESCRIBE, 컨슈머는 READ+DESCRIBE가 필요합니다 보안 치트시트
GroupAuthorizationException 아니오 컨슈머 그룹에 대한 권한 없음 토픽 권한만 주고 그룹 권한을 빼먹는 것이 가장 흔한 실수입니다. --consumer 편의 옵션이 둘 다 부여합니다 보안 치트시트
ClusterAuthorizationException 아니오 클러스터 레벨 오퍼레이션 권한 없음 토픽 자동 생성(Cluster CREATE), 재할당(Cluster ALTER) 등에서 발생
TransactionalIdAuthorizationException 아니오 transactional.id에 대한 권한 없음 TransactionalId 리소스에 WRITE·DESCRIBE를 부여하세요
SaslAuthenticationException 아니오 SASL 인증 실패. 자격 증명 오류 또는 메커니즘 불일치 sasl.mechanism 기본값은 GSSAPI입니다 — SCRAM·PLAIN은 명시해야 합니다 보안 치트시트
SslAuthenticationException 아니오 TLS 핸드셰이크 실패. 인증서 만료, 체인 불일치, 호스트명 검증 실패 -Djavax.net.debug=ssl:handshake로 원인을 좁히세요. ssl.endpoint.identification.algorithm도 확인 보안 치트시트
UnsupportedSaslMechanismException 아니오 브로커가 요청한 SASL 메커니즘을 지원하지 않음 브로커 sasl.enabled.mechanisms에 해당 메커니즘이 있는지 확인 (기본값은 GSSAPI뿐)
ConfigException 아니오 설정 값·조합이 유효하지 않음. 기동 시점에 발생 대표 사례: enable.idempotence=true + max.in.flight.requests.per.connection > 5 설정 치트시트
KafkaStorageException 브로커의 디스크 오류. 로그 디렉터리 접근 실패 OfflineLogDirectoryCount·LogDirectoryOffline 확인. 디스크 교체가 근본 해결 메트릭 치트시트
CorruptRecordException CRC 불일치, 크기 초과, 컴팩션 토픽의 null 키 등 kafka-dump-log.sh --files … --index-sanity-check로 확인. 컴팩션 토픽에 키 없는 레코드를 보내지 마세요
UnsupportedVersionException 아니오 브로커가 요청한 API 버전을 지원하지 않음 kafka-broker-api-versions.sh로 확인. 신 클라이언트 + 구 브로커 조합에서 발생
InvalidReplicationFactorException 아니오 복제 계수가 1 미만이거나 사용 가능한 브로커 수보다 큼 브로커 3대 미만 클러스터에서 offsets.topic.replication.factor=3(기본값)이 실패하는 전형적 사례
TopicExistsException 아니오 같은 이름의 토픽이 이미 존재 멱등한 스크립트를 원하면 --if-not-exists를 쓰세요
ThrottlingQuotaExceededException Admin 요청이 쿼터를 초과 토픽을 대량 생성·삭제하는 스크립트에서 자주 봅니다. 배치 크기를 줄이세요
WakeupException 다른 스레드가 consumer.wakeup()을 호출해 블로킹 호출을 중단시킴 오류가 아닙니다. 정상 종료 신호로 쓰는 패턴입니다. finally에서 close()하세요
InvalidRequiredAcksException 아니오 acks 값이 유효하지 않음 허용값은 0, 1, all(-1)입니다

CommitFailedException 메시지 전문

이 예외는 메시지 자체가 진단서입니다. 인자 없이 생성될 때의 기본 메시지가 아래와 같이 고정되어 있으므로 (Kafka 4.3 CommitFailedException.java 확인), 로그에서 이 문장을 보면 원인을 더 찾을 필요가 없습니다.

기본 메시지 (소스 확인)
Commit cannot be completed since the group has already rebalanced and assigned
the partitions to another member. This means that the time between subsequent
calls to poll() was longer than the configured max.poll.interval.ms, which
typically implies that the poll loop is spending too much time message
processing. You can address this either by increasing max.poll.interval.ms or
by reducing the maximum size of batches returned in poll() with max.poll.records.

브로커 로그 읽기

브로커 로그 파일별 용도
파일무엇이 들어가는가언제 보는가
server.log브로커 전반의 INFO·WARN·ERROR기본. 기동 실패·설정 오류·디스크 문제
controller.log컨트롤러 이벤트, 리더 선거, 메타데이터 처리리더가 이동하거나 오프라인 파티션이 생겼을 때
state-change.log파티션 상태 전이 (리더/팔로워/오프라인)특정 파티션이 왜 오프라인인지 추적할 때
log-cleaner.log컴팩션 스레드의 동작컴팩션이 진행되지 않을 때
kafka-request.log요청 상세 (기본 비활성)권한·크기 문제를 요청 단위로 봐야 할 때만 임시로 켭니다
kafka-authorizer.log인가 판정 결과ACL 문제를 추적할 때 — 거부 이유가 여기 남습니다
재시작 없이 특정 로거만 DEBUG로 (조사 후 반드시 되돌리세요)
# 인가 문제 추적
bin/kafka-configs.sh --bootstrap-server $BS --alter \
  --entity-type broker-loggers --entity-name 1 \
  --add-config org.apache.kafka.metadata.authorizer.StandardAuthorizer=DEBUG

# 현재 로그 레벨 확인
bin/kafka-configs.sh --bootstrap-server $BS --describe \
  --entity-type broker-loggers --entity-name 1

# 되돌리기 — DEBUG 를 켜 둔 채로 두면 디스크가 빠르게 찹니다
bin/kafka-configs.sh --bootstrap-server $BS --alter \
  --entity-type broker-loggers --entity-name 1 \
  --add-config org.apache.kafka.metadata.authorizer.StandardAuthorizer=INFO

공식 문서 출처

예외 클래스명과 retriable 여부는 Apache Kafka 4.3 소스 (org.apache.kafka.common.protocol.Errorsorg.apache.kafka.common.errors 패키지)에서 확인했습니다. 확인하지 못한 예외는 표에 넣지 않았습니다. 의사결정 트리의 순서와 조치 판단은 이 가이드의 정리이며 공식 문서의 서술이 아닙니다.