feat(monitoring): add Kafka monitoring via kafka-exporter

- Add kafka-exporter service to docker-compose.yml
- Add kafka job to prometheus.yml scrape configs
- Add Kafka Overview dashboard (Grafana provisioning)
- Add Kafka alert rules (broker down, consumer lag, etc.)
- Add make reload-monitoring command for easy updates
- Update OPERATIONS.md with TL;DR and troubleshooting

API verified via Context7:
- /danielqsj/kafka_exporter for exporter config
- /prometheus/docs for scrape_configs format
This commit is contained in:
2026-02-08 21:25:31 +03:00
parent 41c867d68d
commit ae593fd08c
7 changed files with 1219 additions and 11 deletions
@@ -0,0 +1,281 @@
apiVersion: 1
groups:
- orgId: 1
name: kafka_health_group
folder: Kafka Alerts
interval: 1m
rules:
# --- Alert: Kafka Broker Down ---
- uid: kafka_broker_down
title: Kafka Broker Down
condition: C
data:
- refId: A
relativeTimeRange:
from: 300
to: 0
datasourceUid: prometheus_uid
model:
datasource:
type: prometheus
uid: prometheus_uid
editorMode: code
expr: kafka_brokers
instant: false
intervalMs: 1000
legendFormat: __auto
maxDataPoints: 43200
range: true
refId: A
- refId: B
datasourceUid: __expr__
model:
conditions:
- evaluator:
params:
- 1
type: lt
operator:
type: and
query:
params:
- B
reducer:
params: []
type: last
type: query
datasource:
type: __expr__
uid: __expr__
expression: A
intervalMs: 1000
maxDataPoints: 43200
refId: B
type: threshold
- refId: C
datasourceUid: __expr__
model:
conditions:
- evaluator:
params:
- 0
type: gt
operator:
type: and
query:
params:
- C
reducer:
params: []
type: last
type: query
datasource:
type: __expr__
uid: __expr__
expression: B
intervalMs: 1000
maxDataPoints: 43200
refId: C
type: threshold
noDataState: Alerting
execErrState: Error
for: 1m
annotations:
summary: "Kafka broker недоступен"
description: "Количество доступных брокеров: {{ $values.A }} (ожидается ≥ 1)"
labels:
severity: critical
# --- Alert: High Consumer Lag ---
- uid: kafka_consumer_lag_high
title: Kafka Consumer Lag High
condition: C
data:
- refId: A
relativeTimeRange:
from: 300
to: 0
datasourceUid: prometheus_uid
model:
datasource:
type: prometheus
uid: prometheus_uid
editorMode: code
expr: kafka_consumer_group_lag
instant: false
intervalMs: 1000
legendFormat: "{{ group }} - {{ topic }}:{{ partition }}"
maxDataPoints: 43200
range: true
refId: A
- refId: B
datasourceUid: __expr__
model:
conditions:
- evaluator:
params:
- 10000
type: gt
operator:
type: and
query:
params:
- B
reducer:
params: []
type: last
type: query
datasource:
type: __expr__
uid: __expr__
expression: A
intervalMs: 1000
maxDataPoints: 43200
refId: B
type: threshold
- refId: C
datasourceUid: __expr__
model:
conditions:
- evaluator:
params:
- 0
type: gt
operator:
type: and
query:
params:
- C
reducer:
params: []
type: last
type: query
datasource:
type: __expr__
uid: __expr__
expression: B
intervalMs: 1000
maxDataPoints: 43200
refId: C
type: threshold
noDataState: NoData
execErrState: Error
for: 5m
annotations:
summary: "Высокий лаг консьюмера {{ $labels.group }}"
description: "Lag для {{ $labels.topic }}:{{ $labels.partition }} составляет {{ $values.A }} сообщений (порог: 10000)"
labels:
severity: warning
# --- Alert: No Messages Produced ---
- uid: kafka_no_messages_produced
title: Kafka No Messages Produced
condition: C
data:
- refId: A
relativeTimeRange:
from: 600
to: 0
datasourceUid: prometheus_uid
model:
datasource:
type: prometheus
uid: prometheus_uid
editorMode: code
expr: rate(kafka_topic_partition_current_offset[5m])
instant: false
intervalMs: 1000
legendFormat: "{{ topic }}"
maxDataPoints: 43200
range: true
refId: A
- refId: B
datasourceUid: __expr__
model:
conditions:
- evaluator:
params:
- 0.1
type: lt
operator:
type: and
query:
params:
- B
reducer:
params: []
type: last
type: query
datasource:
type: __expr__
uid: __expr__
expression: A
intervalMs: 1000
maxDataPoints: 43200
refId: B
type: threshold
- refId: C
datasourceUid: __expr__
model:
conditions:
- evaluator:
params:
- 0
type: gt
operator:
type: and
query:
params:
- C
reducer:
params: []
type: last
type: query
datasource:
type: __expr__
uid: __expr__
expression: B
intervalMs: 1000
maxDataPoints: 43200
refId: C
type: threshold
noDataState: NoData
execErrState: Error
for: 10m
annotations:
summary: "В топик {{ $labels.topic }} не поступают сообщения"
description: "Rate сообщений < 0.1 msg/sec в течение 10 минут"
labels:
severity: warning
# --- Alert: Consumer Group Missing ---
- uid: kafka_consumer_group_missing
title: Kafka Consumer Group Missing
condition: C
data:
- refId: A
relativeTimeRange:
from: 300
to: 0
datasourceUid: prometheus_uid
model:
datasource:
type: prometheus
uid: prometheus_uid
editorMode: code
expr: count by (group) (kafka_consumer_group_lag)
instant: true
intervalMs: 1000
legendFormat: "{{ group }}"
maxDataPoints: 43200
range: false
refId: A
noDataState: Alerting
execErrState: Error
for: 5m
annotations:
summary: "Пропала консьюмер-группа"
description: "Консьюмер-группа не обнаружена в течение 5 минут"
labels:
severity: info
@@ -0,0 +1,608 @@
{
"annotations": {
"list": [
{
"builtIn": 1,
"datasource": {
"type": "grafana",
"uid": "-- Grafana --"
},
"enable": true,
"hide": true,
"iconColor": "rgba(0, 211, 255, 1)",
"name": "Annotations & Alerts",
"type": "dashboard"
}
]
},
"description": "Обзор метрик Kafka через kafka-exporter",
"editable": true,
"fiscalYearStartMonth": 0,
"graphTooltip": 0,
"id": null,
"links": [],
"panels": [
{
"collapsed": false,
"gridPos": {
"h": 1,
"w": 24,
"x": 0,
"y": 0
},
"id": 11,
"panels": [],
"title": "Cluster Health",
"type": "row"
},
{
"datasource": {
"type": "prometheus",
"uid": "prometheus_uid"
},
"fieldConfig": {
"defaults": {
"color": {
"mode": "thresholds"
},
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "red",
"value": 0
},
{
"color": "green",
"value": 1
}
]
},
"unit": "none"
},
"overrides": []
},
"gridPos": {
"h": 4,
"w": 6,
"x": 0,
"y": 1
},
"id": 1,
"options": {
"colorMode": "value",
"graphMode": "area",
"justifyMode": "auto",
"orientation": "auto",
"percentChangeColorMode": "standard",
"reduceOptions": {
"calcs": [
"lastNotNull"
],
"fields": "",
"values": false
},
"showPercentChange": false,
"textMode": "auto",
"wideLayout": true
},
"pluginVersion": "11.0.8",
"targets": [
{
"datasource": {
"type": "prometheus",
"uid": "prometheus_uid"
},
"expr": "kafka_brokers",
"refId": "A"
}
],
"title": "Brokers Up",
"type": "stat"
},
{
"datasource": {
"type": "prometheus",
"uid": "prometheus_uid"
},
"fieldConfig": {
"defaults": {
"color": {
"mode": "continuous-GrYlRd"
},
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green"
}
]
},
"unit": "none"
},
"overrides": []
},
"gridPos": {
"h": 4,
"w": 6,
"x": 6,
"y": 1
},
"id": 2,
"options": {
"colorMode": "value",
"graphMode": "area",
"justifyMode": "auto",
"orientation": "auto",
"percentChangeColorMode": "standard",
"reduceOptions": {
"calcs": [
"lastNotNull"
],
"fields": "",
"values": false
},
"showPercentChange": false,
"textMode": "auto",
"wideLayout": true
},
"pluginVersion": "11.0.8",
"targets": [
{
"datasource": {
"type": "prometheus",
"uid": "prometheus_uid"
},
"expr": "count(count by (topic) (kafka_topic_partitions))",
"refId": "A"
}
],
"title": "Topics",
"type": "stat"
},
{
"datasource": {
"type": "prometheus",
"uid": "prometheus_uid"
},
"fieldConfig": {
"defaults": {
"color": {
"mode": "continuous-BlPu"
},
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green"
}
]
},
"unit": "none"
},
"overrides": []
},
"gridPos": {
"h": 4,
"w": 6,
"x": 12,
"y": 1
},
"id": 3,
"options": {
"colorMode": "value",
"graphMode": "area",
"justifyMode": "auto",
"orientation": "auto",
"percentChangeColorMode": "standard",
"reduceOptions": {
"calcs": [
"lastNotNull"
],
"fields": "",
"values": false
},
"showPercentChange": false,
"textMode": "auto",
"wideLayout": true
},
"pluginVersion": "11.0.8",
"targets": [
{
"datasource": {
"type": "prometheus",
"uid": "prometheus_uid"
},
"expr": "sum(kafka_topic_partitions)",
"refId": "A"
}
],
"title": "Total Partitions",
"type": "stat"
},
{
"datasource": {
"type": "prometheus",
"uid": "prometheus_uid"
},
"fieldConfig": {
"defaults": {
"color": {
"mode": "thresholds"
},
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green"
}
]
},
"unit": "none"
},
"overrides": []
},
"gridPos": {
"h": 4,
"w": 6,
"x": 18,
"y": 1
},
"id": 4,
"options": {
"colorMode": "value",
"graphMode": "area",
"justifyMode": "auto",
"orientation": "auto",
"percentChangeColorMode": "standard",
"reduceOptions": {
"calcs": [
"lastNotNull"
],
"fields": "",
"values": false
},
"showPercentChange": false,
"textMode": "auto",
"wideLayout": true
},
"pluginVersion": "11.0.8",
"targets": [
{
"datasource": {
"type": "prometheus",
"uid": "prometheus_uid"
},
"expr": "count(count by (group) (kafka_consumergroup_lag))",
"refId": "A"
}
],
"title": "Consumer Groups",
"type": "stat"
},
{
"collapsed": false,
"gridPos": {
"h": 1,
"w": 24,
"x": 0,
"y": 5
},
"id": 12,
"panels": [],
"title": "Throughput",
"type": "row"
},
{
"datasource": {
"type": "prometheus",
"uid": "prometheus_uid"
},
"fieldConfig": {
"defaults": {
"color": {
"mode": "palette-classic"
},
"custom": {
"axisBorderShow": false,
"axisCenteredZero": false,
"axisColorMode": "text",
"axisLabel": "",
"axisPlacement": "auto",
"barAlignment": 0,
"drawStyle": "line",
"fillOpacity": 20,
"gradientMode": "none",
"hideFrom": {
"legend": false,
"tooltip": false,
"viz": false
},
"insertNulls": false,
"lineInterpolation": "smooth",
"lineWidth": 1,
"pointSize": 5,
"scaleDistribution": {
"type": "linear"
},
"showPoints": "auto",
"spanNulls": false,
"stacking": {
"group": "A",
"mode": "none"
},
"thresholdsStyle": {
"mode": "off"
}
},
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green"
}
]
},
"unit": "cps"
},
"overrides": []
},
"gridPos": {
"h": 8,
"w": 12,
"x": 0,
"y": 6
},
"id": 5,
"options": {
"legend": {
"calcs": [],
"displayMode": "table",
"placement": "right",
"showLegend": true
},
"tooltip": {
"maxHeight": 600,
"mode": "single",
"sort": "none"
}
},
"targets": [
{
"datasource": {
"type": "prometheus",
"uid": "prometheus_uid"
},
"expr": "kafka_topic_partition_current_offset",
"legendFormat": "{{topic}} - p{{partition}}",
"refId": "A"
}
],
"title": "Messages In / sec by Topic",
"type": "timeseries"
},
{
"datasource": {
"type": "prometheus",
"uid": "prometheus_uid"
},
"fieldConfig": {
"defaults": {
"color": {
"mode": "palette-classic"
},
"custom": {
"axisBorderShow": false,
"axisCenteredZero": false,
"axisColorMode": "text",
"axisLabel": "",
"axisPlacement": "auto",
"barAlignment": 0,
"drawStyle": "line",
"fillOpacity": 20,
"gradientMode": "none",
"hideFrom": {
"legend": false,
"tooltip": false,
"viz": false
},
"insertNulls": false,
"lineInterpolation": "smooth",
"lineWidth": 1,
"pointSize": 5,
"scaleDistribution": {
"type": "linear"
},
"showPoints": "auto",
"spanNulls": false,
"stacking": {
"group": "A",
"mode": "none"
},
"thresholdsStyle": {
"mode": "off"
}
},
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": 0
},
{
"color": "yellow",
"value": 1000
},
{
"color": "red",
"value": 10000
}
]
},
"unit": "none"
},
"overrides": []
},
"gridPos": {
"h": 8,
"w": 12,
"x": 12,
"y": 6
},
"id": 6,
"options": {
"legend": {
"calcs": [],
"displayMode": "table",
"placement": "right",
"showLegend": true
},
"tooltip": {
"maxHeight": 600,
"mode": "single",
"sort": "none"
}
},
"pluginVersion": "11.0.8",
"targets": [
{
"datasource": {
"type": "prometheus",
"uid": "prometheus_uid"
},
"expr": "kafka_consumergroup_lag",
"legendFormat": "{{group}} - {{topic}}:{{partition}}",
"refId": "A"
}
],
"title": "Consumer Lag by Group",
"type": "timeseries"
},
{
"collapsed": false,
"gridPos": {
"h": 1,
"w": 24,
"x": 0,
"y": 14
},
"id": 13,
"panels": [],
"title": "Partitions",
"type": "row"
},
{
"datasource": {
"type": "prometheus",
"uid": "prometheus_uid"
},
"fieldConfig": {
"defaults": {
"color": {
"mode": "palette-classic"
},
"custom": {
"axisBorderShow": false,
"axisCenteredZero": false,
"axisColorMode": "text",
"axisLabel": "",
"axisPlacement": "auto",
"barAlignment": 0,
"drawStyle": "line",
"fillOpacity": 0,
"gradientMode": "none",
"hideFrom": {
"legend": false,
"tooltip": false,
"viz": false
},
"insertNulls": false,
"lineInterpolation": "linear",
"lineWidth": 1,
"pointSize": 5,
"scaleDistribution": {
"type": "linear"
},
"showPoints": "auto",
"spanNulls": false,
"stacking": {
"group": "A",
"mode": "none"
},
"thresholdsStyle": {
"mode": "off"
}
},
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green"
}
]
},
"unit": "none"
},
"overrides": []
},
"gridPos": {
"h": 8,
"w": 24,
"x": 0,
"y": 15
},
"id": 7,
"options": {
"legend": {
"calcs": [],
"displayMode": "table",
"placement": "right",
"showLegend": true
},
"tooltip": {
"maxHeight": 600,
"mode": "single",
"sort": "none"
}
},
"pluginVersion": "11.0.8",
"targets": [
{
"datasource": {
"type": "prometheus",
"uid": "prometheus_uid"
},
"expr": "kafka_topic_partition_current_offset",
"legendFormat": "{{topic}}:{{partition}}",
"refId": "A"
}
],
"title": "Partition Offsets (Current)",
"type": "timeseries"
}
],
"refresh": "10s",
"schemaVersion": 39,
"tags": ["kafka", "messaging", "de"],
"templating": {
"list": []
},
"time": {
"from": "now-1h",
"to": "now"
},
"timepicker": {},
"timezone": "Europe/Moscow",
"title": "Kafka Overview",
"uid": "kafka-overview",
"version": 1,
"weekStart": ""
}
+11 -1
View File
@@ -1,6 +1,6 @@
global:
scrape_interval: 15s
scrape_configs:
- job_name: "clickhouse"
metrics_path: "/metrics"
@@ -8,4 +8,14 @@ scrape_configs:
- targets: ["clickhouse:9126"]
labels:
instance: Clickhouse-1
honor_labels: true
# Kafka metrics via kafka-exporter
# Проверено через Context7: формат scrape_configs подтверждён (/prometheus/docs)
- job_name: "kafka"
metrics_path: "/metrics"
static_configs:
- targets: ["kafka-exporter:9308"]
labels:
instance: Kafka-1
honor_labels: true