Aller au contenu

MQTT — le protocole publish/subscribe de l'IoT

Léger, asynchrone et conçu pour les liens instables : MQTT est devenu le standard de facto de la communication applicative IoT, du capteur embarqué aux plateformes cloud à des millions de connexions.


Modèle publish/subscribe

MQTT repose sur un découplage total entre producteurs et consommateurs de données via un broker central. Un client publie un message sur un topic ; tous les clients abonnés à ce topic reçoivent le message. Ni le publisher ni les subscribers ne se connaissent directement.

graph LR
    S1[Capteur température] -- publish\nusine/zone-a/temp --> B((Broker\nMQTT))
    S2[Capteur humidité]   -- publish\nusine/zone-a/hum  --> B
    B -- subscribe\nusine/zone-a/# --> D1[Dashboard SCADA]
    B -- subscribe\nusine/+/temp   --> D2[Alarme thermique]
    B -- subscribe\n#              --> D3[Archiveur données]

Topics hiérarchiques

Les topics sont des chaînes UTF-8 séparées par /. La hiérarchie est libre et conventionnelle :

usine/batiment-a/capteur-42/temperature
home/salon/thermostat/setpoint
fleet/camion-17/gps/position

Wildcards

Wildcard Symbole Niveau Exemple
Un seul niveau + Unique usine/+/temp → zone-a, zone-b…
Tous les niveaux suivants # Terminal usine/# → tout ce qui commence par usine/

Le # ne peut apparaître qu'en fin de pattern. Un abonnement # seul récupère tous les messages du broker.


Niveaux de QoS

MQTT définit trois niveaux de garantie de livraison. Le choix impacte directement la fiabilité, la consommation réseau et la charge du broker.

QoS 0 — At most once (fire and forget)

sequenceDiagram
    participant P as Publisher
    participant B as Broker
    participant S as Subscriber
    P->>B: PUBLISH (QoS 0)
    B->>S: PUBLISH (QoS 0)
    Note over P,S: Aucun accusé. Message peut être perdu.

Usage : télémetrie haute fréquence où une perte occasionnelle est acceptable (température toutes les 5 s, GPS).

QoS 1 — At least once

sequenceDiagram
    participant P as Publisher
    participant B as Broker
    participant S as Subscriber
    P->>B: PUBLISH (QoS 1, PacketID=42)
    B->>P: PUBACK (PacketID=42)
    B->>S: PUBLISH (QoS 1, PacketID=42)
    S->>B: PUBACK (PacketID=42)
    Note over P,S: Garanti livré ≥1 fois. Doublons possibles.

Usage : alertes, commandes où la perte est inacceptable mais le doublon gérable.

QoS 2 — Exactly once

sequenceDiagram
    participant P as Publisher
    participant B as Broker
    participant S as Subscriber
    P->>B: PUBLISH (QoS 2, PacketID=7)
    B->>P: PUBREC (PacketID=7)
    P->>B: PUBREL (PacketID=7)
    B->>P: PUBCOMP (PacketID=7)
    B->>S: PUBLISH (QoS 2, PacketID=7)
    S->>B: PUBREC (PacketID=7)
    B->>S: PUBREL (PacketID=7)
    S->>B: PUBCOMP (PacketID=7)
    Note over P,S: 4 échanges par message. Exactement une livraison.

Usage : transactions financières, commandes d'actionneurs critiques, ordres de production.

QoS Livraisons Échanges réseau Latence Cas d'usage
0 0 ou 1 1 Minimale Télémetrie fréquente
1 ≥ 1 2 Faible Alertes, commandes
2 Exactement 1 4 Plus élevée Transactions critiques

Retain et Last Will and Testament

Retain messages

Un message publié avec le flag retain=true est conservé par le broker sur ce topic. Tout nouveau subscriber reçoit immédiatement ce dernier message retenu, même s'il s'abonne après la publication.

