Monitoring Kafka: JMX Exporter, Prometheus a Grafana Dashboard
Tichý Kafkův shluk není zdravý shluk – je to shluk, na který se nedíváte. The spotřebitelské zpoždění která roste, hromadí se nedostatečně replikované oddíly, zvyšuje se latence požadavků – tyto signály předvídají selhání o hodiny nebo dny. V této příručce nakonfigurujeme kompletní monitorovací systém: JMX Exporter, Prometheus, Grafana a výstrahy, které musí mít každý cluster Kafka ve výrobě.
Proč je Kafka Monitoring kritický
Apache Kafka je navržen tak, aby byl odolný, ale odolnost není automatická: vyžaduje aktivní pozorovatelnost. Přetížený broker, skupina spotřebitelů, která nestíhá držet krok s výrobou, nebo oddíl s degradovanou replikací pokud nejsou včas odhaleny, mohou se změnit ve ztrátu dat nebo výpadek.
Tři základní dimenze, které je třeba v Kafkovi sledovat, jsou:
- Zdraví klastru: aktivní zprostředkovatelé, aktivní řadič, nedostatečně replikované oddíly, offline oddíly
- Výkon výrobce: četnost požadavků, četnost chyb záznamu, latence požadavku, velikost dávky
- Výkon spotřebitele: zpoždění spotřebitele na skupinu a na oddíl, četnost odevzdání, frekvence vyvažování
5 nejkritičtějších Kafkových metrik
- kafka.consumer.lag: rozdíl mezi LEO a potvrzeným offsetem – metrika č. 1 pro stav systému
- kafka.server.UnderReplicatedPartitions: oddíly s neúplným ISR — degradovaný signál zprostředkovatele
- kafka.server.OfflinePartitionsCount: oddíly bez vedoucích pozic — kritická chyba, data nedostupná
- kafka.network.RequestMetrics.TotalTimeMs: celková latence požadavků
- kafka.server.BrokerTopicMetrics.MessagesInPerSec: propustnost příjmu
Jak Kafka odhaluje metriky: JMX
Kafka odhaluje všechny své interní metriky prostřednictvím JMX (Java Management Extensions), standardní rámec pro
monitorování aplikací JVM. Každá metrika je označena a MBean jméno ve formátu
dominio:tipo=Tipo,nome=Metrica.
Chcete-li zpřístupnit metriky JMX pro Prometheus, nejpoužívanější monitorovací systém v cloudovém nativním prostředí, používáte Exportér JMX: Java agent, který odhaluje metriky JMX jako koncový bod HTTP ve formátu Prometheus (textový, pull model).
Nakonfigurujte JMX Exporter jako Java Agent
JMX Exporter se spouští jako agent JVM: stačí přidat parametr -javaagent na Kafka broker JVM.
Stáhnete si JAR z oficiálního úložiště Prometheus a vytvoříte konfigurační soubor YAML, který specifikuje
které MBeans sbírat a jak je přejmenovat na metriky Prometheus.
# Scaricare JMX Exporter (ultima versione stabile)
wget https://repo1.maven.org/maven2/io/prometheus/jmx/jmx_prometheus_javaagent/1.0.1/jmx_prometheus_javaagent-1.0.1.jar \
-O /opt/kafka/libs/jmx_prometheus_javaagent.jar
# File di configurazione: /opt/kafka/config/kafka-jmx-exporter.yml
# Questo file dice a JMX Exporter quali MBean raccogliere
# kafka-jmx-exporter.yml
# Configurazione completa per Kafka broker + consumer group lag
---
startDelaySeconds: 0
ssl: false
lowercaseOutputName: true
lowercaseOutputLabelNames: true
rules:
# Metriche Broker: throughput messaggi
- pattern: 'kafka.server<type=BrokerTopicMetrics, name=MessagesInPerSec><>OneMinuteRate'
name: kafka_server_brokertopicmetrics_messagesinpersec
labels:
topic: "$1"
# Under-replicated partitions: CRITICO
- pattern: 'kafka.server<type=ReplicaManager, name=UnderReplicatedPartitions><>Value'
name: kafka_server_replicamanager_underreplicatedpartitions
# Offline partitions: CRITICO
- pattern: 'kafka.controller<type=KafkaController, name=OfflinePartitionsCount><>Value'
name: kafka_controller_kafkacontroller_offlinepartitionscount
# Active controller count (deve essere sempre 1)
- pattern: 'kafka.controller<type=KafkaController, name=ActiveControllerCount><>Value'
name: kafka_controller_kafkacontroller_activecontrollercount
# Request latency per tipo di request
- pattern: 'kafka.network<type=RequestMetrics, name=TotalTimeMs, request=(\w+)><>(Mean|99thPercentile)'
name: kafka_network_requestmetrics_totaltimems
labels:
request: "$1"
quantile: "$2"
# Producer request rate
- pattern: 'kafka.server<type=BrokerTopicMetrics, name=BytesInPerSec><>OneMinuteRate'
name: kafka_server_brokertopicmetrics_bytesinpersec
# Log size per topic-partizione
- pattern: 'kafka.log<type=Log, name=Size, topic=(.+), partition=(\d+)><>Value'
name: kafka_log_log_size
labels:
topic: "$1"
partition: "$2"
# JVM heap usage
- pattern: 'java.lang<type=Memory><>HeapMemoryUsage'
name: jvm_heap_memory_usage
type: GAUGE
Povolte exportér JMX v Brokeru
# Modificare kafka-server-start.sh oppure impostare la variabile d'ambiente
# Aggiungere al file bin/kafka-server-start.sh o configurare systemd
# Opzione 1: variabile d'ambiente KAFKA_OPTS
export KAFKA_OPTS="-javaagent:/opt/kafka/libs/jmx_prometheus_javaagent.jar=9404:/opt/kafka/config/kafka-jmx-exporter.yml"
# Opzione 2: in systemd service file
# [Service]
# Environment="KAFKA_OPTS=-javaagent:/opt/kafka/libs/jmx_prometheus_javaagent.jar=9404:/opt/kafka/config/kafka-jmx-exporter.yml"
# Verificare che l'endpoint funzioni dopo il riavvio
curl http://localhost:9404/metrics | grep kafka_server_replicamanager
Spotřebitelské zpoždění: Nejdůležitější metrika
Il spotřebitelské zpoždění měří, kolik záznamů musí spotřebitel ještě zpracovat: je to rozdíl mezi a Log End Offset (poslední záznam zapsaný v tématu) a Committed Offset (poslední záznam zpracovaný skupinou spotřebitelů). Rostoucí zpoždění naznačuje, že spotřebitelé nedrží krok s rychlostí výroby.
Samotné zpoždění neodhalí metriky JMX makléřů: musí být shromážděny dotazem na koordinátora skupiny spotřebitelů. Standardní nástroj k tomu je Exportér Kafka Lag (projekt Lightbend/open source) nebo plugin kafka_consumer_group samotného Prométhea.
# Docker Compose per Kafka Lag Exporter (alternativa moderna)
# https://github.com/seglo/kafka-lag-exporter
services:
kafka-lag-exporter:
image: seglo/kafka-lag-exporter:0.8.0
ports:
- "8000:8000"
volumes:
- ./lag-exporter.conf:/opt/docker/conf/application.conf
environment:
JAVA_OPTS: "-Xmx256m"
# lag-exporter.conf (formato HOCON)
kafka-lag-exporter {
port = 8000
clusters = [
{
name = "production-cluster"
bootstrap-brokers = "kafka1:9092,kafka2:9092,kafka3:9092"
# Polling interval
poll-interval = 30 seconds
# Consumer groups da monitorare (regex, vuoto = tutti)
consumer-group-whitelist = [".*"]
}
]
# Metriche Prometheus esposte:
# kafka_consumer_group_latest_offset
# kafka_consumer_group_partition_lag
# kafka_consumer_group_sum_lag <-- lag totale per group
# kafka_consumer_group_max_lag <-- lag massimo tra le partizioni
}
Vypočítejte zpoždění pomocí PromQL
# Query PromQL per Grafana / Prometheus
# Lag totale per consumer group
sum(kafka_consumer_group_partition_lag) by (group)
# Top 10 consumer groups per lag
topk(10, sum(kafka_consumer_group_partition_lag) by (group))
# Tasso di crescita del lag (se positivo, i consumer non stanno al passo)
rate(kafka_consumer_group_sum_lag[5m])
# Consumer lag per topic specifico
sum(kafka_consumer_group_partition_lag{topic="ordini-effettuati"}) by (group)
# Alert: lag sopra soglia critica per piu di 5 minuti
# kafka_consumer_group_sum_lag{group="servizio-inventario"} > 10000
Nakonfigurujte Prometheus pro Kafku
Prometheus používá šablonu SEM: je to Prometheus, kdo shromažďuje metriky z koncových bodů
vystavené vývozci podle konfigurovatelného intervalu (scrape_interval).
Konfigurace specifikuje škrábat cíl: Koncové body HTTP pro dotaz.
# prometheus.yml - configurazione per scraping Kafka
global:
scrape_interval: 15s
evaluation_interval: 15s
rule_files:
- "kafka-alerts.yml"
scrape_configs:
# JMX Exporter su ogni broker Kafka
- job_name: "kafka-brokers"
static_configs:
- targets:
- "kafka1:9404"
- "kafka2:9404"
- "kafka3:9404"
relabel_configs:
- source_labels: [__address__]
target_label: broker
regex: "([^:]+):.*"
replacement: "$1"
# Kafka Lag Exporter per consumer group metrics
- job_name: "kafka-lag-exporter"
static_configs:
- targets:
- "kafka-lag-exporter:8000"
scrape_interval: 30s # lag cambia meno frequentemente
# JVM metrics dei broker (se abilitato jvm_exporter separato)
- job_name: "kafka-jvm"
static_configs:
- targets:
- "kafka1:9404"
- "kafka2:9404"
- "kafka3:9404"
metrics_path: /metrics
params:
module: [jvm]
Pravidla výstrah Kafka: Základní pravidla
Pravidla výstrah definují podmínky, které spouštějí oznámení. V Prometheovi se vyjadřují s PromQL a jsou spojeny do samostatných souborů YAML. Zde jsou základní pravidla pro Kafku ve výrobě:
# kafka-alerts.yml - Regole di alert per Prometheus Alertmanager
groups:
- name: kafka.critical
rules:
# Broker down: nessun dato dall'endpoint JMX
- alert: KafkaBrokerDown
expr: up{job="kafka-brokers"} == 0
for: 1m
labels:
severity: critical
annotations:
summary: "Kafka broker {{ $labels.broker }} non raggiungibile"
description: "Il broker {{ $labels.broker }} non risponde da piu di 1 minuto."
# Partizioni offline: CRITICO, dati non accessibili
- alert: KafkaOfflinePartitions
expr: kafka_controller_kafkacontroller_offlinepartitionscount > 0
for: 30s
labels:
severity: critical
annotations:
summary: "{{ $value }} partizioni offline in Kafka"
description: "Partizioni senza leader: dati non leggibili/scrivibili."
# Nessun active controller
- alert: KafkaNoActiveController
expr: sum(kafka_controller_kafkacontroller_activecontrollercount) != 1
for: 1m
labels:
severity: critical
annotations:
summary: "Kafka senza controller attivo"
- name: kafka.warning
rules:
# Under-replicated partitions: replica degradata
- alert: KafkaUnderReplicatedPartitions
expr: kafka_server_replicamanager_underreplicatedpartitions > 0
for: 5m
labels:
severity: warning
annotations:
summary: "{{ $value }} partizioni under-replicated su {{ $labels.broker }}"
description: "Replica degradata: un broker potrebbe essere lento o down."
# Consumer lag critico
- alert: KafkaConsumerLagHigh
expr: sum(kafka_consumer_group_partition_lag) by (group) > 50000
for: 10m
labels:
severity: warning
annotations:
summary: "Consumer lag alto per gruppo {{ $labels.group }}"
description: "Lag: {{ $value }}. I consumer non stanno al passo con la produzione."
# Consumer lag critico prolungato
- alert: KafkaConsumerLagCritical
expr: sum(kafka_consumer_group_partition_lag) by (group) > 200000
for: 5m
labels:
severity: critical
annotations:
summary: "Consumer lag CRITICO per gruppo {{ $labels.group }}"
# JVM heap usage alta
- alert: KafkaBrokerHeapHigh
expr: jvm_heap_memory_usage{area="used"} / jvm_heap_memory_usage{area="max"} > 0.85
for: 5m
labels:
severity: warning
annotations:
summary: "Heap JVM alta su broker Kafka {{ $labels.broker }}"
Grafana Dashboard pro Kafku
Grafana je standardní vizualizační nástroj pro Prometheus. Existují řídicí panely připravené k importu přímo z Grafana Dashboard Hub (grafana.com/dashboards). Nejpoužívanější pro Kafku jsou:
- ID panelu 7589: Přehled Kafka (zdraví zprostředkovatele, propustnost, oddíly)
- ID panelu 9021: Confluent Platform Kafka Metrics
- ID panelu 13282: Kafka Consumer Lag (podrobné zpoždění skupiny spotřebitelů)
Chcete-li importovat řídicí panel do Grafany: Řídicí panely → Import → zadejte ID → vyberte zdroj dat Prometheus.
Klávesové panely, které budete mít na svém řídicím panelu
# Pannello 1: Broker Health Overview
# Stat panel: up/down per ogni broker
up{job="kafka-brokers"}
# Pannello 2: Under-Replicated Partitions
# Stat panel con soglia colorata (verde=0, rosso>0)
sum(kafka_server_replicamanager_underreplicatedpartitions)
# Pannello 3: Consumer Lag per Group (time series)
sum(kafka_consumer_group_partition_lag) by (group)
# Pannello 4: Messages In/Out per secondo
rate(kafka_server_brokertopicmetrics_messagesinpersec[1m])
# Pannello 5: Request Latency p99 (heatmap o time series)
kafka_network_requestmetrics_totaltimems{quantile="99thPercentile"}
# Pannello 6: Disk Usage per Broker
# Utile per pianificare l'espansione storage
node_filesystem_size_bytes{mountpoint="/kafka-data"} -
node_filesystem_avail_bytes{mountpoint="/kafka-data"}
Docker Compose: Kompletní sledování zásobníku
Pro vývojová nebo pracovní prostředí tento Docker Compose spouští celý zásobník monitorování: JMX Exporter (integrovaný do brokera), Kafka Lag Exporter, Prometheus a Grafana.
# docker-compose.monitoring.yml
version: "3.9"
services:
kafka:
image: apache/kafka:4.0.0
container_name: kafka
ports:
- "9092:9092"
- "9404:9404" # JMX Exporter
volumes:
- ./config/kafka-jmx-exporter.yml:/opt/kafka-jmx-exporter.yml
- ./libs/jmx_prometheus_javaagent.jar:/opt/jmx_prometheus_javaagent.jar
environment:
KAFKA_NODE_ID: 1
KAFKA_PROCESS_ROLES: "broker,controller"
KAFKA_LISTENERS: "PLAINTEXT://kafka:9092,CONTROLLER://kafka:9093"
KAFKA_ADVERTISED_LISTENERS: "PLAINTEXT://localhost:9092"
KAFKA_CONTROLLER_LISTENER_NAMES: "CONTROLLER"
KAFKA_CONTROLLER_QUORUM_VOTERS: "1@kafka:9093"
KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: "CONTROLLER:PLAINTEXT,PLAINTEXT:PLAINTEXT"
CLUSTER_ID: "monitoring-demo-cluster"
KAFKA_OPTS: "-javaagent:/opt/jmx_prometheus_javaagent.jar=9404:/opt/kafka-jmx-exporter.yml"
kafka-lag-exporter:
image: seglo/kafka-lag-exporter:0.8.0
container_name: kafka-lag-exporter
ports:
- "8000:8000"
volumes:
- ./config/lag-exporter.conf:/opt/docker/conf/application.conf
depends_on:
- kafka
prometheus:
image: prom/prometheus:v2.50.1
container_name: prometheus
ports:
- "9090:9090"
volumes:
- ./config/prometheus.yml:/etc/prometheus/prometheus.yml
- ./config/kafka-alerts.yml:/etc/prometheus/kafka-alerts.yml
command:
- "--config.file=/etc/prometheus/prometheus.yml"
- "--storage.tsdb.retention.time=30d"
grafana:
image: grafana/grafana:10.3.1
container_name: grafana
ports:
- "3000:3000"
environment:
GF_SECURITY_ADMIN_PASSWORD: "kafka-monitoring"
GF_USERS_ALLOW_SIGN_UP: "false"
volumes:
- grafana-data:/var/lib/grafana
- ./config/grafana-datasources.yml:/etc/grafana/provisioning/datasources/prometheus.yml
- ./config/grafana-dashboards.yml:/etc/grafana/provisioning/dashboards/kafka.yml
volumes:
grafana-data:
Monitorování spotřebitelských zpoždění pomocí Java (programové)
V některých případech je užitečné měřit zpoždění spotřebitele přímo v kódu aplikace, například k vystavení metriky pomocí mikrometru/akčního členu v aplikaci Spring Boot. Tento přístup doplňuje externí monitorování a umožňuje přesnější korelace.
// ConsumerLagMonitor.java - Misura il lag programmaticamente con Kafka AdminClient
import org.apache.kafka.clients.admin.*;
import org.apache.kafka.clients.consumer.OffsetAndMetadata;
import org.apache.kafka.common.*;
import java.util.*;
import java.util.concurrent.*;
import java.util.stream.*;
public class ConsumerLagMonitor {
private final AdminClient adminClient;
private final String groupId;
public ConsumerLagMonitor(String bootstrapServers, String groupId) {
Properties props = new Properties();
props.put("bootstrap.servers", bootstrapServers);
this.adminClient = AdminClient.create(props);
this.groupId = groupId;
}
public Map<TopicPartition, Long> getLagPerPartition() throws ExecutionException, InterruptedException {
// 1. Recupera committed offsets del consumer group
ListConsumerGroupOffsetsResult offsetsResult =
adminClient.listConsumerGroupOffsets(groupId);
Map<TopicPartition, OffsetAndMetadata> committedOffsets =
offsetsResult.partitionsToOffsetAndMetadata().get();
// 2. Recupera l'end offset (Log End Offset) per le stesse partizioni
Map<TopicPartition, OffsetSpec> latestOffsetRequest = committedOffsets.keySet().stream()
.collect(Collectors.toMap(tp -> tp, tp -> OffsetSpec.latest()));
ListOffsetsResult latestOffsets = adminClient.listOffsets(latestOffsetRequest);
Map<TopicPartition, ListOffsetsResult.ListOffsetsResultInfo> endOffsets =
latestOffsets.all().get();
// 3. Calcola il lag = endOffset - committedOffset
Map<TopicPartition, Long> lag = new HashMap<>();
for (Map.Entry<TopicPartition, OffsetAndMetadata> entry : committedOffsets.entrySet()) {
TopicPartition tp = entry.getKey();
long committedOffset = entry.getValue().offset();
long endOffset = endOffsets.get(tp).offset();
lag.put(tp, Math.max(0, endOffset - committedOffset));
}
return lag;
}
public long getTotalLag() throws ExecutionException, InterruptedException {
return getLagPerPartition().values().stream()
.mapToLong(Long::longValue)
.sum();
}
public void close() {
adminClient.close();
}
}
Nejlepší postupy pro monitorování Kafky
Anti-Pattern: Alert on Every Spike of Lag
Zpoždění spotřebitele přirozeně kolísá: momentální vrchol ve výrobě nebo pauza spotřebitele GC
způsobují dočasné zpoždění, které se rychle obnoví. Nakonfigurujte upozornění na absolutní prahové hodnoty bez
časové okno (for: 10m) generuje neustále falešně pozitivní výsledky.
Před spuštěním výstrahy vždy používejte minimální dobu trvání (5-10 minut).
-
Sledujte trend, ne absolutní hodnotu: Klesající zpoždění o 100 000 je méně znepokojivé
rostoucího zpoždění 5K. USA
rate()v PromQL vidět derivát. - Oddělte panely podle osob: provozní panel s kritickými výstrahami pro SRE, řídicí panel plánování kapacity pro týmy infrastruktury, řídicí panel obchodních klíčových ukazatelů výkonu pro produktové manažery.
-
Zahrnout metriky JVM: 30 % problémů s výkonem Kafky pochází z tlaku GC
o makléře. Vždy sledujte
jvm_gc_pause_secondsa využití haldy. - Uchovávejte Prometheus alespoň 30 dní: pro analýzu trendů a měsíční plánování kapacity. Zvažte Thanose nebo Mimira pro dlouhodobé uchování.
-
Testovat upozornění pomocí
amtool: Ověřte, že pravidla výstrah jsou syntakticky správná správné a že se spouštějí s očekávanými testovacími daty před uvedením do výroby.
Kafka v Cloud Managed: Confluent Cloud Metrics API
Pokud používáte Confluent Cloud nebo spravovanou službu Kafka (AWS MSK, Aiven Kafka), metriky JMX nejsou přímo přístupný. V tomto případě použijeme Metrics API poskytovatele cloudu. Confluent Cloud zpřístupňuje Metrics REST API kompatibilní s Prometheus prostřednictvím remote_write:
# prometheus.yml per Confluent Cloud Metrics API
scrape_configs:
- job_name: "confluent-cloud"
honor_timestamps: true
metrics_path: "/v2/metrics/cloud/export"
scheme: https
basic_auth:
username: "<CONFLUENT_CLOUD_API_KEY>"
password: "<CONFLUENT_CLOUD_API_SECRET>"
static_configs:
- targets:
- "api.telemetry.confluent.cloud"
params:
resource.kafka.id:
- "<CLUSTER_ID>"
# Per AWS MSK: usa il CloudWatch exporter
# https://github.com/prometheus/cloudwatch_exporter
scrape_configs:
- job_name: "aws-msk"
static_configs:
- targets:
- "cloudwatch-exporter:9106"
Shrnutí: Kafka Monitoring Checklist
- JMX Exporter nakonfigurován na všech brokerech, port 9404
- Kafka Lag Exporter nebo ekvivalent pro metriky skupiny spotřebitelů
- Prometheus s intervalem stírání 15s pro brokera, 30s pro lag exportéra
- Kritická upozornění: výpadek zprostředkovatele, offline oddíly, žádný aktivní řadič
- Upozornění: nedostatečně replikované oddíly, velké zpoždění spotřebitele, halda > 85 %
- Importován řídicí panel Grafana (ID 7589 pro přehled, ID 13282 pro zpoždění)
- Uchovávání Prometheus minimálně 30 dní
- Upozornění testována s minimální dobou trvání (po dobu: 5 m), aby se zabránilo falešně pozitivním výsledkům
Další kroky v sérii
Nastavili jste sledování. Dalším krokem je vědět, co dělat, když nastanou problémy:
- Článek 10 – Fronta nedoručených zpráv a zpracování chyb: vzory pro správu zpráv které se nepodaří zpracovat, včetně DLQ, exponenciálního opakování a detekce jedových pilulek.
- Článek 11 – Kafka ve výrobě: kompletní provozní příručka pro dimenzování clusteru, optimální konfiguraci faktorů uchovávání a replikace a MirrorMaker 2 pro obnovu po havárii.
Propojení s ostatními sériemi
- Apache Kafka Fundamentals (článek 1): Koncept spotřebitelského zpoždění vyžaduje pochopení rozdíl mezi LEO, HW a potvrzeným offsetem vysvětlený v prvním článku série.
- Event-Driven Architecture: Sledování zpoždění spotřebitelů je také zásadní v systémech EDA s AWS SQS a SNS, kde ekvivalentní metrikou je hloubka fronty.







