Fondamentaux MQTT

Le modèle publish/subscribe de MQTT : découpler appareils et applications

Le modèle publish/subscribe de MQTT permet aux appareils et aux applications d'échanger des données sans se connaître. Découvrez les trois formes de découplage et testez-les en direct avec deux clients sur le serveur MQTT public gratuit broker.connectmq.com.

Schéma du modèle publish/subscribe MQTT avec des capteurs qui publient vers un broker qui diffuse les messages vers des tableaux de bord et des services
Essayez-le sur votre propre broker MQTTObtenez un broker MQTT privé et managé avec l’offre Free et partez d’exemples de code prêts à l’emploi.
Essayer gratuitement Exemples de code Aucune carte bancaire requise

Le modèle publish/subscribe de MQTT est la raison pour laquelle un capteur de température, un tableau de bord et un service de facturation peuvent partager des données sans jamais connaître l'adresse les uns des autres. Dans cet article, vous verrez en quoi le pub/sub diffère du modèle requête/réponse, ce que signifient concrètement les trois formes de découplage, et vous prouverez chacune d'elles vous-même avec deux fenêtres de terminal connectées à un broker gratuit.

Requête/réponse ou publication/abonnement

La plupart des développeurs découvrent le réseau à travers HTTP. Un client ouvre une connexion vers un serveur connu, pose une question et attend la réponse. Ce modèle est simple, mais il couple fortement les deux parties : le client doit connaître l'adresse du serveur, le serveur doit être disponible à cet instant précis, et le client reste bloqué (ou interroge en boucle) jusqu'à ce que quelque chose revienne.

Le modèle publication/abonnement rompt ce couplage en ajoutant un intermédiaire. Dans MQTT, cet intermédiaire est le broker. Les clients ne se parlent jamais directement ; ils ne parlent qu'au broker :

  • Un publisher envoie un message avec un topic comme plant1/line2/press/temperature.
  • Un subscriber indique au broker les topics qui l'intéressent, éventuellement avec des wildcards comme plant1/+/press/#.
  • Le broker compare chaque message entrant à tous les abonnements actifs et en transmet une copie à chaque correspondance.

Si le rôle du serveur intermédiaire est nouveau pour vous, notre guide sur ce que fait un broker MQTT détaille le routage, les sessions et l'état retained.

Aspect Requête/réponse (HTTP) Publish/subscribe MQTT
Qui connaît qui Le client connaît l'adresse du serveur Les clients ne connaissent que le broker
Sens Le client tire les données Le broker pousse à l'arrivée
Diffusion à de nombreux lecteurs Une requête par lecteur Une publication, de nombreuses livraisons
Connexion Souvent de courte durée Une seule connexion TCP de longue durée
Destinataires hors ligne La requête échoue Les sessions persistantes peuvent mettre en file

Les trois formes de découplage du modèle publish/subscribe MQTT

La littérature sur le pub/sub décrit généralement trois dimensions de découplage. Il vaut la peine de les distinguer, car chacune résout un problème IoT différent.

Découplage spatial

Les publishers et les subscribers ne connaissent ni l'adresse IP, ni le nom d'hôte des autres, ni même leur nombre. Un capteur publie sur site/tank3/level ; qu'aucune, une ou cinquante applications le reçoivent lui est invisible. C'est ce qui vous permet d'ajouter un nouveau service d'analyse l'an prochain sans toucher au firmware de milliers d'appareils déjà déployés sur le terrain.

Découplage temporel