Cas d'usage typique : état courant d'un device (online/offline, dernière valeur connue d'un capteur) disponible à tout nouvel abonné sans attendre la prochaine publication.

Last Will and Testament (LWT)

À la connexion, un client peut déclarer un message de «testament» : topic, payload, QoS et retain. Si la connexion est rompue de façon anormale (timeout keepalive, coupure réseau), le broker publie automatiquement ce message.

# Exemple de LWT
Topic   : fleet/camion-17/status
Payload : {"state": "offline", "reason": "connection_lost"}
QoS     : 1
Retain  : true

Ce mécanisme est fondamental pour la détection de déconnexion involontaire dans les flottes IoT.


Brokers MQTT — comparatif

Broker Licence Mémoire Clustering Auth/TLS MQTT 5 Points forts
Mosquitto EPL 2.0 < 2 Mo Non (bridge) Oui Oui (≥2.0) Ultra-léger, embarqué, Raspberry Pi
EMQX Apache 2 / Commercial ~50 Mo Oui (Erlang) Oui Oui 100M+ connexions, plugins Kafka/DB
VerneMQ Apache 2 ~30 Mo Oui (Erlang) Oui Partiel Erlang OTP, écriture plugins Lua
HiveMQ Commercial ~200 Mo Oui Oui Oui Certifié industries, extensions Java
NanoMQ MIT < 1 Mo Non Oui Oui Edge ultra-léger, multi-thread

Mosquitto s'impose sur les gateways embarquées (OpenWRT, Raspberry Pi) grâce à son empreinte mémoire inférieure à 2 Mo. EMQX cible les déploiements cloud à très haute disponibilité avec son cluster Erlang.


MQTT 5.0 — nouvelles fonctionnalités clés

La version 5.0 (2019) apporte des fonctionnalités manquantes en 3.1.1, notamment pour les déploiements industriels à grande échelle.

Shared subscriptions

Plusieurs consommateurs partagent la charge d'un topic sans recevoir de doublons :

# Groupe de consommateurs "workers" sur le topic data/#
$share/workers/data/#

Le broker distribue chaque message à un seul membre du groupe (round-robin ou aléatoire). Permet le scaling horizontal des consommateurs.

Flow control

Le client annonce son Receive Maximum à la connexion : nombre maximum de messages QoS 1/2 en vol simultanément. Évite la saturation des clients lents.

Topic alias

Remplace un topic long par un entier court pour réduire le overhead sur les liens contraints. L'alias est négocié à la connexion.

Reason codes

Chaque ACK inclut un code de raison détaillé (succès, non autorisé, topic invalide…). En 3.1.1, les SUBACK se limitaient à 0x00/0x80.

User properties

Paires clé/valeur arbitraires dans les headers : métadonnées, corrélation, traçabilité sans toucher au payload.

Fonctionnalité MQTT 3.1.1 MQTT 5.0
Shared subscriptions Non Oui
Reason codes détaillés Non Oui (45 codes)
Topic alias Non Oui
Flow control Non Oui
User properties Non Oui
Message expiry Non Oui
Session expiry configurable Non Oui
Request/Response natif Non Oui

Sparkplug B — MQTT industriel

Sparkplug B (spécification Cirrus Link / Eclipse Foundation) définit un namespace et un encodage au-dessus de MQTT 3.1.1 pour les environnements SCADA/IIoT.

Namespace

spBv1.0/<group_id>/<message_type>/<edge_node_id>[/<device_id>]

Exemples :

spBv1.0/Usine-A/NBIRTH/PLC-01
spBv1.0/Usine-A/DDATA/PLC-01/Capteur-Temp
spBv1.0/Usine-A/NDEATH/PLC-01

Types de messages

Type Signification
NBIRTH Nœud edge en ligne, publie toutes ses metrics
NDEATH Nœud edge hors ligne (LWT)
DBIRTH Device connecté au nœud, metrics initiales
DDEATH Device déconnecté
NDATA Données télémétriques du nœud (delta)
DDATA Données télémétriques du device (delta)
NCMD Commande vers un nœud
DCMD Commande vers un device

Encodage Protobuf

Le payload est sérialisé en Protocol Buffers (binaire compact) avec un schéma Sparkplug défini. Chaque metric inclut : nom, type, valeur, timestamp, qualité. Les BIRTH publient toutes les metrics ; les DATA publient uniquement les deltas (valeurs modifiées).

Birth/Death certificates

Le mécanisme BIRTH/DEATH reconstruit l'état complet de l'infrastructure à tout moment : un nouveau subscriber peut rejoindre et connaître immédiatement l'état de tous les équipements. C'est la principale limite de MQTT 3.1.1 vanilla (pas de modèle d'état natif) que Sparkplug résout.


Ce qu'il faut retenir

  • MQTT est asynchrone et découplé : publisher et subscriber ne se connaissent pas, le broker est l'intermédiaire unique.
  • Le choix du QoS (0/1/2) équilibre fiabilité, overhead et latence — QoS 2 n'est justifié que pour des transactions réellement critiques.
  • LWT + retain forment le mécanisme de base pour suivre l'état de connexion des devices.
  • MQTT 5.0 apporte les shared subscriptions, le flow control et les reason codes essentiels pour les déploiements à grande échelle.
  • Sparkplug B ajoute un namespace et un modèle d'état complet (BIRTH/DEATH/DATA) pour les cas SCADA/IIoT.

Chapitre suivant : CoAP & protocoles contraints — REST sur UDP pour les microcontrôleurs les plus limités en ressources.