콘솔 명령어를 사용한 일반적인 Kafka 컨슈머 지연 문제 해결
강력한 콘솔 명령어를 사용하여 Kafka 컨슈머 지연 문제를 해결하는 방법을 마스터하세요. 이 포괄적인 가이드는 `kafka-consumer-groups.sh`(및 레거시 `consumer-offset-checker.sh`)를 사용한 지연 진단, 출력 해석, 컨슈머 오프셋 재설정을 통해 애플리케이션을 다시 동기화하는 방법을 안내합니다. 모범 사례를 배우고, 오프셋 재설정의 영향을 이해하며, Kafka 파이프라인이 효율적이고 안정적으로 유지되도록 보장하세요. 실용적인 예제와 실행 가능한 단계는 Kafka 운영자와 개발자에게 필수적인 리소스입니다.
콘솔 명령어를 사용한 일반적인 Kafka 컨슈머 지연 문제 해결
컨슈머 지연은 파이프라인이 느리게 느껴질 때 대부분의 Kafka 운영자가 가장 먼저 확인하는 숫자이지만, 가장 쉽게 오해할 수 있는 숫자 중 하나이기도 합니다. 그룹이 백만 개의 레코드 지연을 보일 수 있는 이유는 다운스트림 API 하나가 타임아웃되거나, 배포로 인해 절반의 컨슈머가 오프라인 상태가 되거나, 하나의 파티션이 다른 파티션보다 더 뜨겁거나, 애플리케이션이 정상적으로 계획된 일시 중지 후 따라잡고 있기 때문일 수 있습니다. 명령어는 간단합니다. 그 명령어를 둘러싼 판단이 인시던트의 승패를 가릅니다.
이 가이드는 지연 인시던트 중에 제가 사용하는 명령줄 경로에 초점을 맞춥니다: 그룹 설명, 파티션 비교, 컨슈머가 살아 있는지 확인, 지연이 증가하는지 감소하는지 결정, 그리고 그 후에야 오프셋 재설정을 고려합니다. 오프셋 재설정은 때때로 필요하기 때문에 포함되었지만, 느린 컨슈머에 대한 치료법이 아닙니다. 작업을 건너뛰거나 다시 실행합니다. 이를 성능 수정이 아닌 운영 결정으로 취급하세요.
Kafka 컨슈머 지연 이해하기
Kafka에서 메시지는 토픽으로 구성되며, 이는 다시 파티션으로 나뉩니다. 파티션 내의 각 메시지에는 순차적이고 변경 불가능한 오프셋이 할당됩니다. 컨슈머는 현재 위치(커밋된 오프셋)를 유지하여 파티션에서 메시지를 읽습니다. Kafka 브로커는 각 파티션에 대한 로그-끝-오프셋을 추적하며, 이는 파티션에 추가된 최신 메시지의 오프셋을 나타냅니다.
컨슈머 지연 = 로그-끝-오프셋 - 커밋된 오프셋
기본적으로 지연은 특정 파티션에 대해 컨슈머가 로그의 헤드보다 뒤처진 메시지 수입니다. 일부 지연은 모든 스트리밍 시스템에서 자연스럽고 예상되지만, 지속적으로 증가하거나 과도하게 큰 지연은 문제를 나타냅니다.
높은 컨슈머 지연이 우려되는 이유:
- 데이터 처리 지연: 애플리케이션이 데이터를 너무 느리게 처리하여 실시간 분석이나 중요한 비즈니스 운영에 영향을 미칠 수 있습니다.
- 리소스 고갈: 컨슈머가 따라잡지 못해 CPU, 메모리 또는 네트워크 사용량이 높아질 수 있습니다.
- 오래된 데이터: 지연되는 컨슈머로부터 데이터를 받는 다운스트림 시스템은 오래된 정보를 기반으로 작동합니다.
- 보존 정책 문제: 지연이 토픽의 보존 기간을 초과하면 메시지가 로그에서 제거되어 컨슈머가 메시지를 영구히 놓칠 수 있습니다.
- 컨슈머 그룹 리밸런스: 지속적인 지연은 불안정한 컨슈머 그룹 동작과 빈번한 리밸런스에 기여할 수 있습니다.
높은 지연의 일반적인 원인:
- 느린 컨슈머 로직: 컨슈머 애플리케이션 자체가 각 메시지를 처리하는 데 너무 오래 걸립니다.
- 컨슈머 인스턴스 부족: 모든 파티션의 메시지 볼륨을 처리할 수 있는 충분한 컨슈머 인스턴스가 실행되고 있지 않습니다.
- 네트워크 지연: 컨슈머와 브로커 간의 문제.
- 브로커 성능 문제: 브로커가 메시지를 효율적으로 제공하는 데 어려움을 겪을 수 있습니다.
- 메시지 생성 급증: 일시적인 메시지 폭주로 컨슈머가 압도됩니다.
- 구성 오류: 잘못된 컨슈머 또는 토픽 구성.
kafka-consumer-groups.sh로 지연 진단 (권장)
kafka-consumer-groups.sh 도구는 컨슈머 그룹을 관리하고 검사하는 현대적이고 권장되는 방법입니다. Kafka 브로커와 직접 상호 작용하여 내부 __consumer_offsets 토픽에 저장된 컨슈머 오프셋 정보를 검색합니다. 이 도구는 지연을 포함한 컨슈머 그룹 상태에 대한 포괄적인 세부 정보를 제공합니다.
컨슈머 그룹 설명 기본 사용법
특정 컨슈머 그룹의 지연을 확인하려면 --describe 및 --group 옵션을 사용하세요:
kafka-consumer-groups.sh --bootstrap-server <Kafka_Broker_Host:Port> --describe --group <Consumer_Group_Name>
<Kafka_Broker_Host:Port>를 Kafka 브로커 중 하나의 주소(예: localhost:9092)로 바꾸고 <Consumer_Group_Name>을 검사하려는 컨슈머 그룹의 이름으로 바꾸세요.
출력 해석
일반적인 출력은 다음과 같습니다:
GROUP TOPIC PARTITION CURRENT-OFFSET LOG-END-OFFSET LAG CONSUMER-ID HOST CLIENT-ID
my-consumer-app my-topic 0 12345 12347 2 consumer-1-a1b2c3d4-e5f6-7890-1234-abcdedfg /192.168.1.100 consumer-1
my-consumer-app my-topic 1 20000 20500 500 consumer-2-hijk-lmno-pqrs-tuvw-xyz /192.168.1.101 consumer-2
my-consumer-app my-topic 2 5000 5000 0 consumer-3-1234-5678-90ab-cdef-12345678 /192.168.1.102 consumer-3
my-consumer-app another-topic 0 900 900 0 consumer-1-a1b2c3d4-e5f6-7890-1234-abcdedfg /192.168.1.100 consumer-1
중요한 열을 분석해 보겠습니다:
GROUP: 컨슈머 그룹의 이름.TOPIC: 소비 중인 토픽.PARTITION: 토픽의 특정 파티션.CURRENT-OFFSET: 이 파티션에 대해 컨슈머가 커밋한 마지막 오프셋.LOG-END-OFFSET: 이 파티션의 최신 메시지 오프셋.LAG:LOG-END-OFFSET과CURRENT-OFFSET의 차이. 컨슈머가 뒤처진 메시지 수입니다.CONSUMER-ID: 컨슈머 인스턴스의 고유 식별자.-이면 해당 파티션에 활성 컨슈머가 할당되지 않았음을 의미합니다.HOST: 컨슈머 인스턴스의 IP 주소 또는 호스트 이름.CLIENT-ID: 컨슈머 인스턴스에 대해 구성된 클라이언트 ID.
주요 관찰 사항:
- 높은
LAG값: 컨슈머가 뒤처지고 있음을 나타냅니다. 컨슈머 로직, 리소스 또는 확장을 조사하세요. CONSUMER-ID의-: 파티션이 소비되고 있지 않음을 시사합니다. 이는 그룹에 활성 컨슈머가 충분하지 않거나 컨슈머 인스턴스가 충돌 후 다시 합류하지 않았기 때문일 수 있습니다. 이러한 파티션의LAG가 높으면 심각한 문제입니다.LAG가 0: 컨슈머가 최신 메시지를 완전히 따라잡았음을 의미합니다.
consumer-offset-checker.sh로 지연 진단 (레거시 도구)
consumer-offset-checker.sh는 오래되고 더 이상 사용되지 않는 도구로, ZooKeeper에 의존하여 컨슈머 오프셋을 저장하고 검색했습니다(이전 kafka.consumer.ZookeeperConsumerConnector를 사용하는 컨슈머의 경우). 최신 Kafka 클라이언트(0.9.0 이상)의 경우 오프셋은 Kafka 자체에 저장됩니다. kafka-consumer-groups.sh로 대체되었지만, 이전 환경이나 레거시 컨슈머 클라이언트에서 이 도구를 접할 수 있습니다.
경고: 사용 중단 알림
이 도구는 오프셋 관리를 위해 ZooKeeper에 의존합니다. 최신 Kafka 클라이언트(0.9.0+)는 오프셋을 Kafka에 직접 저장합니다. 최신 클러스터 및 클라이언트의 경우
kafka-consumer-groups.sh가 권위 있고 선호되는 도구입니다. 컨슈머 클라이언트가 ZooKeeper에 오프셋을 저장하도록 명시적으로 구성된 경우에만consumer-offset-checker.sh를 사용하세요.
기본 사용법
이 도구로 지연을 확인하려면 ZooKeeper 연결 문자열을 제공해야 합니다:
consumer-offset-checker.sh --zk <ZooKeeper_Host:Port> --group <Consumer_Group_Name>
<ZooKeeper_Host:Port>(예: localhost:2181)와 <Consumer_Group_Name>을 바꾸세요.
출력 해석
Group Topic Partition Offset LogSize Lag Owner
my-old-app my-old-topic 0 1000 1050 50 consumer-1_hostname-1234-5678-90ab-cdef
my-old-app my-old-topic 1 2000 2000 0 consumer-2_hostname-abcd-efgh-ijkl-mnop
Group,Topic,Partition:kafka-consumer-groups.sh와 유사합니다.Offset: 컨슈머가 커밋한 오프셋.LogSize: 파티션의LOG-END-OFFSET.Lag: 컨슈머가 뒤처진 메시지 수.Owner: 현재 파티션을 소유(소비)하고 있는 컨슈머 인스턴스.
지연 값의 해석은 유사합니다: 높은 지연은 문제를 나타내고, 높은 지연 파티션에 Owner가 없으면 심각한 문제입니다.
높은 컨슈머 지연 해결: 전략 및 오프셋 재설정
높은 컨슈머 지연을 식별한 후 다음 단계는 해결하는 것입니다. 여기에는 종종 두 가지 접근 방식이 포함됩니다: 첫째, 근본 원인을 조사하고 수정하는 것, 둘째, 필요한 경우 컨슈머 오프셋을 재설정하는 것입니다.
근본 원인 조사
오프셋 재설정으로 뛰어들기 전에 지연이 왜 발생하는지 이해하는 것이 중요합니다. 다음을 확인하세요:
- 컨슈머 애플리케이션 로그: 오류, 과도한 처리 시간 또는 애플리케이션 실패 징후를 찾으세요.
- 컨슈머 호스트 메트릭: CPU, 메모리 및 네트워크 사용량을 모니터링하세요. 컨슈머가 리소스에 제약을 받고 있습니까?
- Kafka 브로커 메트릭: 브로커가 스트레스를 받고 있습니까? 디스크 I/O, 네트워크 또는 CPU가 높습니까?
- 프로듀서 처리량: 메시지 생성에 예상치 못한 급증이 있었습니까?
- 컨슈머 그룹 상태: 빈번한 리밸런스가 있습니까?
max.poll.interval.ms에 도달하고 있습니까?
컨슈머 확장
기존 컨슈머가 메시지를 충분히 빠르게 처리할 수 없고 토픽에 충분한 파티션이 있는 경우, 더 많은 컨슈머 인스턴스를 추가하여 컨슈머 그룹을 확장해야 할 수 있습니다. 그룹의 각 컨슈머 인스턴스는 모든 파티션이 할당될 때까지(파티션 수까지) 하나 이상의 파티션을 인계받습니다.
컨슈머 오프셋 재설정
컨슈머 오프셋을 재설정한다는 것은 컨슈머 그룹이 메시지를 읽기 시작할 시작점을 변경하는 것을 의미합니다. 이는 강력하고 잠재적으로 중단을 일으킬 수 있는 작업이므로 주의해서 사용해야 합니다.
오프셋 재설정 전 중요한 고려 사항:
- 데이터 손실:
--to-latest로 재설정하면 컨슈머가 현재 오프셋과 로그-끝-오프셋 사이의 모든 메시지를 건너뛰게 되어 해당 메시지가 영구적으로 손실됩니다.- 데이터 재처리:
--to-earliest또는 이전 오프셋으로 재설정하면 컨슈머가 이미 처리한 메시지를 다시 처리하게 됩니다. 컨슈머 애플리케이션은 이를 원활하게 처리하려면 멱등성(메시지를 여러 번 처리해도 동일한 결과를 생성)을 가져야 합니다.- 애플리케이션 상태: 재처리가 컨슈머 애플리케이션이나 다운스트림 시스템에서 관리하는 상태에 어떤 영향을 미칠지 고려하세요.
오프셋을 재설정하려면 다시 kafka-consumer-groups.sh를 사용합니다. 오프셋을 재설정하는 방법에 대한 다양한 옵션을 제공합니다:
--to-earliest: 파티션에서 사용 가능한 가장 이른 오프셋으로 재설정합니다.--to-latest: 파티션의 최신 오프셋으로 재설정합니다(사실상 현재 모든 메시지를 건너뜁니다).--to-offset <offset>: 특정 원하는 오프셋으로 재설정합니다.--to-datetime <YYYY-MM-DDTHH:mm:SS.sss>: 특정 타임스탬프에 해당하는 오프셋으로 재설정합니다.--shift-by <N>: 현재 오프셋을 N 위치만큼 이동합니다(예:-10은 10개 메시지 뒤로,+10은 10개 메시지 앞으로).
중요한 안전 기능: --dry-run 및 --execute
--execute로 커밋하기 전에 항상 먼저 --dry-run을 수행하여 재설정 작업이 무엇을 할지 확인하세요.
오프셋 재설정을 위한 단계별 프로세스:
대상 컨슈머 그룹의 모든 컨슈머를 중지합니다. 이는 오프셋을 재설정하는 동안 컨슈머가 새 오프셋을 커밋하는 것을 방지하는 데 중요합니다.
드라이 런을 수행하여 오프셋 변경 사항을 미리 봅니다:
예: 가장 이른 오프셋으로 재설정(모든 메시지 재처리)
kafka-consumer-groups.sh --bootstrap-server localhost:9092 --group my-consumer-app --reset-offsets --to-earliest --topic my-topic --dry-run예: 최신 오프셋으로 재설정(지연된 모든 메시지 건너뛰기)
kafka-consumer-groups.sh --bootstrap-server localhost:9092 --group my-consumer-app --reset-offsets --to-latest --topic my-topic --dry-run예: 특정 타임스탬프로 재설정(예: 2023-01-01 00:00:00 UTC부터 시작)
kafka-consumer-groups.sh --bootstrap-server localhost:9092 --group my-consumer-app --reset-offsets --to-datetime 2023-01-01T00:00:00.000 --topic my-topic --dry-run예: 오프셋을 500개 메시지 뒤로 이동(파티션당)
kafka-consumer-groups.sh --bootstrap-server localhost:9092 --group my-consumer-app --reset-offsets --shift-by -500 --topic my-topic --dry-run
--dry-run의 출력은 제안된 오프셋 변경 사항을 보여줍니다:GROUP TOPIC PARTITION NEW-OFFSET my-consumer-app my-topic 0 0 my-consumer-app my-topic 1 0드라이 런 결과에 만족하면 재설정을 실행합니다:
- 예: 가장 이른 오프셋으로 재설정(실행)
kafka-consumer-groups.sh --bootstrap-server localhost:9092 --group my-consumer-app --reset-offsets --to-earliest --topic my-topic --execute
- 예: 가장 이른 오프셋으로 재설정(실행)
컨슈머 애플리케이션을 다시 시작합니다. 오프셋이 재설정된 후 컨슈머 인스턴스를 다시 시작하세요. 이제 새 시작 오프셋에서 소비를 시작합니다.
팁: 그룹의 모든 토픽에 대한 오프셋 재설정
그룹이 소비하는 모든 토픽에 대한 오프셋을 재설정하려면
kafka-consumer-groups.sh --reset-offsets를 사용할 때--topic플래그를 생략할 수 있습니다. 이는 모든 것에 영향을 미치므로 각별히 주의하세요.
컨슈머 운영 모범 사례
- 사전 모니터링: Prometheus/Grafana, Datadog 또는 사용자 정의 스크립트와 같은 도구를 사용하여 컨슈머 지연에 대한 강력한 모니터링을 구현하세요. 빠르게 증가하거나 지속적으로 높은 지연에 대한 알림을 설정하세요.
- 멱등성 이해: 컨슈머 애플리케이션을 멱등성 있게 설계하세요. 이렇게 하면 오류나 오프셋 재설정 시 메시지를 안전하게 재처리할 수 있습니다.
max.poll.interval.ms조정: 이 설정은 컨슈머가 폴링 없이 갈 수 있는 최대 시간을 정의합니다. 처리 로직이 느린 경우 이 값을 늘려 원치 않는 리밸런스를 방지하되, 근본적인 느림 현상도 조사하세요.- 처리 불가능한 메시지 처리: 반복적으로 실패하고 컨슈머를 차단하는 대신 "데드 레터" 메시지(예: 데드 레터 큐(DLQ)로 보내기)에 대한 전략을 구현하세요.
- 정상 종료: 컨슈머 애플리케이션이 정상적으로 종료되어 불필요한 재처리나 재시작 중 지연 급증을 방지하기 위해 최종 오프셋을 커밋하도록 하세요.
- 파티션과 컨슈머 일치: 최적의 병렬 처리를 위해 실행할 컨슈머 인스턴스 수만큼 최소한의 파티션을 확보하는 것을 목표로 하세요. 더 많은 파티션은 더 많은 병렬 처리를 허용합니다.
실용적인 인시던트 흐름
지연이 알림을 발생시키면 먼저 오프셋을 재설정하고 싶은 충동을 억제하세요. 현재 그룹 상태를 캡처하는 것으로 시작하세요:
kafka-consumer-groups.sh --bootstrap-server kafka-1:9092 --describe --group payments-writer
크기뿐만 아니라 형태를 살펴보세요. 모든 파티션이 거의 동일한 양만큼 지연되고 있다면 전체 그룹이 프로비저닝 부족이거나 공유 종속성에서 차단되었을 가능성이 높습니다. 하나의 파티션이 훨씬 뒤처져 있다면 키 편향, 포이즌 메시지, 또는 CPU, 디스크, DNS, 네트워크 동작이 나쁜 단일 컨슈머 호스트를 확인하세요. CONSUMER-ID가 -이면 해당 파티션에 현재 활성 멤버가 할당되지 않은 것입니다. 이는 일반적으로 충돌한 컨슈머, 진행 중인 리밸런스, 또는 예상보다 건강한 멤버가 적은 그룹을 가리킵니다.
1분 후에 명령어를 다시 실행하세요. 500,000의 지연 값은 배포 롤백 후 빠르게 감소하고 있다면 덜 걱정됩니다. 5,000의 지연 값은 정상 트래픽 중에 매분 두 배로 증가한다면 더 걱정됩니다. 인시던트 중에 저는 일반적으로 세 가지 숫자를 기록합니다: 총 지연, 최악의 파티션 지연, 그룹 상태가 안정적인지 여부. 이를 통해 컨슈머를 확장하거나, 프로듀서를 늦추거나, 애플리케이션 오류를 수정하거나, 제어된 재생을 준비할지 결정할 수 있는 충분한 신호를 얻을 수 있습니다.
재설정 전에 현재 오프셋을 인시던트 티켓에라도 내구성 있는 곳에 저장하세요. 드라이 런은 백업이 아닙니다. 명령어 출력은 누군가 재설정이 여전히 중요한 데이터를 건너뛰었다는 것을 깨달았을 때 필요할 수 있는 오프셋을 제공합니다.
최종 확인
건강한 지연 런북에는 세 가지 습관이 있습니다: 변경하기 전에 설명하고, 실행하기 전에 드라이 런하고, 오프셋을 이동하기 전에 컨슈머를 수정하세요. kafka-consumer-groups.sh는 커밋된 오프셋과 파티션 소유권에 대한 원시적인 진실을 제공합니다. 여러분의 임무는 그 출력을 뒤에 있는 애플리케이션 동작에 연결하는 것입니다.