Prometheus et Grafana forment la stack habituelle pour superviser un broker MQTT. Prometheus collecte les métriques en HTTP et évalue les règles d'alerte. Grafana dessine les dashboards. Les brokers exposent leurs métriques de deux façons : certains ont un endpoint Prometheus natif (EMQX, VerneMQ, HiveMQ via une extension), d'autres, comme Mosquitto, ne publient que des topics $SYS et ont besoin d'un exporter pour les traduire.
Ce guide branche les trois sources de données dont vous aurez probablement besoin : un exporter pour Mosquitto, l'endpoint natif d'EMQX et une sonde côté client qui fonctionne avec n'importe quel broker, y compris les brokers managés. Il ajoute ensuite des dashboards et des alertes.
D'où viennent les métriques
| Broker | Comment Prometheus obtient les métriques |
|---|---|
| Mosquitto | mosquitto-exporter s'abonne à $SYS/# et sert /metrics (port 9234 par défaut) |
| EMQX 5 | Endpoint intégré /api/v5/prometheus/stats sur le port du dashboard/de l'API (18083), ou envoi vers un Pushgateway |
| HiveMQ | HiveMQ Prometheus Monitoring Extension, sert /metrics (port 9399 par défaut) |
| VerneMQ | /metrics intégré sur son listener HTTP (port 8888 par défaut) |
| Broker managé | Métriques du fournisseur si elles existent, plus votre propre sonde côté client |
Les métriques côté broker indiquent ce que fait le broker : connexions, débit, files d'attente et messages abandonnés. Une sonde côté client indique ce que vivent vos appareils : peuvent-ils se connecter, et combien de temps met un message ? Il vous faut les deux. Si vous ne pouvez en avoir qu'une, choisissez la sonde, car c'est elle qui détecte les pannes DNS, TLS, load balancer et d'authentification.
Si $SYS est nouveau pour vous, lisez d'abord surveiller un broker avec les topics $SYS. L'exporter ci-dessous n'est qu'une fine couche par-dessus.
Une stack locale avec Docker Compose
Cette stack lance ensemble Mosquitto, l'exporter, Prometheus et Grafana. C'est un bon laboratoire pour construire des dashboards avant de les pointer vers la production.
services:
mosquitto:
image: eclipse-mosquitto:2
ports: ["1883:1883"]
volumes:
- ./mosquitto.conf:/mosquitto/config/mosquitto.conf:ro
mosquitto-exporter:
image: sapcc/mosquitto-exporter
command: ["--endpoint", "tcp://mosquitto:1883"]
ports: ["9234:9234"]
depends_on: [mosquitto]
prometheus:
image: prom/prometheus
ports: ["9090:9090"]
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml:ro
- ./alerts.yml:/etc/prometheus/alerts.yml:ro
grafana:
image: grafana/grafana
ports: ["3000:3000"]
volumes:
- ./grafana-datasource.yml:/etc/grafana/provisioning/datasources/prometheus.yml:rolistener 1883
allow_anonymous true
sys_interval 10apiVersion: 1
datasources:
- name: Prometheus
type: prometheus
url: http://prometheus:9090
isDefault: trueallow_anonymous true n'est acceptable que sur un poste de développement. Sur un vrai broker, créez un compte de supervision dédié qui peut lire $SYS/# et rien d'autre, puis passez-le à l'exporter avec --user et --pass. Le générateur de mosquitto.conf peut produire les blocs listener et authentification pour vous. Pour un laboratoire plus complet avec davantage de services, voir la stack MQTT Docker Compose.
L'exporter transforme chaque topic $SYS numérique en métrique dont le nom suit le chemin du topic ; par exemple, $SYS/broker/clients/connected devient broker_clients_connected. Ouvrez http://localhost:9234/metrics pour voir les noms exacts produits par votre version avant d'écrire vos requêtes.
Un exporter de sonde pour n'importe quel broker
Cet exporter Python (paho-mqtt 2.x et prometheus_client) se connecte en TLS toutes les 15 secondes, s'abonne à un topic unique, publie un message et attend qu'il revienne. Il exporte le résultat et la durée de chaque étape :
import os, ssl, threading, time, uuid
import paho.mqtt.client as mqtt
from prometheus_client import Gauge, Histogram, start_http_server
HOST, PORT, INTERVAL = "broker.connectmq.com", 8883, 15
success = Gauge("mqtt_probe_success", "1 if the last connect/publish/receive cycle worked")
connect_s = Gauge("mqtt_probe_connect_seconds", "TCP + TLS + CONNACK time of the last probe")
roundtrip = Histogram("mqtt_probe_roundtrip_seconds", "Subscribe, publish and receive time",
buckets=(0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1, 2.5, 5))
def probe() -> bool:
topic = f"testmqtt/probe/{uuid.uuid4().hex[:8]}"
connected, received = threading.Event(), threading.Event()
c = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2,
client_id=f"testmqtt-probe-{uuid.uuid4().hex[:6]}")
c.username_pw_set(os.getenv("MQTT_USER"), os.getenv("MQTT_PASS"))
c.tls_set(cert_reqs=ssl.CERT_REQUIRED)
c.on_connect = lambda cl, ud, fl, rc, pr: connected.set() if not rc.is_failure else None
c.on_subscribe = lambda cl, ud, mid, rcs, pr: cl.publish(topic, "ping", qos=1)
c.on_message = lambda cl, ud, msg: received.set()
t0 = time.perf_counter()
try:
c.connect(HOST, PORT, keepalive=10)
c.loop_start()
if not connected.wait(5):
return False
connect_s.set(time.perf_counter() - t0)
t1 = time.perf_counter()
c.subscribe(topic, qos=1)
if not received.wait(5):
return False
roundtrip.observe(time.perf_counter() - t1)
return True
except OSError:
return False
finally:
c.disconnect()
c.loop_stop()
if __name__ == "__main__":
start_http_server(9105) # métriques sur http://localhost:9105/metrics
while True:
success.set(1 if probe() else 0)
time.sleep(INTERVAL)Installez les dépendances avec pip install paho-mqtt prometheus-client. Ouvrir une nouvelle connexion à chaque cycle est voulu : cela teste DNS, TLS et authentification à chaque fois, comme un appareil qui redémarre. Utilisez un client ID unique à chaque exécution. Le générateur de client ID explique pourquoi des doublons se déconnectent mutuellement.
Configuration du scrape
global:
scrape_interval: 15s
rule_files: ["/etc/prometheus/alerts.yml"]
scrape_configs:
- job_name: mosquitto
static_configs:
- targets: ["mosquitto-exporter:9234"]
- job_name: mqtt-probe
static_configs:
- targets: ["host.docker.internal:9105"] # là où tourne la sonde
- job_name: emqx
metrics_path: /api/v5/prometheus/stats
static_configs:
- targets: ["emqx:18083"]Supprimez les jobs que vous n'utilisez pas. Sur les versions récentes d'EMQX, l'endpoint de statistiques peut être configuré pour exiger une authentification. Dans ce cas, ajoutez basic_auth avec une clé d'API et son secret. Pour essayer EMQX en local, voir EMQX sous Docker. host.docker.internal fonctionne avec Docker Desktop. Sous Linux, lancez plutôt la sonde comme un autre service Compose.
Des dashboards qui répondent à de vraies questions
Un dashboard MQTT utile compte peu de panneaux, et chacun répond à une question qu'on se posera pendant un incident :
| Panneau | PromQL (exemple) |
|---|---|
| Des clients sont-ils connectés ? | broker_clients_connected ou sum(emqx_connections_count) |
| Messages entrants / sortants par seconde | rate(broker_messages_received[5m]), rate(emqx_messages_sent[5m]) |
| Perd-on des messages ? | rate(broker_publish_messages_dropped[5m]) ou rate(emqx_messages_dropped[5m]) |
| Un client peut-il se connecter maintenant ? | mqtt_probe_success |
| La livraison est-elle lente ? | histogram_quantile(0.99, sum by (le) (rate(mqtt_probe_roundtrip_seconds_bucket[10m]))) |
| Temps de connexion | mqtt_probe_connect_seconds |
Appliquez rate() aux compteurs et ne tracez jamais la valeur brute d'un compteur. Placez les panneaux de la sonde en haut, car ils montrent ce que voient les utilisateurs. Des dashboards communautaires pour l'exporter Mosquitto et pour EMQX sont publiés sur grafana.com. Ce sont de bons points de départ, mais vérifiez que leurs noms de métriques correspondent à votre version de l'exporter.
Règles d'alerte
groups:
- name: mqtt
rules:
- alert: MqttProbeFailing
expr: max_over_time(mqtt_probe_success[3m]) == 0
labels: { severity: page }
annotations:
summary: "No successful MQTT round trip for 3 minutes"
- alert: MqttProbeSlow
expr: histogram_quantile(0.99, sum by (le) (rate(mqtt_probe_roundtrip_seconds_bucket[10m]))) > 0.5
for: 10m
labels: { severity: ticket }
- alert: MqttClientsDropped
expr: broker_clients_connected < 0.7 * (broker_clients_connected offset 10m)
for: 2m
labels: { severity: page }
- alert: MqttExporterDown
expr: up{job="mosquitto"} == 0
for: 2m
labels: { severity: ticket }MqttClientsDropped repère le schéma d'incident classique : une grande partie des appareils se déconnecte d'un coup, après l'expiration d'un certificat, un changement réseau ou un redémarrage du broker. Routez les alertes page via Alertmanager vers votre canal d'astreinte et les alertes ticket vers un endroit plus calme. Pour les vérifications externes et le calcul des SLO, voir la surveillance de disponibilité MQTT.
Testez la supervision elle-même
Avant de faire confiance aux alertes, déclenchez chacune volontairement :
- Échec de la sonde : remplacez
MQTT_PASSpar une valeur erronée et redémarrez la sonde.mqtt_probe_successdoit tomber à 0 etMqttProbeFailingse déclencher en trois minutes environ. - Chute de clients : connectez un lot de clients de test (un simulateur d'appareils ou plusieurs onglets du client en ligne), attendez dix minutes puis fermez-les. Le panneau des clients connectés doit baisser en conséquence.
- Exporter arrêté :
docker compose stop mosquitto-exporterdoit déclencherMqttExporterDown. - Latence : ajoutez du délai avec un outil de mise en forme du trafic, ou comparez les chiffres de la sonde avec un test de latence dédié.
Une alerte qui ne s'est jamais déclenchée en test risque de ne pas se déclencher non plus lors d'une vraie panne.
Prometheus et Grafana apportent l'historique, les dashboards et les alertes que $SYS seul ne fournit pas. Combinez les métriques du broker avec une sonde côté client, gardez un dashboard réduit et testez chaque alerte une fois avant de vous y fier.
Questions fréquentes
Mosquitto a-t-il un endpoint Prometheus intégré ?
Non. Mosquitto publie ses statistiques sur des topics $SYS. Un exporter comme mosquitto-exporter s'abonne à $SYS/# et expose les valeurs sur un endpoint HTTP /metrics que Prometheus peut collecter.
Peut-on superviser un broker MQTT managé avec Prometheus ?
Oui, côté client. Même si vous ne pouvez pas installer d'exporter à côté du broker, une petite sonde qui se connecte, publie et reçoit un message peut exporter des métriques de succès et de latence. C'est souvent le signal le plus utile.
Sur quoi alerter en premier ?
Commencez par trois alertes : la sonde en échec pendant quelques minutes, une chute brutale du nombre de clients connectés et des messages abandonnés au-dessus de zéro. Ajoutez des alertes de latence quand vous connaissez votre p99 habituel.


