La surveillance externe de disponibilité répond à une seule question : un appareil situé hors de votre réseau pourrait-il, à l'instant, se connecter au broker et échanger un message ? Les métriques internes ne peuvent pas y répondre. Elles ne voient ni les pannes DNS, ni les certificats expirés, ni les load balancers défaillants, ni un changement de pare-feu. Seule une sonde qui se comporte comme un client et tourne depuis l'extérieur les voit.
Ce guide construit cette sonde, la planifie, achemine les alertes vers Slack ou PagerDuty et présente les calculs de SLO nécessaires pour choisir l'intervalle de vérification et le seuil d'alerte.
Ce que « disponible » veut dire pour un broker MQTT
« Le port est ouvert » est une définition trop faible. Un broker n'est utile que si toutes ces couches fonctionnent :
| Couche | Vérification | Panne typique détectée |
|---|---|---|
| DNS | Le nom d'hôte se résout | Domaine expiré, mauvais enregistrement après une migration |
| TCP | Le port 8883 accepte la connexion | Pare-feu, security group, processus du broker arrêté |
| TLS | Le handshake réussit, le certificat est valide N jours de plus | Certificat expiré ou qui ne correspond pas |
| MQTT CONNECT | CONNACK avec un code de succès | Backend d'authentification en panne, identifiants changés, limite de connexions atteinte |
| Aller-retour | Le message publié est reçu dans le délai | Routage cassé, cluster scindé, surcharge |
Vérifiez chaque couche séparément et indiquez laquelle a échoué. « TLS en échec, certificat expiré » se corrige en cinq minutes. « Sonde en échec » lance une enquête d'une demi-heure. Pour des vérifications manuelles ponctuelles, voir vérifier l'état d'un broker MQTT et tester si un port MQTT est ouvert.
Une sonde minimale avec les clients Mosquitto
Si vous avez déjà mosquitto_pub et mosquitto_sub, une sonde shell tient en une douzaine de lignes :
#!/usr/bin/env bash
set -u
HOST=broker.connectmq.com; PORT=8883
TOPIC="testmqtt/uptime/$(hostname)-$$"
MSG="ping-$(date +%s)"
OUT=$(mktemp)
mosquitto_sub -h "$HOST" -p "$PORT" --capath /etc/ssl/certs \
-u "$MQTT_USER" -P "$MQTT_PASS" -t "$TOPIC" -q 1 -C 1 -W 10 > "$OUT" &
SUB=$!
sleep 1
mosquitto_pub -h "$HOST" -p "$PORT" --capath /etc/ssl/certs \
-u "$MQTT_USER" -P "$MQTT_PASS" -t "$TOPIC" -q 1 -m "$MSG"
wait $SUB
if grep -qx "$MSG" "$OUT"; then echo "OK"; rm -f "$OUT"; exit 0
else echo "FAIL: no round trip within 10 s"; rm -f "$OUT"; exit 1; fi-C 1 fait quitter l'abonné après un message, et -W 10 le fait abandonner au bout de dix secondes. Le code de sortie est tout ce dont un planificateur ou un service de heartbeat a besoin.
Une sonde par couches en Python
Cette version (paho-mqtt 2.x) vérifie chaque couche, la chronomètre, indique le nombre de jours avant l'expiration du certificat et affiche une ligne JSON facile à envoyer dans vos logs :
import json, os, socket, ssl, sys, threading, time, uuid
import paho.mqtt.client as mqtt
HOST, PORT, TIMEOUT = "broker.connectmq.com", 8883, 10
result = {"host": HOST, "ts": int(time.time())}
def fail(stage, detail):
result.update(ok=False, stage=stage, detail=str(detail))
print(json.dumps(result)); sys.exit(1)
t = time.perf_counter()
try:
socket.getaddrinfo(HOST, PORT)
except OSError as e:
fail("dns", e)
try:
ctx = ssl.create_default_context()
with socket.create_connection((HOST, PORT), timeout=TIMEOUT) as raw:
with ctx.wrap_socket(raw, server_hostname=HOST) as tls:
not_after = ssl.cert_time_to_seconds(tls.getpeercert()["notAfter"])
except ssl.SSLError as e:
fail("tls", e)
except OSError as e:
fail("tcp", e)
result["cert_days_left"] = int((not_after - time.time()) // 86400)
result["tls_ms"] = round((time.perf_counter() - t) * 1000)
topic = f"testmqtt/uptime/{uuid.uuid4().hex[:8]}"
connack, got = {}, threading.Event()
c = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2, client_id=f"testmqtt-uptime-{uuid.uuid4().hex[:6]}")
c.username_pw_set(os.getenv("MQTT_USER"), os.getenv("MQTT_PASS"))
c.tls_set_context(ctx)
c.on_connect = lambda cl, ud, fl, rc, pr: (connack.update(rc=rc),
None if rc.is_failure else cl.subscribe(topic, qos=1))
c.on_subscribe = lambda cl, ud, mid, rcs, pr: cl.publish(topic, "ping", qos=1)
c.on_message = lambda cl, ud, msg: got.set()
t = time.perf_counter()
try:
c.connect(HOST, PORT, keepalive=15)
except OSError as e:
fail("connect", e)
c.loop_start()
ok = got.wait(TIMEOUT)
c.disconnect(); c.loop_stop()
if "rc" not in connack:
fail("connect", "no CONNACK")
if connack["rc"].is_failure:
fail("connect", connack["rc"])
if not ok:
fail("roundtrip", f"no message within {TIMEOUT} s")
result.update(ok=True, roundtrip_ms=round((time.perf_counter() - t) * 1000))
print(json.dumps(result))
sys.exit(2 if result["cert_days_left"] < 14 else 0)Le code de sortie 0 signifie que tout va bien, 1 que le service est indisponible (le champ stage indique où), et 2 que le service répond mais que le certificat expire dans moins de deux semaines. Ce dernier cas est un avertissement, pas une alerte d'astreinte. Quand l'étape connect échoue, le reason code (par exemple Not authorized) indique s'il s'agit d'un problème d'identifiants ou d'ACL. Consultez-le avec l'outil de reason codes ou dans les erreurs de connexion MQTT.
Planifier la sonde
- cron ou un timer systemd sur une petite VM hors du réseau du broker :
* * * * * /opt/probe/mqtt_uptime_probe.py >> /var/log/mqtt-probe.log 2>&1. C'est simple et ça tourne chaque minute. - Plusieurs emplacements. Lancez la même sonde depuis deux ou trois régions ou fournisseurs. Alertez quand la majorité échoue. Si un seul emplacement échoue, c'est en général le réseau de cet emplacement.
- Le
schedulede GitHub Actions convient aux vérifications peu critiques, mais l'intervalle minimal est de cinq minutes et les exécutions peuvent démarrer en retard. Ce n'est pas adapté à l'astreinte. - Uptime Kuma (auto-hébergé) propose un type de moniteur MQTT et convient bien si vous préférez une interface graphique.
Ce qui exécute la sonde peut aussi tomber en panne. Utilisez un heartbeat (dead man's switch) : après chaque exécution réussie, la sonde envoie un ping à une URL d'un service de heartbeat comme Healthchecks.io ou un push monitor d'Uptime Kuma. Si les pings cessent, c'est que le broker ou la machine de la sonde est tombé, et vous êtes alerté dans les deux cas :
* * * * * /opt/probe/mqtt-probe.sh && curl -fsS -m 10 --retry 3 "$HEARTBEAT_URL" > /dev/nullCanaux d'alerte
Envoyez les alertes là où quelqu'un les verra vraiment, et seulement quand les preuves sont suffisantes. Une règle courante : trois échecs consécutifs depuis au moins deux emplacements, avec un message de rétablissement quand tout revient à la normale.
curl -fsS -X POST -H 'Content-Type: application/json' \
-d '{"text":":red_circle: MQTT probe failed at stage tls (broker.connectmq.com:8883)"}' \
"$SLACK_WEBHOOK_URL"curl -fsS -X POST https://events.pagerduty.com/v2/enqueue \
-H 'Content-Type: application/json' \
-d '{"routing_key":"'"$PD_ROUTING_KEY"'","event_action":"trigger",
"dedup_key":"mqtt-probe-broker",
"payload":{"summary":"MQTT round trip failing","source":"mqtt-probe","severity":"critical"}}'Envoyez la même requête avec "event_action":"resolve" et la même dedup_key pour clore l'incident automatiquement. Gardez les avertissements d'expiration de certificat dans Slack ou par e-mail. Ils demandent une action dans la semaine, pas à 3 heures du matin. Si vous utilisez déjà Prometheus, exportez la sonde sous forme de métriques et alertez depuis Prometheus. Voir superviser MQTT avec Prometheus et Grafana.
Calculs de SLO
Un objectif de disponibilité n'a de sens qu'avec son budget d'indisponibilité :
| Disponibilité | Indisponibilité sur 30 jours | Indisponibilité par an |
|---|---|---|
| 99 % | 7 h 12 min | 3,65 jours |
| 99,5 % | 3 h 36 min | 1,83 jour |
| 99,9 % | 43,2 min | 8 h 46 min |
| 99,95 % | 21,6 min | 4 h 23 min |
| 99,99 % | 4,3 min | 52,6 min |
Mesurez-la comme sondes réussies ÷ sondes totales. Une sonde par minute donne 43 200 échantillons en 30 jours, donc 99,9 % autorise 43 sondes en échec. Trois conséquences en découlent :
- L'intervalle limite la précision. Avec une sonde par minute, une panne de 20 secondes peut passer inaperçue ou compter pour une minute entière. Pour mesurer 99,99 %, sondez toutes les 10 à 15 secondes.
- Le temps de détection consomme le budget. Trois échecs à une minute d'intervalle, c'est environ trois minutes avant que quelqu'un soit alerté. C'est acceptable pour 99,9 % (43 minutes) et c'est presque tout le budget à 99,99 %.
- Votre SLO n'est pas le SLA du fournisseur. Le SLA couvre le broker. Votre sonde mesure tout le chemin, y compris votre DNS, vos certificats et votre réseau. Lisez SLA et disponibilité des brokers MQTT avant de comparer les deux.
Suivez votre budget d'erreur : si 30 de vos 43 minutes sont consommées à la mi-mois, gelez les changements risqués sur le broker jusqu'à ce qu'il se reconstitue.
Testez la chaîne d'alerte
Une sonde qui n'a jamais échoué n'a pas été testée. Avant de vous y fier :
- Mettez un mauvais mot de passe et vérifiez que l'étape
connectéchoue et que l'alerte arrive dans Slack ou PagerDuty. - Pointez
HOSTvers un nom qui ne se résout pas et vérifiezstage: dns. - Arrêtez la tâche cron et vérifiez que le service de heartbeat vous alerte.
- Vérifiez à la main que la vision de la sonde correspond à la réalité : connectez-vous avec le client MQTT en ligne et publiez sur le topic de la sonde pendant son exécution.
La surveillance externe de disponibilité se résume à un petit script, un planificateur et un heartbeat. Vérifiez chaque couche séparément, n'alertez que sur des échecs répétés depuis plusieurs emplacements, déduisez l'intervalle de la sonde de votre SLO, et cassez volontairement la configuration une fois pour prouver que les alertes arrivent.
Questions fréquentes
Vérifier que le port 1883 est ouvert suffit-il pour surveiller la disponibilité MQTT ?
Non. Un broker peut accepter des connexions TCP tout en refusant les logins, en échouant sur TLS ou en ne routant pas les messages. Une vraie vérification se connecte avec des identifiants, s'abonne, publie un message et confirme qu'il arrive dans un délai donné.
À quelle fréquence une sonde de disponibilité MQTT doit-elle tourner ?
Toutes les minutes est une bonne valeur par défaut. L'intervalle limite la précision de la mesure : avec une vérification par minute, les pannes de moins d'une minute peuvent passer inaperçues, et un budget mensuel de 99,99 % (environ quatre minutes) est épuisé avant qu'une alerte à trois échecs ne se déclenche.
Combien d'indisponibilité 99,9 % autorise-t-il ?
Environ 43 minutes par mois de 30 jours, soit à peu près 8 heures 46 minutes par an. 99,95 % autorise environ 22 minutes par mois, et 99,99 % environ 4,3 minutes.