Le publisher et le subscriber n'ont pas besoin d'être en ligne en même temps. MQTT fournit deux mécanismes pour cela :

  • Les retained messages. Le broker conserve le dernier retained message de chaque topic et le remet immédiatement à tout nouvel abonné. Un tableau de bord lancé à 9 h voit toujours l'état de la vanne publié à 6 h.
  • Les sessions persistantes. Un subscriber qui se connecte avec le drapeau clean start à false (et, en MQTT 5, un intervalle d'expiration de session) conserve ses abonnements pendant sa déconnexion, et le broker met en file les messages QoS 1 et QoS 2 à son intention.

Le découplage temporel n'est pas illimité. Les files sont bornées par l'expiration de session et les quotas du broker : considérez-le comme un tampon pour de courtes coupures, pas comme un stockage à long terme.

Découplage de synchronisation

Aucune des deux parties ne bloque l'autre. Un publisher remet son message à la bibliothèque cliente et poursuit son travail ; la bibliothèque gère les acquittements en arrière-plan. Les subscribers reçoivent les messages via des callbacks au lieu d'attendre dans une boucle. Sur un microcontrôleur, cela signifie que la boucle principale continue de lire les capteurs pendant que les entrées/sorties réseau se déroulent de façon asynchrone.

Les topics : le contrat entre publishers et subscribers

Comme il n'y a pas de lien direct entre les parties, la chaîne du topic est le seul contrat qu'elles partagent. Une bonne conception des topics compte donc davantage en MQTT que la conception des URL en REST :

  1. Allez du général au particulier : company/site/area/line/device/measurement.
  2. Gardez des niveaux stables et porteurs de sens pour que les wildcards restent utiles.
  3. Ne mettez jamais de secrets ni de données personnelles dans les noms de topics.
  4. Ne commencez pas un topic par $ ; ce préfixe est réservé aux topics du broker comme $SYS.
  5. Séparez les commandes de la télémétrie, par exemple .../cmd/... et .../telemetry/....

Le wildcard + correspond à exactement un niveau et # à un nombre quelconque de niveaux finaux. Un historian peut s'abonner à acme/#, alors qu'un superviseur de ligne n'a besoin que de acme/izmir/assembly/line4/+/status.

Essayez : deux clients sur broker.connectmq.com

Rien ne fait mieux comprendre le modèle que de le voir fonctionner. Installez les clients en ligne de commande Mosquitto (mosquitto_pub et mosquitto_sub), puis ouvrez deux terminaux. Choisissez un suffixe aléatoire pour que vos topics n'entrent pas en collision avec ceux des autres utilisateurs du serveur MQTT public gratuit. N'oubliez pas que l'espace public est lisible par tout le monde : ne publiez rien de sensible.

Étape 1 : démarrer un subscriber

# Terminal A : abonnement avec un wildcard
mosquitto_sub -h broker.connectmq.com -p 1883 -i sub-demo-7f3a \
  -t "connectmq/demo/7f3a/#" -v

Étape 2 : publier depuis un autre client

# Terminal B : publication de deux mesures
mosquitto_pub -h broker.connectmq.com -p 1883 -i pub-demo-7f3a \
  -t "connectmq/demo/7f3a/room1/temperature" -m "21.4"
mosquitto_pub -h broker.connectmq.com -p 1883 -i pub-demo-7f3a \
  -t "connectmq/demo/7f3a/room2/temperature" -m "19.8"

Le terminal A affiche les deux messages avec leurs topics. Le publisher n'a jamais su où se trouvait le subscriber : c'est le découplage spatial.

Étape 3 : prouver le découplage temporel avec un retained message

Arrêtez le subscriber avec Ctrl+C. Publiez maintenant une valeur retained alors que personne n'écoute :

mosquitto_pub -h broker.connectmq.com -p 1883 -i pub-demo-7f3a \
  -t "connectmq/demo/7f3a/door/state" -m "open" -r

Relancez le subscriber. Il reçoit immédiatement connectmq/demo/7f3a/door/state open, bien que le message ait été envoyé pendant qu'il était hors ligne. Pour faire le ménage, publiez un payload retained vide avec -r -n.

Étape 4 : le fan-out

Ouvrez un troisième terminal avec un autre subscriber (utilisez un client ID différent, comme sub2-demo-7f3a). Publiez une fois et les deux subscribers reçoivent le message. Une publication, plusieurs livraisons, et le code du publisher n'a pas changé.

Un subscriber programmatique en Python

Le même modèle dans du code illustre le découplage de synchronisation : le callback se déclenche à chaque arrivée de données pendant que votre programme reste libre de faire autre chose.

import time
import paho.mqtt.client as mqtt

BROKER = "broker.connectmq.com"
PREFIX = "connectmq/demo/7f3a"

def on_connect(client, userdata, flags, reason_code, properties):
    print("Connected:", reason_code)
    client.subscribe(f"{PREFIX}/#", qos=1)

def on_message(client, userdata, msg):
    print(f"{msg.topic} -> {msg.payload.decode()} (retained={msg.retain})")

client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2, client_id="py-sub-7f3a")
client.on_connect = on_connect
client.on_message = on_message
client.connect(BROKER, 1883, keepalive=60)
client.loop_start()

try:
    while True:
        # Votre application continue de travailler ; les messages arrivent en arrière-plan.
        time.sleep(5)
        client.publish(f"{PREFIX}/heartbeat", str(int(time.time())), qos=1)
except KeyboardInterrupt:
    client.loop_stop()
    client.disconnect()

Pourquoi le pub/sub convient si bien à l'IoT

  • Des liaisons peu fiables. Les appareils en cellulaire ou en Wi-Fi décrochent régulièrement. Les sessions persistantes et les QoS 1/2 leur permettent de rattraper leur retard sans logique de relance sur mesure. Le guide des niveaux de QoS MQTT détaille les garanties de livraison.
  • De nombreux consommateurs par donnée. La même mesure de vibration peut alimenter un tableau de bord, un script d'alerte et un historian. Chacun s'abonne indépendamment.
  • Des connexions uniquement sortantes. Les appareils ouvrent une connexion vers le broker ; rien n'a besoin de se connecter à l'appareil. C'est bien plus compatible avec le NAT et les pare-feux que de faire tourner un serveur HTTP sur chaque capteur.
  • Des paquets légers. L'en-tête fixe peut tenir en deux octets, ce qui limite le temps radio et la consommation des forfaits de données.

