클라이언트 모니터링, 쿼터, Lag 모니터링, End-to-End 모니터링
Kafka: The Definitive Guide (O'Reilly, 2017, 1st Edition) — Neha Narkhede, Gwen Shapira, Todd Palino Chapter 10: Monitoring Kafka — Client Monitoring (Producer Metrics / Consumer Metrics / Quotas) / Lag Monitoring / End-to-End Monitoring (pp.235-245)
브로커가 정상이어도 클라이언트가 잘 쓰고 있는지는 별개 문제다. 이 모듈은 프로듀서와 컨슈머 클라이언트의 MBean 구조와 알람을 걸어야 할 소수의 지표, 브로커가 오류 코드 없이 응답을 붙잡아 두는 쿼터 스로틀링을 어떻게 감지하는지, 컨슈머 lag을 왜 클라이언트 지표로 보면 안 되는지와 Burrow를 통한 외부 lag 모니터링, 그리고 Kafka Monitor로 하는 종단 간 가용성 모니터링을 다룬다.
프로듀서 클라이언트 지표
신규 Kafka 프로듀서 클라이언트는 지표를 소수의 MBean에 속성으로 압축해 제공한다. 예전 프로듀서 클라이언트는 MBean 수는 많고 개별 지표는 더 상세했지만(백분위수와 여러 이동 평균 제공), 신규 클라이언트는 커버리지가 더 넓은 대신 이상치를 추적하기는 더 어렵다.
모든 프로듀서 지표의 빈 이름에는 클라이언트 ID가 들어간다.
- 전체 프로듀서: kafka.producer:type=producer-metrics,client-id=CLIENTID - 브로커별: kafka.producer:type=producer-node-metrics,client-id=CLIENTID,node-id=node-BROKERID - 토픽별: kafka.producer:type=producer-topic-metrics,client-id=CLIENTID,topic=TOPICNAME
전체 프로듀서 빈에서 반드시 알람을 걸어야 할 속성은 record-error-rate다. 이 값은 항상 0이어야 하며, 0보다 크면 프로듀서가 브로커로 보내려던 메시지를 버리고 있다는 뜻이다. 프로듀서는 정해진 재시도 횟수와 재시도 간 백오프를 갖는데, 이를 모두 소진하면 레코드가 드롭된다. record-retry-rate 속성도 추적할 수 있지만, 재시도 자체는 정상이므로 오류율만큼 치명적이지는 않다.
또 하나 알람을 걸어야 할 지표는 request-latency-avg다. 브로커로 보낸 produce 요청의 평균 소요 시간으로, 정상 운영 시 기준선을 잡아 그 위에 임계값을 두면 된다. 요청 지연이 늘어난다는 것은 produce 요청이 느려진다는 뜻이고, 네트워크 문제일 수도 브로커 문제일 수도 있으며 어느 쪽이든 프로듀싱 애플리케이션에 백프레셔를 유발한다.
트래픽 파악용으로는 세 가지 관점이 있다. outgoing-byte-rate는 초당 절대 바이트, record-send-rate는 초당 생산 메시지 수, request-rate는 초당 브로커로 보낸 produce 요청 수다. 하나의 요청은 하나 이상의 배치를 담고, 하나의 배치는 하나 이상의 메시지를 담으며, 각 메시지는 일정 바이트로 이루어진다는 계층을 이해하면 세 지표의 관계가 분명해진다.
크기 관련 지표로는 request-size-avg(produce 요청 평균 크기), batch-size-avg(단일 토픽 파티션에 대한 메시지 배치의 평균 크기), record-size-avg(단일 레코드 평균 크기), records-per-request-avg(요청당 평균 메시지 수)가 있다. 단일 토픽 프로듀서에서는 유용하지만 MirrorMaker처럼 다중 토픽 프로듀서에서는 정보량이 떨어진다.
마지막으로 권장되는 것은 record-queue-time-avg다. 애플리케이션이 메시지를 보낸 뒤 실제로 Kafka로 produce되기까지 프로듀서 안에서 대기한 평균 시간(밀리초)이다. send()가 호출되면 프로듀서는 둘 중 하나가 일어날 때까지 기다린다. 배치를 채울 만큼 메시지가 모이거나(max.partition.bytes 설정 기준), 마지막 배치 전송 이후 충분한 시간이 흐르거나(linger.ms 설정 기준)다. 바쁜 토픽에서는 첫 번째 조건이, 한산한 토픽에서는 두 번째 조건이 적용된다. 이 지표는 두 설정을 애플리케이션 지연 요구에 맞게 튜닝할 때 지침이 된다.
참고로 ProducerRequestMetrics라는 빈은 요청 지연의 백분위수와 요청 rate의 이동 평균을 함께 제공하지만 권장되지 않는다. 이 지표가 프로듀서 스레드별로 따로 제공되어, 성능을 위해 여러 스레드를 쓰는 애플리케이션에서는 값을 종합하기 어렵기 때문이다. 보통은 전체 프로듀서 빈 하나의 속성으로 충분하다.
브로커별·토픽별 지표는 속성과 의미가 전체 지표와 동일하며 특정 브로커나 토픽에만 적용된다. 브로커별 지표 중에서는 request-latency-avg가 가장 유용하다. 배치가 안정적이라면 이 값도 대체로 안정적이어서 특정 브로커와의 연결 문제를 드러낼 수 있다. 반면 outgoing-byte-rate 같은 값은 각 브로커가 어떤 파티션의 리더인지에 따라 계속 변한다.
핵심 포인트
- 빈 3종: producer-metrics(전체), producer-node-metrics(브로커별), producer-topic-metrics(토픽별)
- 알람 필수 2개: record-error-rate(항상 0이어야 함), request-latency-avg
- record-retry-rate는 재시도가 정상이므로 오류율보다 덜 치명적
- record-queue-time-avg는 max.partition.bytes / linger.ms 튜닝의 지침
- ProducerRequestMetrics는 스레드별로 제공되어 종합이 어려워 비권장
컨슈머 클라이언트 지표
신규 컨슈머도 지표를 소수의 빈에 통합했고, 프로듀서와 마찬가지로 지연 백분위수와 rate 이동 평균은 제거되었다. 다만 소비 로직이 더 복잡한 만큼 다뤄야 할 지표는 조금 더 많다.
- 전체 컨슈머: kafka.consumer:type=consumer-metrics,client-id=CLIENTID - Fetch Manager: kafka.consumer:type=consumer-fetch-manager-metrics,client-id=CLIENTID - 토픽별: kafka.consumer:type=consumer-fetch-manager-metrics,client-id=CLIENTID,topic=TOPICNAME - 브로커별: kafka.consumer:type=consumer-node-metrics,client-id=CLIENTID,node-id=node-BROKERID - 코디네이터: kafka.consumer:type=consumer-coordinator-metrics,client-id=CLIENTID
컨슈머에서는 전체 컨슈머 빈보다 fetch manager 빈이 중요하다. 전체 빈은 저수준 네트워크 동작 지표를 담고 있고, 바이트·요청·레코드 rate는 fetch manager 빈에 있다. 프로듀서와 달리 컨슈머 지표는 들여다보기에는 좋지만 알람을 걸기에는 적합하지 않은 편이다.
fetch manager에서 모니터링과 알람을 고려할 만한 속성은 fetch-latency-avg다. 프로듀서의 request-latency-avg에 대응하는 값으로 브로커로의 fetch 요청이 얼마나 걸리는지 알려 준다. 다만 이 지표에 알람을 걸기 어려운 이유가 있다. fetch 지연은 컨슈머 설정 fetch.min.bytes와 fetch.max.wait.ms에 좌우되기 때문이다. 한산한 토픽에서는 메시지가 있으면 브로커가 빨리 응답하고 없으면 fetch.max.wait.ms 동안 응답하지 않으므로 지연이 들쭉날쭉해진다. 메시지가 규칙적이고 풍부한 토픽에서는 더 볼 만한 지표가 된다.
컨슈머가 처리하는 트래픽 양은 bytes-consumed-rate(초당 바이트)와 records-consumed-rate(초당 메시지)로 파악한다. 둘 다 잡는 것이 좋다. 일부 사용자는 컨슈머가 충분히 일하지 않을 때 알림을 받으려고 이 지표에 최소 임계값 알람을 걸지만 주의가 필요하다. Kafka는 컨슈머와 프로듀서를 분리해 독립적으로 동작하게 하려는 시스템인데, 컨슈머가 소비할 수 있는 속도는 프로듀서가 제대로 동작하는지에 좌우되는 경우가 많다. 즉 컨슈머 쪽 지표로 알람을 거는 것은 프로듀서 상태에 대한 가정을 깔고 있는 셈이고, 거짓 알람으로 이어질 수 있다.
바이트·메시지·요청의 관계는 fetch-rate(초당 fetch 요청 수), fetch-size-avg(fetch 요청 평균 크기, 바이트), records-per-request-avg(fetch 요청당 평균 메시지 수)로 파악한다. 컨슈머에는 프로듀서의 record-size-avg에 해당하는 지표가 없으므로, 평균 메시지 크기가 필요하면 다른 지표에서 추정하거나 애플리케이션에서 직접 측정해야 한다.
**컨슈머 코디네이터 지표**는 그룹 조정 활동을 다룬다. 컨슈머가 코디네이터 활동 때문에 겪는 가장 큰 문제는 그룹 동기화 중 소비가 멈추는 것이다. 이때 그룹의 컨슈머 인스턴스들이 어떤 파티션을 누가 소비할지 협상하며, 소비 중인 파티션 수에 따라 시간이 꽤 걸릴 수 있다. 코디네이터는 sync-time-avg(동기화 평균 소요 시간, 밀리초)와 sync-rate(초당 그룹 동기화 횟수)를 제공한다. 안정된 컨슈머 그룹이라면 sync-rate는 대부분의 시간 0이어야 한다.
또한 오프셋 커밋은 사실상 produce 요청(전용 요청 타입이긴 하지만 특수 토픽으로 보내는 메시지)이므로, 코디네이터가 제공하는 commit-latency-avg를 프로듀서의 요청 지연처럼 모니터링해야 한다. 기준선을 만들고 그 위에 합리적인 알람 임계값을 두면 된다.
마지막으로 유용한 코디네이터 지표는 assigned-partitions다. 이 컨슈머 인스턴스가 소비하도록 할당받은 파티션 수로, 그룹 내 다른 인스턴스의 값과 비교하면 그룹 전체의 부하 균형을 볼 수 있다. 파티션 분배 알고리즘 문제로 생긴 불균형을 찾아내는 데 쓴다.
핵심 포인트
- 컨슈머 빈 5종 — 핵심은 fetch manager와 coordinator
- fetch-latency-avg는 fetch.min.bytes / fetch.max.wait.ms에 좌우되어 알람이 까다롭다
- bytes/records-consumed-rate에 최소 임계값 알람을 걸면 프로듀서 상태를 가정하게 되어 거짓 알람 위험
- coordinator: sync-time-avg / sync-rate(안정 그룹은 대부분 0) / commit-latency-avg / assigned-partitions
쿼터 — 오류 코드 없이 조용히 느려진다
Kafka는 한 클라이언트가 클러스터 전체를 압도하지 못하도록 클라이언트 요청을 스로틀링할 수 있다. 프로듀서와 컨슈머 모두에 설정 가능하며, 개별 클라이언트 ID가 개별 브로커에 대해 허용되는 트래픽 양을 초당 바이트로 표현한다. 모든 클라이언트에 대한 기본값을 정하는 브로커 설정이 있고, 클라이언트별 오버라이드를 동적으로 설정할 수도 있다.
브로커가 클라이언트의 쿼터 초과를 계산하면, 클라이언트를 쿼터 아래로 유지하기에 충분한 시간만큼 응답을 붙잡아 둠으로써 속도를 늦춘다.
중요한 점은 브로커가 스로틀링 사실을 응답의 오류 코드로 알려 주지 않는다는 것이다. 따라서 클라이언트가 얼마나 오래 스로틀링되고 있는지를 보여 주는 지표를 모니터링하지 않으면 애플리케이션 쪽에서는 스로틀링이 일어나는지조차 알기 어렵다.
- 컨슈머: kafka.consumer:type=consumer-fetch-manager-metrics,client-id=CLIENTID 의 fetch-throttle-time-avg 속성 - 프로듀서: kafka.producer:type=producer-metrics,client-id=CLIENTID 의 produce-throttle-time-avg 속성
쿼터는 브로커에서 기본으로 활성화되어 있지 않지만, 현재 쿼터를 쓰지 않더라도 이 지표들을 모니터링해 두는 것이 안전하다. 나중에 쿼터를 켤 수도 있고, 나중에 지표를 추가하는 것보다 처음부터 모니터링하는 편이 쉽기 때문이다.
핵심 포인트
- 쿼터는 클라이언트 ID 단위 × 브로커 단위, 초당 바이트로 표현
- 브로커는 오류 코드가 아니라 응답을 붙잡아 두는 방식으로 스로틀링한다
- 감지 지표: fetch-throttle-time-avg(컨슈머), produce-throttle-time-avg(프로듀서)
- 쿼터는 기본 비활성이지만 지표는 미리 모니터링해 두는 것이 좋다
Lag 모니터링 — 클라이언트 지표로는 부족하다
Kafka 컨슈머에서 가장 중요하게 모니터링할 것은 컨슈머 lag이다. 메시지 수로 측정되며, 특정 파티션에 마지막으로 생산된 메시지와 컨슈머가 마지막으로 처리한 메시지의 차이다.
이 주제는 보통 컨슈머 클라이언트 모니터링에서 다루지만, 외부 모니터링이 클라이언트 자체 지표를 크게 능가하는 대표적인 사례다. 컨슈머 클라이언트에도 lag 지표(fetch manager 빈의 records-lag-max)가 있지만 두 가지 문제가 있다.
첫째, 이 지표는 가장 많이 뒤처진 파티션 하나의 lag만 보여 준다. 컨슈머가 전체적으로 얼마나 뒤처졌는지를 정확히 나타내지 못한다.
둘째, 이 값은 컨슈머가 정상 동작한다는 전제 위에서만 유효하다. 지표가 fetch 요청마다 컨슈머 자신에 의해 계산되기 때문에, 컨슈머가 고장 났거나 오프라인이면 값이 부정확하거나 아예 없다.
권장되는 방식은 외부 프로세스가 브로커 쪽 파티션 상태(가장 최근 생산된 메시지의 오프셋)와 컨슈머 쪽 상태(컨슈머 그룹이 그 파티션에 대해 마지막으로 커밋한 오프셋)를 함께 감시하는 것이다. 그러면 컨슈머 상태와 무관하게 갱신되는 객관적인 관점을 얻는다. 이 확인은 컨슈머 그룹이 소비하는 모든 파티션에 대해 수행해야 하며, MirrorMaker 같은 대형 컨슈머라면 수만 개 파티션이 될 수도 있다.
커맨드라인 도구로 lag을 보는 방식에도 문제가 있다. 우선 파티션마다 '합리적인 lag'이 얼마인지 이해해야 한다. 시간당 100건을 받는 토픽과 초당 100,000건을 받는 토픽은 임계값이 달라야 한다. 게다가 모든 lag 지표를 모니터링 시스템에 넣고 알람을 걸어야 하는데, 1,500개 토픽의 100,000개 파티션을 소비하는 컨슈머 그룹이라면 벅찬 작업이 된다.
이 복잡도를 줄이는 방법 하나가 Burrow다. LinkedIn이 원래 개발해 오픈소스로 공개한 애플리케이션으로, 클러스터의 모든 컨슈머 그룹에 대한 lag 정보를 모아 그룹별로 '정상 동작 중 / 뒤처지는 중 / 정체 또는 정지'라는 단일 상태를 계산해 준다. 임계값을 요구하지 않고 컨슈머 그룹이 메시지 처리에서 진전을 만들고 있는지를 관찰하는 방식이며, 절대 수치로서의 lag도 함께 얻을 수 있다. Burrow를 배포하면 여러 클러스터에 걸친 모든 컨슈머를 손쉽게 모니터링할 수 있고 기존 모니터링·알람 시스템과 통합하기도 쉽다.
다른 선택지가 전혀 없다면 클라이언트의 records-lag-max로 부분적인 관점이라도 확보해야 하지만, Burrow 같은 외부 모니터링 시스템을 쓰는 편이 강력히 권장된다.
핵심 포인트
- lag = 파티션에 마지막으로 생산된 메시지와 컨슈머가 마지막으로 처리한 메시지의 차이
- records-lag-max는 가장 뒤처진 파티션 하나만 보여 주고, 컨슈머가 정상일 때만 유효하다
- 권장: 외부 프로세스가 브로커의 최신 오프셋과 그룹의 커밋 오프셋을 함께 감시
- Burrow는 임계값 없이 그룹별 단일 상태(정상/뒤처짐/정지)를 계산해 준다
End-to-End 모니터링 — 나는 실제로 쓸 수 있는가
권장되는 또 다른 외부 모니터링은 클라이언트 관점에서 클러스터 건강 상태를 보는 종단 간(end-to-end) 모니터링이다.
컨슈머와 프로듀서 지표는 Kafka 클러스터에 문제가 있을 수 있다는 신호를 주지만, 늘어난 지연이 클라이언트 문제인지 네트워크 문제인지 Kafka 문제인지는 추측 게임이 되기 쉽다. 게다가 클러스터만 운영하고 클라이언트는 남이 운영한다면 모든 클라이언트까지 모니터링해야 하는 상황이 된다.
정작 알아야 할 질문은 두 가지뿐이다. Kafka 클러스터에 메시지를 생산할 수 있는가? Kafka 클러스터에서 메시지를 소비할 수 있는가?
이상적으로는 모든 토픽에 대해 이를 확인하고 싶지만, 대부분의 상황에서 모든 토픽에 합성 트래픽을 주입하는 것은 현실적이지 않다. 그러나 클러스터의 모든 브로커에 대해서는 이 답을 줄 수 있고, 그것이 Kafka Monitor가 하는 일이다. LinkedIn의 Kafka 팀이 오픈소스로 공개한 도구로, 클러스터의 모든 브로커에 퍼져 있는 토픽에 대해 지속적으로 데이터를 생산하고 소비한다. 브로커마다 produce와 consume 요청의 가용성을 측정하고 produce에서 consume까지의 전체 지연도 측정한다.
컨슈머 lag 모니터링과 마찬가지로, Kafka 브로커는 클라이언트가 클러스터를 제대로 쓸 수 있는지를 스스로 보고할 수 없기 때문에 이런 외부 검증이 매우 가치 있다.
핵심 포인트
- 핵심 질문 두 가지: 생산할 수 있는가, 소비할 수 있는가
- Kafka Monitor는 모든 브로커에 걸친 토픽에 합성 트래픽을 흘려 가용성과 produce→consume 지연을 측정
- 브로커는 클라이언트가 클러스터를 쓸 수 있는지 스스로 보고할 수 없다
이 모듈과 연관된 문항 4개가 문제 은행에 있습니다.
이 내용으로 문제 풀어보기