La plupart des brokers MQTT rendent compte de leur propre état via MQTT. Abonnez-vous à $SYS/# et le broker publie le nombre de clients connectés, le nombre de messages et d'octets reçus et envoyés, le nombre d'abonnements et de messages retenus qu'il conserve, et depuis combien de temps il tourne. C'est donc le moyen le plus rapide de surveiller un broker. Il ne faut ni exporter ni agent, seulement un client MQTT.
Ce guide présente ce que $SYS expose sur les brokers courants, comment s'y abonner correctement, comment transformer des compteurs bruts en débits utiles, et comment les enregistrer et les tracer avec un court script Python.
Que sont les topics $SYS ?
La spécification MQTT réserve les topics commençant par $ à l'usage interne du broker. Les clients ne doivent pas y publier, et les jokers ne les attrapent pas par accident : un abonnement à # ou à +/foo ne reçoit jamais de messages $SYS. Vous devez vous abonner volontairement à $SYS/# (ou à un filtre plus précis).
Le contenu n'est pas standardisé. Mosquitto, EMQX, VerneMQ et les autres publient chacun leur propre arborescence, et certains services managés la masquent entièrement ou la restreignent par ACL. Pour une référence complète de l'arborescence, consultez les topics $SYS MQTT. Cet article explique comment utiliser ces topics pour la surveillance.
Les topics à surveiller
Voici les noms utilisés par Mosquitto (2.x). Les autres brokers publient des valeurs similaires sous d'autres chemins.
| Topic | Type | Ce qu'il indique |
|---|---|---|
$SYS/broker/clients/connected | jauge | Clients connectés en ce moment |
$SYS/broker/clients/maximum | jauge | Pic de connexions simultanées depuis le démarrage |
$SYS/broker/clients/disconnected | jauge | Sessions persistantes dont le client est hors ligne |
$SYS/broker/messages/received | compteur | Messages reçus depuis le démarrage (tous types de paquets) |
$SYS/broker/messages/sent | compteur | Messages envoyés depuis le démarrage |
$SYS/broker/publish/messages/dropped | compteur | Messages PUBLISH abandonnés (limites de file, clients hors ligne) |
$SYS/broker/bytes/received / sent | compteur | Octets réseau entrants et sortants |
$SYS/broker/load/messages/received/1min | débit | Moyenne glissante sur 1, 5 et 15 minutes |
$SYS/broker/subscriptions/count | jauge | Abonnements actifs |
$SYS/broker/retained messages/count | jauge | Messages retenus stockés (attention à l'espace dans le topic) |
$SYS/broker/uptime | texte | Par exemple 86400 seconds |
$SYS/broker/version | texte | Version du broker |
On trouve ici deux sortes de valeurs. Les jauges (clients connectés, abonnements) se lisent telles quelles. Les compteurs (messages, octets) ne font qu'augmenter : il faut la différence entre deux échantillons pour obtenir un débit. Mosquitto publie aussi des moyennes glissantes toutes prêtes sous $SYS/broker/load/.... Elles sont pratiques pour un coup d'œil rapide, mais vous ne maîtrisez pas la fenêtre.
Sur EMQX, l'arborescence est organisée par nœud : $SYS/brokers/<node>/version, $SYS/brokers/<node>/uptime, plus les sous-arbres stats/... et metrics/... et des événements optionnels de connexion et de déconnexion des clients. L'intervalle de publication se règle avec sys_msg_interval. Pour des dashboards sur EMQX, son endpoint Prometheus intégré est en général une meilleure source. Voir la supervision avec Prometheus et Grafana.
S'abonner à $SYS
Le test le plus rapide se fait avec mosquitto_sub. Mettez le topic entre apostrophes simples, sinon le shell tentera d'interpréter $SYS comme une variable :
mosquitto_sub -h broker.connectmq.com -p 1883 \
-u "$MQTT_USER" -P "$MQTT_PASS" \
-v -t '$SYS/#'Pour ne suivre que quelques valeurs, abonnez-vous à plusieurs filtres précis :
mosquitto_sub -h broker.connectmq.com -p 1883 \
-u "$MQTT_USER" -P "$MQTT_PASS" -v \
-t '$SYS/broker/clients/connected' \
-t '$SYS/broker/load/messages/+/1min' \
-t '$SYS/broker/uptime'Vous pouvez faire la même chose dans le navigateur : ouvrez le client MQTT en ligne, connectez-vous et abonnez-vous à $SYS/#. Si rien n'arrive, vérifiez ces trois points dans l'ordre :
- Le broker a désactivé
$SYS. Dans Mosquitto,sys_interval 0le désactive. - Une ACL l'interdit. Beaucoup de configurations de production n'autorisent qu'un compte administrateur à lire
$SYS. Les clients MQTT 5 reçoivent un SUBACK avec le reason code0x87 Not authorized. Décodez-le avec l'outil de reason codes. - Vous n'avez attendu qu'un intervalle. Certaines valeurs n'apparaissent qu'au tick
sys_intervalsuivant.
Régler l'intervalle de mise à jour
Dans Mosquitto, l'intervalle tient en une seule option :
# Publish $SYS updates every 10 seconds (default). 0 disables $SYS.
sys_interval 10Un intervalle plus court donne des graphes plus fins, mais coûte un peu de CPU et de bande passante pour chaque abonné à $SYS/#. Pour des dashboards, 10 à 30 secondes suffisent largement. Le générateur de mosquitto.conf propose cette option si vous partez de zéro.
Transformer les compteurs en débits
Les compteurs ne sont utiles que sous forme de différences. Si messages/received valait 1 204 500 à 12:00:00 et 1 210 500 à 12:00:10, le broker a reçu (1210500 − 1204500) / 10 = 600 messages par seconde sur cette fenêtre. Deux règles évitent les calculs trompeurs :
- Utilisez l'heure de réception de l'échantillon, pas l'intervalle nominal. La gigue réseau et la charge du broker décalent les ticks.
- Gérez les remises à zéro. Quand le broker redémarre, les compteurs repartent de zéro. Si une nouvelle valeur est inférieure à la précédente, ignorez cette différence au lieu de tracer un énorme pic négatif. Une baisse de
uptimeconfirme le redémarrage.
Enregistrer et tracer $SYS avec Python
Ce script (paho-mqtt 2.x) s'abonne à quelques topics $SYS, calcule des débits à partir des compteurs, affiche une ligne par mise à jour et ajoute le tout à un fichier CSV que vous pourrez tracer ensuite :
import csv, os, time
import paho.mqtt.client as mqtt
HOST, PORT = "broker.connectmq.com", 1883
TOPICS = {
"$SYS/broker/clients/connected": "gauge",
"$SYS/broker/subscriptions/count": "gauge",
"$SYS/broker/messages/received": "counter",
"$SYS/broker/messages/sent": "counter",
"$SYS/broker/bytes/received": "counter",
"$SYS/broker/bytes/sent": "counter",
}
last = {} # topic -> (horodatage, valeur)
out = csv.writer(open("sys_metrics.csv", "a", newline=""))
def on_connect(client, userdata, flags, reason_code, properties):
if reason_code.is_failure:
print("échec de connexion :", reason_code)
return
client.subscribe([(t, 0) for t in TOPICS])
def on_message(client, userdata, msg):
now = time.time()
try:
value = float(msg.payload.decode().split()[0])
except ValueError:
return
name = msg.topic.removeprefix("$SYS/broker/")
if TOPICS[msg.topic] == "counter":
prev = last.get(msg.topic)
last[msg.topic] = (now, value)
if prev is None or value < prev[1]: # premier échantillon ou redémarrage du broker
return
value = (value - prev[1]) / (now - prev[0])
name += "/s"
out.writerow([int(now), name, round(value, 2)])
print(f"{time.strftime('%H:%M:%S')} {name:<24} {value:>12.1f}")
client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2, client_id="testmqtt-sys-monitor")
client.username_pw_set(os.getenv("MQTT_USER"), os.getenv("MQTT_PASS"))
client.on_connect = on_connect
client.on_message = on_message
client.connect(HOST, PORT, keepalive=30)
client.loop_forever()S'abonner dans on_connect est important : après une reconnexion, les abonnements sont rétablis automatiquement. Pour tracer le CSV, quelques lignes de pandas et matplotlib suffisent :
import pandas as pd
import matplotlib.pyplot as plt
df = pd.read_csv("sys_metrics.csv", names=["ts", "metric", "value"])
df["ts"] = pd.to_datetime(df["ts"], unit="s")
df.pivot_table(index="ts", columns="metric", values="value").plot(subplots=True, figsize=(10, 8))
plt.tight_layout()
plt.show()Pour un dashboard permanent avec historique et alertes, envoyez les mêmes valeurs dans Prometheus ou InfluxDB plutôt que dans un CSV.
Vérifiez que votre supervision réagit
Un moniteur qui n'a jamais vu de changement n'a pas été testé. Générez une charge connue et vérifiez que les chiffres bougent :
for i in $(seq 1 1000); do echo "{\"i\":$i}"; done | \
mosquitto_pub -h broker.connectmq.com -u "$MQTT_USER" -P "$MQTT_PASS" \
-t testmqtt/sys-monitor/load -lPendant le test, messages/received/s devrait augmenter à peu près du débit auquel vous publiez. Ouvrez dix connexions supplémentaires dans le client en ligne ou avec un simulateur d'appareils, et clients/connected devrait augmenter de dix. Si rien ne bouge, vous lisez probablement un autre nœud que celui sur lequel vous écrivez, ou un cluster remonte des valeurs par nœud.
Les limites de la supervision par $SYS
- Pas d'historique.
$SYSne montre que l'état actuel. C'est à vous de le stocker. - Pas d'alertes. Associez-le à Prometheus, Grafana ou à un script qui vous prévient. Pour des vérifications depuis l'extérieur, voir les health checks du broker.
- Propre à chaque broker. Les noms de topics et leur signification changent d'un broker à l'autre, et parfois d'une version à l'autre.
- Surveillé par le système qu'il surveille. Si le broker tombe,
$SYSse tait. Un moniteur silencieux doit déclencher une alerte, pas passer pour une journée calme.
Les topics $SYS sont l'observabilité la moins coûteuse qu'offre un broker MQTT. Abonnez-vous une fois à $SYS/# pour voir ce que publie votre broker, gardez un petit script qui transforme les compteurs en débits, et restreignez l'accès pour que seul votre compte de supervision puisse lire l'arborescence.
Questions fréquentes
Pourquoi un abonnement à # n'affiche-t-il pas les messages $SYS ?
La spécification MQTT indique que les abonnements avec joker commençant par # ou + ne doivent pas correspondre aux topics qui commencent par $. Abonnez-vous explicitement à $SYS/#, dans un abonnement séparé.
À quelle fréquence les topics $SYS sont-ils mis à jour ?
Cela dépend du broker. Mosquitto les publie toutes les sys_interval secondes (10 par défaut, 0 les désactive). EMQX utilise son propre réglage sys_msg_interval. Vérifiez la configuration de votre broker.
Les topics $SYS font-ils partie du standard MQTT ?
Non. La spécification réserve seulement les topics commençant par $ à l'usage du broker. Les noms et valeurs sous $SYS sont propres à chaque broker : un dashboard conçu pour Mosquitto ne fonctionnera pas tel quel sur EMQX ou un autre broker.


