Un test de latence MQTT mesure le temps que met un message pour aller d'un publisher, via le broker, jusqu'à un subscriber. La méthode fiable consiste à mesurer le temps aller-retour (RTT) sur une seule horloge : le même processus publie un message, le reçoit en retour du broker et soustrait deux lectures d'un minuteur monotone. Tout ce qui compare des horodatages de deux machines mesure autant l'écart entre leurs horloges que le réseau.
Ce guide vous donne un script de latence prêt à copier, explique les pièges d'horloge qui faussent la plupart des mesures, montre comment présenter des percentiles et comment comparer équitablement des brokers ou des régions.
Ce que « latence MQTT » veut vraiment dire
Plusieurs valeurs différentes portent le nom de latence. Décidez laquelle vous intéresse avant d'écrire la moindre ligne de code :
| Mesure | De → vers | Horloge nécessaire |
|---|---|---|
| RTT en boucle (loopback) | Le client publie → le même client reçoit son propre message | Une horloge (simple, fiable) |
| RTT avec écho | Client A → broker → client écho B → broker → client A | Une horloge sur A |
| Latence dans un sens | Publisher sur l'hôte A → subscriber sur l'hôte B | Deux horloges synchronisées |
| Temps de connexion | TCP + handshake TLS + CONNECT → CONNACK | Une horloge |
| Référence réseau | Connexion TCP au port du broker | Une horloge |
Pour la planification de capacité et la comparaison de brokers, le RTT en boucle suffit généralement. Il inclut le travail de routage du broker dans les deux sens et deux traversées du réseau, et ne nécessite qu'un seul client.
Les pièges d'horloge
La plupart des mauvaises mesures de latence viennent de l'horloge, pas du broker :
- L'heure murale fait des sauts.
time.time()en Python ouDate.now()en JavaScript suivent l'horloge système, que NTP peut ajuster à tout moment. Utilisez une horloge monotone pour les intervalles :time.perf_counter()en Python,performance.now()ouprocess.hrtime.bigint()en Node.js. - Deux machines ne sont jamais parfaitement d'accord. Même avec NTP, les hôtes divergent couramment d'une milliseconde ou plus, et bien davantage sur des appareils sans bonne source de temps. Une mesure dans un sens hérite directement de cette erreur — vous pouvez même obtenir des latences négatives.
- RTT / 2 n'est qu'une estimation. Les chemins montant et descendant peuvent différer (réseau mobile, ADSL, liaisons montantes saturées). Présentez le RTT comme un RTT et ne divisez par deux qu'en le précisant.
- Résolution du minuteur sur les petits appareils.
millis()sur un microcontrôleur a une résolution de 1 ms ; faites la moyenne de nombreuses mesures plutôt que de vous fier à une seule.
Un script de RTT en boucle
Ce script (paho-mqtt 2.x) s'abonne à un topic unique, publie des numéros de séquence un par un et attend le retour de chaque message avant d'envoyer le suivant. Cette conception en boucle fermée mesure la latence d'un chemin au repos, sans effet de file d'attente.
import os, statistics, sys, threading, time, uuid
import paho.mqtt.client as mqtt
HOST = os.getenv("MQTT_HOST", "broker.connectmq.com")
PORT = int(os.getenv("MQTT_PORT", "1883"))
N = int(sys.argv[1]) if len(sys.argv) > 1 else 500
QOS = int(os.getenv("MQTT_QOS", "1"))
WARMUP = 20
TOPIC = f"testmqtt/latency/{uuid.uuid4().hex[:8]}"
ready, got = threading.Event(), threading.Event()
state = {"expected": -1, "t0": 0.0}
samples, lost = [], 0
def on_connect(client, userdata, flags, reason_code, properties):
client.subscribe(TOPIC, qos=QOS)
def on_subscribe(client, userdata, mid, reason_code_list, properties):
ready.set()
def on_message(client, userdata, msg):
if int(msg.payload) == state["expected"]:
rtt = (time.perf_counter() - state["t0"]) * 1000
if state["expected"] >= WARMUP:
samples.append(rtt)
got.set()
client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2)
if os.getenv("MQTT_USER"):
client.username_pw_set(os.getenv("MQTT_USER"), os.getenv("MQTT_PASS"))
client.on_connect, client.on_subscribe, client.on_message = on_connect, on_subscribe, on_message
client.connect(HOST, PORT, keepalive=30)
client.loop_start()
ready.wait(10)
for i in range(N + WARMUP):
got.clear()
state["expected"], state["t0"] = i, time.perf_counter()
client.publish(TOPIC, str(i), qos=QOS)
if not got.wait(5):
lost += 1
time.sleep(0.02) # laisse le chemin au repos entre deux sondes
client.loop_stop()
q = statistics.quantiles(samples, n=100)
print(f"{HOST}:{PORT} QoS {QOS} samples {len(samples)} lost {lost}")
print(f"min {min(samples):.1f} p50 {q[49]:.1f} p95 {q[94]:.1f} "
f"p99 {q[98]:.1f} max {max(samples):.1f} ms")pip install "paho-mqtt>=2"
python mqtt_rtt.py 1000
MQTT_PORT=8883 python mqtt_rtt.py 1000 # nécessite client.tls_set() pour TLS
MQTT_QOS=0 python mqtt_rtt.py 1000Les WARMUP premiers messages sont écartés parce qu'ils paient les caches froids et la montée en régime de la connexion. Pour tester avec TLS, ajoutez client.tls_set() avant connect() et utilisez le port 8883 — le handshake n'a lieu qu'une fois, il affecte donc le temps de connexion, pas le RTT par message.
Avant de lancer le script, une vérification rapide dans le client MQTT en ligne vaut la peine : abonnez-vous à testmqtt/latency/#, publiez un message et vérifiez qu'il revient. Si cela fonctionne, le script fonctionnera aussi.
Séparer le réseau du broker
Un RTT de 40 ms ne veut rien dire tant que vous ne savez pas quelle part revient au réseau. Mesurez comme référence le simple temps de connexion TCP au port du broker :
python3 -c "import socket,time
for _ in range(5):
t=time.perf_counter(); socket.create_connection(('broker.connectmq.com',1883)).close()
print(f'{(time.perf_counter()-t)*1000:.1f} ms')"Une connexion TCP correspond à un aller-retour réseau. Si votre RTT MQTT en boucle en QoS 0 est proche de cette référence, le broker n'ajoute presque rien et le reste de la latence vient de la distance. S'il est bien plus élevé, examinez le broker, le client ou le chemin — le dépannage de la latence élevée passe en revue les causes habituelles.
La lumière parcourt environ 200 km par milliseconde dans la fibre : un broker situé à 2 000 km coûte donc au moins ~20 ms de RTT avant même qu'un logiciel ne s'exécute. Aucun réglage du broker ne bat la physique ; choisissez une région proche de vos appareils.
Présenter des percentiles, pas des moyennes
Les distributions de latence ont des queues longues. Une moyenne de 12 ms peut cacher un p99 de 300 ms, et c'est le p99 qui provoque des timeouts sur les appareils et fait saccader les dashboards. Indiquez toujours au minimum :
- min — le plancher fixé par le réseau ; il doit rester stable d'un essai à l'autre.
- p50 — l'expérience typique.
- p95 / p99 — la queue ; comparez ces valeurs entre configurations.
- max et lost — les valeurs aberrantes isolées et les timeouts sont des signaux, pas du bruit.
Collectez assez de mesures pour le percentile présenté. Avec 100 mesures, le p99 correspond en pratique à un seul message ; visez au moins 1 000 mesures avant de citer un p99.
Ce qui fait varier la latence
| Facteur | Effet sur le RTT |
|---|---|
| QoS 0 → QoS 1 | La livraison n'attend pas le PUBACK, mais la persistance côté broker et les limites d'inflight peuvent ajouter du temps sous charge |
| QoS 2 | Échange de quatre paquets par saut ; nettement plus lent, voir le benchmark QoS 0 vs 1 vs 2 |
| TLS | Coût du handshake à la connexion ; faible coût de chiffrement par message |
| WebSockets | Encapsulation supplémentaire et souvent un saut par un proxy |
| Taille du payload | Les gros payloads prennent plus de temps sur les liaisons lentes |
| Charge du broker | Les files s'allongent, la latence de queue augmente en premier |
| Callbacks du client | Un on_message lent retarde tous les messages suivants |
Pour voir comment la latence se comporte sous charge, lancez ce script pendant qu'un générateur de charge envoie du trafic — la méthode est décrite dans le test de charge d'un broker MQTT. Le RTT au repos est votre meilleur cas ; le RTT sous charge est celui sur lequel vous planifiez.
Comparer équitablement brokers et régions
Une comparaison n'est équitable que si tout, sauf le broker, est identique :
- Mesurez depuis la même machine et le même réseau, idéalement une VM dans la région où se trouvent vos appareils ou votre backend.
- Utilisez le même QoS, le même payload, le même port et le même réglage TLS pour chaque cible.
- Alternez les cibles (A, B, A, B) plutôt que tout A puis tout B, afin qu'un incident réseau passager touche les deux.
- Notez min, p50, p99 et lost pour chacune, avec la référence TCP, dans un seul tableau.
- Recommencez à un autre moment de la journée avant de conclure.
Pour une décision multirégion, lancez une petite VM dans chaque région où vous avez des utilisateurs et exécutez le même script contre chaque endpoint de broker. La matrice p50/p99 par (région du client, région du broker) est la donnée la plus honnête que vous obtiendrez.
Checklist du test de latence
- Utilisez une horloge monotone et un seul processus pour le RTT.
- Écartez les messages de préchauffage ; mesurez le temps de connexion à part.
- Collectez plus de 1 000 mesures et indiquez min, p50, p95, p99, max et lost.
- Notez une référence TCP à côté de chaque résultat MQTT.
- Testez au repos et sous charge, depuis le réseau qu'utilisent réellement vos appareils.
- Conservez le script dans votre dépôt et relancez-le après chaque changement de broker ou de réseau.
Vérifier l'aller-retour dans le navigateur
Un test de latence MQTT fiable est surtout une question de rigueur : une seule horloge, assez de mesures, des percentiles plutôt que des moyennes et une référence qui indique quelle part du chiffre revient au réseau. Avec cela, un script de 15 minutes répond à des questions que les benchmarks des éditeurs n'aborderont jamais.
Questions fréquentes
Comment mesurer la latence MQTT sans horloges synchronisées ?
Mesurez le temps aller-retour sur une seule horloge : un client publie sur un topic auquel il est lui-même abonné (ou vers un client écho qui republie), et le même processus horodate l'envoi et la réception avec une horloge monotone.
Le temps aller-retour MQTT vaut-il deux fois la latence dans un sens ?
Seulement à peu près. RTT / 2 suppose que les deux sens sont symétriques, ce qui est souvent faux sur les réseaux mobiles ou asymétriques. Pour de vraies mesures dans un sens, il faut des horloges synchronisées bien en dessous de la latence mesurée.
Pourquoi mon premier message MQTT est-il beaucoup plus lent que les suivants ?
Les premiers messages paient la résolution DNS, la montée en régime de TCP et TLS, la création de l'abonnement et les caches froids. Écartez un lot de préchauffage avant d'enregistrer des mesures et mesurez le temps de connexion à part.


