Monitoring Kafka: JMX-exporteur, Prometheus en Grafana Dashboard
Een stil Kafka-cluster is geen gezond cluster; het is een cluster waar je niet naar kijkt. De vertraging van de consument dat groeit, te weinig gerepliceerde partities stapelen zich op, de latentie van verzoeken neemt toe: deze signalen anticiperen op fouten met uren of dagen. In deze handleiding configureren we een compleet monitoringsysteem: JMX Exporter, Prometheus, Grafana en de waarschuwingen die elk Kafka-cluster in productie moet hebben.
Waarom Kafka-monitoring van cruciaal belang is
Apache Kafka is ontworpen om veerkrachtig te zijn, maar veerkracht is niet automatisch: het vereist actieve waarneembaarheid. Een overbelaste makelaar, een consumentengroep die de productie niet kan bijhouden, of een partitie met een verminderde replicatie als ze niet tijdig worden opgemerkt, kunnen ze leiden tot gegevensverlies of downtime.
De drie fundamentele dimensies die in Kafka moeten worden gemonitord zijn:
- Clustergezondheid: actieve makelaars, actieve controller, te weinig gerepliceerde partities, offline partities
- Prestaties van de producent: verzoeksnelheid, recordfoutenpercentage, latentie van verzoeken, batchgrootte
- Consumentenprestaties: consumentenvertraging per groep en per partitie, commit-snelheid, frequentie van herbalanceren
De 5 meest kritische Kafka-statistieken
- kafka.consumer.lag: verschil tussen LEO en vastgelegde offset — de nummer 1 maatstaf voor systeemgezondheid
- kafka.server.UnderReplicatedPartitions: partities met onvolledige ISR - verslechterd brokersignaal
- kafka.server.OfflinePartitionsCount: leiderloze partities - kritieke fout, gegevens ontoegankelijk
- kafka.network.RequestMetrics.TotalTimeMs: totale latentie van verzoeken
- kafka.server.BrokerTopicMetrics.MessagesInPerSec: opnamedoorvoer
Hoe Kafka statistieken blootlegt: JMX
Kafka maakt al zijn interne statistieken openbaar via JMX (Java-beheerextensies), het standaardframework voor
monitoring van JVM-applicaties. Elke metriek wordt geïdentificeerd door een MBean-naam in het formaat
dominio:tipo=Tipo,nome=Metrica.
Om JMX-statistieken toegankelijk te maken voor Prometheus, het meest gebruikte monitoringsysteem in een cloud-native omgeving, jij gebruikt de JMX-exporteur: een Java-agent die JMX-statistieken beschikbaar stelt als een HTTP-eindpunt in Prometheus-formaat (op tekst gebaseerd, pull-model).
Configureer JMX Exporter als Java-agent
JMX Exporter wordt gestart als een JVM-agent: voeg gewoon de parameter toe -javaagent aan de Kafka-makelaar JVM.
U downloadt de JAR uit de officiële Prometheus-repository en maakt een YAML-configuratiebestand dat specificeert
welke MBeans je moet verzamelen en hoe je ze kunt hernoemen naar Prometheus-statistieken.
# 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
Schakel JMX Exporter in de Broker in
# 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
Consumentenvertraging: de belangrijkste maatstaf
Il vertraging van de consument meet hoeveel records de consument nog moet verwerken: het is het verschil daartussen de Logeinde-offset (de laatste record die in het onderwerp is geschreven) en de Toegewijde compensatie (het laatste record dat door de consumentengroep is verwerkt). Een toenemende vertraging geeft aan dat consumenten de snelheid van de productie niet kunnen bijhouden.
De vertraging alleen onthult de JMX-statistieken van de makelaars niet: deze moeten worden verzameld door de coördinator van de consumentengroep te ondervragen. Het standaardhulpmiddel hiervoor is Kafka Lag-exporteur (Lightbend/open source-project) of de plug-in kafka_consumentengroep van Prometheus zelf.
# 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
}
Bereken vertraging met 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
Configureer Prometheus voor Kafka
Prometheus gebruikt een sjabloon trekken: het is Prometheus die statistieken van de eindpunten verzamelt
blootgesteld door exporteurs, volgens een configureerbaar interval (scrape_interval).
De configuratie specificeert de doel schrapen: De HTTP-eindpunten die moeten worden opgevraagd.
# 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]
Waarschuwingsregels Kafka: de essentiële regels
De waarschuwingsregels definiëren de voorwaarden die een melding activeren. In Prometheus drukken ze zich uit met PromQL en worden gebundeld in afzonderlijke YAML-bestanden. Hier zijn de basisregels voor Kafka in productie:
# 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 voor Kafka
Grafana is de standaard visualisatietool voor Prometheus. Er zijn kant-en-klare dashboards rechtstreeks vanuit de Grafana Dashboard Hub (grafana.com/dashboards). De meest gebruikte voor Kafka zijn:
- Dashboard-ID 7589: Kafka-overzicht (brokerstatus, doorvoer, partities)
- Dashboard-ID 9021: Confluent Platform Kafka-statistieken
- Dashboard-ID 13282: Kafka Consumer Lag (gedetailleerde vertraging van de consumentengroep)
Om een dashboard in Grafana te importeren: Dashboards → Importeren → voer ID in → selecteer Prometheus-gegevensbron.
Belangrijke panelen voor uw dashboard
# 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: complete stackmonitoring
Voor ontwikkelings- of faseringsomgevingen lanceert deze Docker Compose de volledige monitoringstack: JMX Exporter (geïntegreerd in de makelaar), Kafka Lag Exporter, Prometheus en 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:
Monitoring van consumentenvertraging met Java (programmatisch)
In sommige gevallen is het nuttig om de consumentenvertraging rechtstreeks in de applicatiecode te meten, bijvoorbeeld om statistiek bloot te leggen via micrometer/actuator in een Spring Boot-toepassing. Deze aanpak is complementair aan externe monitoring en maakt nauwkeurigere correlaties mogelijk.
// 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();
}
}
Beste praktijken voor het monitoren van Kafka
Anti-patroon: waarschuwing bij elke piek in vertraging
De vertraging van de consument fluctueert op natuurlijke wijze: een tijdelijke piek in de productie of een pauze van de consumentenconsumptie
ze veroorzaken een tijdelijke vertraging die snel herstelt. Configureer waarschuwingen op absolute drempels zonder
een tijdvenster (for: 10m) genereert voortdurend valse positieven.
Houd altijd een minimumduur (5-10 minuten) aan voordat u de waarschuwing activeert.
-
Houd de trend in de gaten, niet de absolute waarde: Een afnemende vertraging van 100K is minder zorgwekkend
van een groeiende vertraging van 5K. VS
rate()in PromQL om de afgeleide te zien. - Aparte dashboards per persoon: een operationeel dashboard met kritische waarschuwingen voor SRE's, een dashboard voor capaciteitsplanning voor infrastructuurteams, een zakelijk KPI-dashboard voor productmanagers.
-
Voeg JVM-statistieken toe: 30% van de prestatieproblemen van Kafka komt voort uit GC-druk
over de makelaar. Houd altijd toezicht
jvm_gc_pause_secondsen heapgebruik. - Bewaar Prometheus minimaal 30 dagen: voor trendanalyse en maandelijkse capaciteitsplanning. Overweeg Thanos of Mimir voor langdurige retentie.
-
Test waarschuwingen met
amtool: Controleer of de waarschuwingsregels syntactisch correct zijn correct zijn en dat ze worden geactiveerd met de verwachte testgegevens voordat ze in productie gaan.
Kafka in Cloud Managed: Confluente Cloud Metrics-API
Als u Confluent Cloud of een beheerde Kafka-service (AWS MSK, Aiven Kafka) gebruikt, zijn JMX-statistieken niet direct toegankelijk. In dit geval gebruiken wij de Metriek-API van de cloudaanbieder. Confluent Cloud stelt een Prometheus-compatibele Metrics REST API beschikbaar via 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"
Samenvatting: Kafka-monitoringchecklist
- JMX Exporter geconfigureerd op alle makelaars, poort 9404
- Kafka Lag Exporter of gelijkwaardig voor statistieken over consumentengroepen
- Prometheus met schraapinterval 15s voor makelaar, 30s voor lag-exporteur
- Kritieke waarschuwingen: broker defect, offline partities, geen actieve controller
- Waarschuwingswaarschuwing: te weinig gerepliceerde partities, hoge consumentenvertraging, heap> 85%
- Grafana-dashboard geïmporteerd (ID 7589 voor overzicht, ID 13282 voor vertraging)
- Bewaartermijn Prometheus minimaal 30 dagen
- Alarmen getest met een minimale duur (voor: 5 m) om valse positieven te voorkomen
Volgende stappen in de serie
U hebt monitoring geconfigureerd. De volgende stap is weten wat u moet doen als er zich problemen voordoen:
- Artikel 10 – Dead Letter-wachtrij en foutafhandeling: patronen voor het beheren van berichten die niet kunnen worden verwerkt, waaronder DLQ, exponentiële nieuwe pogingen en detectie van gifpillen.
- Artikel 11 – Kafka in productie: complete operationele gids voor clustergrootte, de optimale configuratie van retentie- en replicatiefactoren, en MirrorMaker 2 voor noodherstel.
Link met andere series
- Apache Kafka-grondbeginselen (artikel 1): Het concept van consumentenvertraging vereist begrip het verschil tussen LEO, HW en vastgelegde compensatie wordt uitgelegd in het eerste artikel van de serie.
- Gebeurtenisgestuurde architectuur: Het monitoren van de consumentenvertraging is ook van cruciaal belang in EDA-systemen met AWS SQS en SNS, waarbij de equivalente maatstaf de wachtrijdiepte is.







