Fondamentaux MQTT

QoS maximum MQTT et rétrogradation des abonnements

La QoS demandée n'est pas toujours la QoS obtenue. Découvrez comment se calcule la QoS effective, comment les brokers annoncent une QoS maximum et accordent des niveaux d'abonnement inférieurs, et comment vérifier ce qu'utilise réellement votre connexion.

Un publisher en QoS 2 et un subscriber en QoS 1 se rejoignant sur un broker, illustrant la rétrogradation de la QoS maximum MQTT
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

La QoS maximum MQTT est l'aspect de la qualité de service qui surprend le plus : vous pouvez publier en QoS 2 et recevoir malgré tout un message en QoS 0. Le niveau réellement utilisé pour une livraison dépend du publisher, du subscriber et des limites propres au broker. Dans cet article, vous verrez comment se calcule la QoS effective, comment les brokers annoncent et appliquent un maximum, et comment tester précisément ce qu'obtient votre connexion.

La QoS se négocie à chaque saut

MQTT propose trois niveaux de QoS : 0 (au plus une fois), 1 (au moins une fois) et 2 (exactement une fois). S'ils sont nouveaux pour vous, commencez par les niveaux de QoS MQTT expliqués.

Le point essentiel est que la QoS n'est pas de bout en bout. Un message parcourt deux sauts distincts :

  1. Du publisher au broker, à la QoS choisie par le publisher pour ce PUBLISH.
  2. Du broker à chaque subscriber, à une QoS que le broker calcule pour cet abonnement.

Chaque saut a sa propre poignée de main. Le PUBACK du publisher vient du broker, pas du subscriber : un publisher ne sait donc jamais si un subscriber a reçu le message.

Comment se calcule la QoS effective

Pour chaque subscriber, le broker livre à la plus basse de deux valeurs : la QoS du PUBLISH entrant et la QoS accordée à l'abonnement correspondant.

QoS de publication QoS d'abonnement QoS livrée
0 2 0
1 0 0
1 2 1
2 1 1
2 2 2

Deux conséquences comptent en pratique :

  • S'abonner en QoS 2 n'améliore rien. Si un capteur publie en QoS 0, chaque subscriber reçoit en QoS 0, quoi qu'il ait demandé.
  • Un subscriber peut rétrograder volontairement. Un tableau de bord qui ne s'intéresse qu'à la dernière valeur peut s'abonner en QoS 0 à une télémétrie publiée en QoS 1, ce qui économise les acquittements sur son propre lien.

Si un filtre d'abonnement en chevauche un autre (par exemple plant/# et plant/line1/+), le broker peut livrer le message une seule fois à la QoS correspondante la plus élevée, ou une fois par abonnement en MQTT 5, selon l'implémentation. Évitez autant que possible les abonnements qui se chevauchent avec des QoS différentes.

Comment les brokers plafonnent la QoS

Un broker n'est pas obligé de prendre en charge tous les niveaux pour tous les clients. Il dispose de deux mécanismes pour l'indiquer.

QoS accordée dans le SUBACK. Lorsqu'un client s'abonne, le broker répond par un SUBACK contenant la QoS accordée pour chaque filtre. Il peut accorder un niveau inférieur à celui demandé. En MQTT 3.1.1, les codes de retour sont 0, 1, 2 ou 0x80 en cas d'échec ; en MQTT 5, ce sont des reason codes où 0x00, 0x01 et 0x02 signifient QoS accordée 0, 1 et 2. Un client bien écrit vérifie cette valeur au lieu de supposer que sa demande a été honorée.

Maximum QoS dans le CONNACK (MQTT 5). Un broker MQTT 5 qui ne prend pas en charge la QoS 2, ou les QoS 1 et 2, inclut une propriété Maximum QoS dans le CONNACK. Si la propriété est absente, la QoS 2 est prise en charge. Un client qui publie ensuite au-dessus du maximum annoncé viole le protocole, et le broker le déconnecte avec le reason code 0x9B (QoS not supported). En MQTT 3.1.1, cette propriété n'existe pas : les clients le découvrent à leurs dépens.

Les brokers plafonnent la QoS pour de bonnes raisons : la QoS 2 exige davantage d'état stocké et quatre paquets par message à chaque saut, ce qui pèse lourd sur une infrastructure partagée et multi-tenant.

Tester la QoS maximum MQTT sur le serveur MQTT public gratuit

Le serveur MQTT public gratuit broker.connectmq.com prend en charge les QoS 0 à 2 : c'est donc un bon endroit pour observer les rétrogradations dues à la combinaison publication/abonnement. Le flag -d fait afficher aux outils Mosquitto les paquets du protocole, y compris la QoS accordée dans le SUBACK.

Terminal 1, abonnement en demandant la QoS 1 :

mosquitto_sub -d -h broker.connectmq.com -p 1883 -i mq-sub-u3x7 -q 1 \
  -t 'connectmq/demo/u3x7/#' -F 'qos=%q %t %p'

Dans la sortie de débogage, cherchez une ligne comme Client mq-sub-u3x7 received SUBACK suivie de Subscribed (mid: 1): 1. Le dernier nombre est la QoS accordée.

Terminal 2, publication à chaque niveau :

for q in 0 1 2; do
  mosquitto_pub -h broker.connectmq.com -p 1883 -i mq-pub-u3x7 -q $q \
    -t connectmq/demo/u3x7/test -m "published at qos $q"
done

Le terminal 1 affiche qos=0, qos=1 et qos=1. La publication en QoS 2 a été rétrogradée à 1 sur le chemin vers ce subscriber, car c'est ce que demandait l'abonnement. Relancez le subscriber avec -q 2 et la troisième ligne devient qos=2.

