콘텐츠로 이동
Study NoteKafka

11. 트러블슈팅

증상은 대부분 컨슈머에서 보이지만, 원인은 네 층 어디에나 있다 — 층부터 가른다

이 장에서 처음 나오는 말2개
poison pill
역직렬화 실패 등으로 처리가 항상 실패하는 레코드. 컨슈머가 같은 오프셋에서 무한 재시도하며 그 파티션 소비가 멈춘다.
DLTDead Letter Topic
처리에 계속 실패한 레코드를 치워 두는 별도 토픽. poison pill로 파티션 전체가 멈추는 것을 막는 안전판이다.
  1. 클러스터 — 브로커 파드가 다 살아 있나, URP가 0인가, active controller가 1인가. 여기가 아프면 위층 증상은 전부 파생이다

    터미널 창
    kubectl get pods -n kafka
    kubectl get kafka my-cluster -n kafka -o yaml # status 조건 확인
  2. 토픽/파티션 — 문제의 토픽에 리더 없는 파티션이 있나, ISR이 줄어 있나

    터미널 창
    kafka-topics.sh --bootstrap-server ... --describe --topic order.payment.completed
  3. 프로듀서 — 앱 로그의 전송 오류(NotEnoughReplicas · timeout), 버퍼 상태 (4장)

  4. 컨슈머 — 그룹의 랙과 파티션 배정 상태, 리밸런스 로그 (5장)

    터미널 창
    kafka-consumer-groups.sh --bootstrap-server ... --describe --group notification-service
증상원인일 확률이 높은 것어디를 보나
프로듀서 NotEnoughReplicasException브로커 다운으로 ISR < min.insync.replicas — 유실 대신 쓰기 거부 중(3장)URP · 죽은 브로커. 설정이 아니라 브로커를 고친다
랙이 전 파티션에서 증가소비 처리량 < 생산 처리량컨슈머 수(파티션 한도?) · 처리 병목(DB?)
랙이 한 파티션만 증가poison pill(아래) 또는 핫 파티션(4장)그 파티션 담당 컨슈머 로그 · 키 분포
리밸런스가 반복되고 소비 정지처리 지연으로 max.poll.interval.ms 초과 → 축출 → 반복 (5장의 루프)배치 크기(max.poll.records) 축소 · 처리 시간
RecordTooLargeException기본 최대 메시지 ~1MB 초과큰 파일은 Kafka에 넣지 않는다 — 오브젝트 스토리지에 두고 참조만 흘린다
외부에서 bootstrap만 되고 타임아웃advertised 주소가 클라이언트 기준 무효 (9장)kcat -L로 받은 주소 확인
새 컨슈머가 과거 데이터를 안 읽음auto.offset.reset=latest 기본값 (5장)의도가 처음부터면 earliest
같은 메시지가 두 번 처리됨at-least-once의 정상 동작 (6장)고칠 곳은 Kafka가 아니라 소비자의 멱등 처리
브로커 디스크 만석보존 계산과 유입의 불일치 · retention.bytes 미설정아래

poison pill — 한 파티션만 멈춘다

섹션 제목: “poison pill — 한 파티션만 멈춘다”

형식이 깨진 레코드 하나가 들어오면, 컨슈머는 그 오프셋에서 실패 → 재시도 → 실패를 반복한다. 커밋이 안 넘어가니 그 파티션 전체가 멈추고, 랙은 한 파티션만 자란다.

  • 응급 — 그 오프셋을 건너뛰게 오프셋을 수동으로 옮긴다 (kafka-consumer-groups.sh --reset-offsets --to-offset …, 그룹 정지 상태에서)
  • 재발 방지 — 역직렬화·처리 실패 시 N회 재시도 후 DLT로 치우고 다음으로 넘어가는 처리를 컨슈머에 넣는다 (Spring Kafka 등 주요 프레임워크에 내장 지원이 있다). DLT는 버리는 곳이 아니라 나중에 고쳐 재처리하는 대기소다 — 알람을 걸어 둔다

리밸런스 루프 — 그룹 전체가 멈춘다

섹션 제목: “리밸런스 루프 — 그룹 전체가 멈춘다”

5장의 함정 그대로. 신호는 “랙 증가 + CPU 한가 + 리밸런스 로그 반복”. 처리 시간이 튀는 원인(외부 API 지연 · 대형 배치)을 찾고, 급한 불은 max.poll.records를 줄여서 끈다 — max.poll.interval.ms를 늘리는 것은 마지막 수단이다 (장애 감지도 그만큼 늦어진다).

디스크가 차면 브로커가 죽고, 복구해도 읽을 데이터부터 지워야 떠서 유실이 강제된다.

  • 예방이 전부다 — retention.bytes를 파티션마다 안전판으로 걸고, 70% 알람(10장)
  • “보존을 줄였는데 안 지워져요” — 삭제는 세그먼트 단위라 active 세그먼트는 안 지워진다 (2장). 유입이 적은 토픽은 segment.ms로 세그먼트를 잘게 굴려야 보존이 제때 먹는다
  • 진단은 아래층부터 — 클러스터(URP) → 토픽(리더/ISR) → 프로듀서 → 컨슈머(랙)
  • poison pill은 DLT + 재시도 상한으로 예방 — 응급은 오프셋 건너뛰기
  • 리밸런스 루프는 poll 지연이 원인 — 배치를 줄이는 것이 먼저, 타임아웃 연장은 마지막
  • 디스크 만석은 예방만 있다 — retention.bytes 안전판 · 70% 알람 · segment.ms
  • 큰 파일은 참조만, 중복은 멱등으로 — Kafka 밖에서 고칠 문제를 Kafka에서 찾지 않는다