Les pièges courants et comment les éviter

L'absence d'abonné n'est pas une erreur. Si vous publiez sur un topic sans abonné, le broker accepte le message puis le supprime (sauf s'il est retained). Les développeurs pensent parfois qu'un message perdu est un problème réseau alors qu'il s'agit en réalité d'une faute de frappe dans le topic. Abonnez-vous à # sous votre préfixe pendant le débogage.

Des client ID dupliqués. Deux clients avec le même ID s'éjectent mutuellement en boucle. Chaque connexion a besoin d'un ID unique.

Des wildcards trop larges en production. Un service abonné à # reçoit tout, y compris du trafic qu'il ne sait pas traiter. Limitez les abonnements aux niveaux dont vous avez besoin.

Attendre des réponses. Le pub/sub n'a pas de mécanisme de réponse intégré. Si vous avez besoin d'une sémantique requête/réponse, MQTT 5 ajoute un response topic et des correlation data, présentés dans notre tour d'horizon des fonctionnalités de MQTT 5.

L'ordre entre topics. MQTT préserve l'ordre par topic pour une QoS donnée et un même publisher, mais pas entre topics différents. Ajoutez un horodatage ou un numéro de séquence dans les payloads quand l'ordre compte.

De la démo à la production

Le serveur MQTT public gratuit est parfait pour expérimenter, mais il est partagé et lisible par tous. Pour de vrais appareils, vous voulez de l'authentification, du TLS sur le port 8883 et votre propre espace de noms isolé. Un broker MQTT managé comme ConnectMQ vous offre exactement cela : créez un broker dans le portail, copiez le nom d'utilisateur, le mot de passe et le client ID générés, et pointez le même code vers le port 8883 avec TLS. ConnectMQ prend en charge MQTT 3.1.1 et 5.0 : les retained messages, l'expiration de session et les shared subscriptions fonctionnent comme décrit dans cet article. Pour un parcours plus complet du protocole, commencez par notre tutoriel MQTT complet, ou lisez comment fonctionne MQTT au niveau des paquets.

Démarrez avec ConnectMQ

Prêt à passer votre prototype pub/sub sur un broker privé ? Inscrivez-vous sur app.connectmq.com et créez un broker Serverless gratuit en quelques minutes, sans carte bancaire. Le client MQTT intégré au navigateur et l'explorateur de topics en direct de ConnectMQ vous permettent de voir circuler publications et abonnements sans rien installer.

Questions fréquentes

Le publish/subscribe de MQTT est-il la même chose qu'une file de messages ?

Pas exactement. Dans MQTT, chaque abonné correspondant reçoit sa propre copie de chaque message, alors qu'une file classique livre chaque message à un seul consommateur. Les shared subscriptions de MQTT 5 ajoutent un équilibrage de charge de type file quand vous en avez besoin.

Un client peut-il publier et s'abonner en même temps ?

Oui. Une seule connexion MQTT peut publier sur certains topics et s'abonner à d'autres : c'est ainsi que la plupart des appareils reçoivent des commandes tout en envoyant leur télémétrie.

Que deviennent les messages quand personne n'est abonné ?

Le broker les supprime, sauf si le message est retained, auquel cas la dernière valeur retained de chaque topic est stockée pour les futurs abonnés.

Les publishers savent-ils combien d'abonnés ont reçu un message ?

Non. Les acquittements MQTT ne concernent que le client et le broker, et c'est précisément ce qui garde publishers et subscribers découplés.

Articles liés

Qui a inventé MQTT ? L'histoire, des oléoducs à l'IoT

MQTT a été inventé en 1999 par Andy Stanford-Clark (IBM) et Arlen Nipper (Arcom) pour surveiller des oléoducs par satellite. Suivez son parcours vers l'open source, OASIS, l'ISO et les brokers MQTT managés d'aujourd'hui.

8 min de lecture

Pourquoi votre client MQTT se déconnecte sans cesse (et comment y remédier)

Les boucles de reconnexion sont l'un des problèmes MQTT les plus courants. Découvrez les cinq causes habituelles, des client ID en double aux timeouts de keep alive et aux paquets trop volumineux, et suivez une méthode de diagnostic qui identifie la vôtre.

9 min de lecture

Taille maximale d'un message MQTT : limites et stratégies pour les gros payloads

MQTT peut techniquement transporter un paquet de 256 Mo, mais les brokers, les bibliothèques clientes et les appareils imposent des limites bien plus basses. Découvrez où se trouvent les vraies limites, ce qui se passe quand on les dépasse et comment envoyer de gros payloads.

8 min de lecture

Tous les articles →

Votre broker MQTT privé, à quelques clics

Créez un compte, récupérez les identifiants de votre broker et connectez votre premier appareil — aucun serveur à installer, mettre à jour ou dimensionner.