Vérifier la QoS accordée et la QoS maximum dans le code

Ce script paho-mqtt 2.x se connecte en MQTT 5, affiche la Maximum QoS annoncée par le broker si elle est présente, s'abonne en QoS 2 et affiche ce qui lui a été accordé :

import uuid
import paho.mqtt.client as mqtt

BROKER = "broker.connectmq.com"
TOPIC = "connectmq/demo/u3x7/check"

def on_connect(client, userdata, flags, reason_code, properties):
    max_qos = getattr(properties, "MaximumQoS", None)
    if max_qos is None:
        print("CONNACK: no Maximum QoS property, QoS 2 supported")
    else:
        print(f"CONNACK: broker maximum QoS is {max_qos}")
    client.subscribe(TOPIC, qos=2)

def on_subscribe(client, userdata, mid, reason_code_list, properties):
    rc = reason_code_list[0]
    if rc.is_failure:
        print("subscription refused:", rc)
    else:
        print(f"SUBACK: requested 2, granted {rc.value}")
    client.disconnect()

client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2,
                     client_id=f"qoscheck-{uuid.uuid4().hex[:8]}",
                     protocol=mqtt.MQTTv5)
client.on_connect = on_connect
client.on_subscribe = on_subscribe
client.connect(BROKER, 1883, keepalive=30)
client.loop_forever()

Exécutez le même script contre votre broker de production avec vos vrais identifiants avant de vous fier à un niveau de QoS. Cela prend quelques secondes et élimine les suppositions.

QoS des messages retenus et des messages Will

La même règle du minimum s'applique aux messages que le broker envoie de sa propre initiative. Un retained message est stocké avec la QoS à laquelle il a été publié, et un nouveau subscriber le reçoit à la plus basse entre cette QoS et la QoS accordée à son abonnement. Un Last Will est publié à la QoS de will définie dans le CONNECT, et chaque subscriber le reçoit là encore à la plus basse des deux. Si la QoS maximum du broker est inférieure à la QoS de will demandée, un broker MQTT 5 peut refuser la connexion avec le reason code 0x9B : gardez donc la QoS du will dans la limite annoncée.

Check-list pratique

  1. Choisissez la QoS de chaque topic en fonction du coût d'un message perdu ou dupliqué.
  2. Publiez à cette QoS ; les subscribers ne peuvent pas l'augmenter.
  3. Vérifiez la QoS accordée dans le SUBACK et journalisez-la lorsqu'elle est inférieure à la demande.
  4. En MQTT 5, lisez la Maximum QoS dans le CONNACK et limitez vos publications à cette valeur.
  5. Concevez vos consommateurs pour la QoS réellement obtenue : idempotents en QoS 1 (voir les messages dupliqués MQTT), tolérants aux trous en QoS 0.
  6. Évitez les abonnements qui se chevauchent avec des QoS différentes sur un même client.

Dépanner les problèmes de QoS

Client déconnecté juste après une publication. Si le reason code est 0x9B, vous avez publié au-dessus du maximum du broker. Baissez la QoS ou passez à une offre ou à un broker qui la prend en charge. La liste complète des codes se trouve dans les reason codes MQTT.

Le subscriber reçoit en QoS 0 alors qu'il s'est abonné en QoS 1. Le publisher utilise la QoS 0. Corrigez-le à la source.

La bibliothèque signale un succès mais des messages sont perdus. Certaines bibliothèques ignorent la QoS accordée. Vérifiez vous-même le SUBACK comme dans le script ci-dessus.

La QoS 2 est lente. Chaque message nécessite quatre paquets par saut. Pour une télémétrie à haut débit, la QoS 1 avec déduplication offre généralement un meilleur débit.

Les règles normatives figurent dans la spécification OASIS MQTT 5.0, dans les sections consacrées aux propriétés SUBACK et CONNACK.

Limites de QoS des offres ConnectMQ

ConnectMQ est explicite sur la QoS de chaque offre. L'offre Serverless gratuite prend en charge la QoS jusqu'à 1, l'offre Serverless payante ajoute la QoS 2 ainsi que des messages plus volumineux et les shared subscriptions, et les options Dedicated, BYOC et Self Managed Enterprise vous donnent un cluster isolé. Le serveur MQTT public gratuit autorise les QoS 0 à 2 pour vos expérimentations. Exécutez le script de vérification avec vos identifiants ConnectMQ pour confirmer ce que rapporte votre connexion. Si vous comparez des fournisseurs, notre présentation du broker MQTT managé et le tutoriel MQTT sont de bonnes lectures pour la suite.

Démarrer avec ConnectMQ

Créez gratuitement un broker sur app.connectmq.com avec l'offre Serverless, sans carte bancaire. Commencez en QoS 0 et 1, puis passez à l'offre payante pour la QoS 2 lorsque la charge de votre broker MQTT cloud exige une livraison exactement une fois.

Questions fréquentes

Qu'est-ce que la QoS effective en MQTT ?

C'est la QoS utilisée pour livrer un message à un subscriber : la plus basse entre la QoS de publication et la QoS accordée à l'abonnement.

Un subscriber peut-il obtenir une QoS plus élevée que celle du publisher ?

Non. Un message publié en QoS 0 est toujours livré en QoS 0, quel que soit l'abonnement.

Comment connaître la QoS maximum du broker ?

En MQTT 5, lisez la propriété Maximum QoS dans le CONNACK ; si elle est absente, la QoS 2 est prise en charge. En MQTT 3.1.1, vérifiez la QoS accordée dans le SUBACK.

Que se passe-t-il si je publie au-dessus de la QoS maximum ?

Un broker MQTT 5 déconnecte le client avec le reason code 0x9B, QoS not supported.

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.