kafka_exporter 는 Kafka 프로토콜로 접속해 토픽 오프셋과 컨슈머 그룹 오프셋을 읽어 Prometheus 지표로 내보낸다. JMX Exporter 가 브로커 내부 지표를 보는 것과 달리, 이쪽은 컨슈머 그룹 lag 을 보는 데 쓴다. 두 가지는 용도가 다르므로 대개 함께 둔다.
기동·정지 스크립트를 직접 만드는 대신 systemd 에 맡기면 상태 확인과 자동 재기동이 함께 해결된다.
[Unit]
Description=Kafka Exporter
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
User=monitor
Group=monitor
ExecStart=/apps/kafka_export/bin/kafka_exporter \
--kafka.server=broker01.example.com:9092 \
--kafka.server=broker02.example.com:9092 \
--kafka.server=broker03.example.com:9092 \
--web.listen-address=:60002
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
브로커를 여러 대 지정할 때는 --kafka.server 를 여러 번 적는다. 쉼표로 이어 붙이지 않는다.
인증이 있는 클러스터는 옵션을 더한다.
--sasl.enabled --sasl.mechanism=plain --sasl.username=${KAFKA_USER} --sasl.password=${KAFKA_PASSWORD}
--tls.enabled --tls.ca-file=/etc/pki/ca.crt
비밀번호를 유닛 파일에 직접 적지 말고 EnvironmentFile 로 분리해 권한을 600 으로 둔다.
node_exporter 도 같은 형태로 등록한다.
[Service]
Type=simple
User=monitor
ExecStart=/apps/node_export/bin/node_exporter --web.listen-address=:60001
Restart=on-failure
systemctl daemon-reload
systemctl enable --now kafka_exporter node_exporter
systemctl status kafka_exporter
curl -s localhost:60002/metrics | grep -c '^kafka_'
scrape_configs:
- job_name: 'kafka'
static_configs:
- targets:
- 'broker01.example.com:60002'
- job_name: 'node'
static_configs:
- targets:
- 'broker01.example.com:60001'
- 'broker02.example.com:60001'
- 'broker03.example.com:60001'
kafka_exporter 는 클러스터 전체를 조회하므로 한 곳에서만 돌려도 된다. 가용성이 필요하면 두 곳에서 돌리고 중복 지표는 집계 시 처리한다.
주요 지표 이름은 다음과 같다.
| 지표 | 의미 |
|---|---|
kafka_consumergroup_lag |
그룹·토픽·파티션별 남은 건수 |
kafka_consumergroup_current_offset |
그룹이 커밋한 오프셋 |
kafka_topic_partition_current_offset |
파티션의 마지막 오프셋 |
kafka_topic_partition_oldest_offset |
파티션의 가장 오래된 오프셋 |
kafka_brokers |
브로커 수 |
그룹·토픽 단위 합계가 실무에서 가장 많이 쓰인다.
sum(kafka_consumergroup_lag) by (consumergroup, topic)
그룹 전체 합계는 다음과 같다.
sum(kafka_consumergroup_lag) by (consumergroup)
lag 이 쌓이는 추세인지 보려면 증가율을 본다. 순간값 하나로는 일시적 밀림과 진짜 정체를 구분하지 못한다.
deriv(sum(kafka_consumergroup_lag) by (consumergroup)[10m:])
lag 을 시간으로 환산하려면 소비 속도로 나눈다. 건수보다 직관적이다.
sum(kafka_consumergroup_lag) by (consumergroup)
/ on(consumergroup) (sum(rate(kafka_consumergroup_current_offset[5m])) by (consumergroup) > 0)
유입량은 파티션 오프셋의 증가율로 본다.
sum(rate(kafka_topic_partition_current_offset[5m])) by (topic)
groups:
- name: kafka
rules:
- alert: KafkaConsumerLagHigh
expr: sum(kafka_consumergroup_lag) by (consumergroup, topic) > 100000
for: 10m
labels:
severity: warning
annotations:
summary: '{{ $labels.consumergroup }} 그룹의 {{ $labels.topic }} lag 이 10 분 이상 높다'
- alert: KafkaConsumerStalled
expr: sum(rate(kafka_consumergroup_current_offset[10m])) by (consumergroup) == 0
and sum(kafka_consumergroup_lag) by (consumergroup) > 0
for: 10m
labels:
severity: critical
annotations:
summary: '{{ $labels.consumergroup }} 그룹이 소비를 멈췄다'
임계값을 절대 건수로 두면 토픽마다 적정 값이 달라 오탐이 잦다. 멈춤 여부(소비 속도 0)와 추세를 함께 보는 편이 실효가 있다.
지표 이름은 exporter 버전에 따라 달라질 수 있으므로 /metrics 를 직접 확인한 뒤 질의를 쓴다.