Les topic aliases de MQTT 5 remplacent un long nom de topic par un nombre de 2 octets pour le reste d'une connexion. Le premier PUBLISH porte le topic et l'alias. Chaque PUBLISH suivant envoie un topic vide plus l'alias. Pour les tester, lisez le Topic Alias Maximum accordé par le broker dans son CONNACK, publiez avec et sans nom de topic, vérifiez que les subscribers reçoivent le topic complet et reproduisez les deux cas d'erreur : un alias hors limites et un alias inconnu du broker.
Le mécanisme lui-même est présenté dans les topic aliases MQTT. Cet article est le plan de test.
Comment les alias sont négociés
| Sens | Qui fixe la limite | Où | Par défaut |
|---|---|---|---|
| Client → broker | Broker | Topic Alias Maximum dans le CONNACK | 0 (aucun alias) |
| Broker → client | Client | Topic Alias Maximum dans le CONNECT | 0 (aucun alias) |
Les règles qu'une implémentation correcte respecte :
- Les valeurs d'alias vont de 1 au maximum négocié. 0 n'est jamais valide.
- L'émetteur choisit la correspondance. Envoyer un nouveau topic avec un numéro d'alias existant le réaffecte.
- Les correspondances sont propres à chaque connexion et à chaque sens. Elles disparaissent à la déconnexion, même avec une session persistante.
- Un PUBLISH avec un topic vide doit porter un alias déjà affecté sur cette connexion.
Combien un alias fait-il gagner ?
Prenons un topic de télémétrie typique, factory/line-3/press-07/telemetry/vibration (43 caractères), un payload de 20 octets et le QoS 1 :
| Champ | Topic complet | Avec alias |
|---|---|---|
| En-tête fixe | 2 octets | 2 octets |
| Nom du topic (longueur sur 2 octets + texte) | 45 octets | 2 octets (vide) |
| Identifiant de paquet | 2 octets | 2 octets |
| Propriétés (longueur + Topic Alias) | 1 octet | 4 octets |
| Payload | 20 octets | 20 octets |
| Total | 70 octets | 30 octets |
Cela fait 40 octets économisés par message, plus de la moitié du paquet. À un message par seconde, un appareil économise environ 3,5 Mo par jour. Le gain ne compte que lorsque les topics sont longs par rapport aux payloads et que les octets coûtent de l'argent ou de la batterie, comme sur des liaisons cellulaires, satellites ou LPWAN. Sur un LAN avec des payloads de 2 Ko, c'est du bruit. Le calculateur de taille de paquet donne les chiffres pour vos propres topics, et l'overhead de bande passante MQTT présente d'autres façons de réduire le trafic. TLS ajoute son propre overhead par enregistrement : mesurez sur le réseau si le budget est serré.
Test 1 : lire le maximum négocié
Avant tout, journalisez ce que le broker accorde. Les brokers diffèrent : certains autorisent de nombreux alias, d'autres seulement quelques-uns, d'autres les désactivent (maximum 0). Un client qui utilise des alias sans vérifier sera déconnecté par les brokers qui n'en autorisent aucun.
Avec la CLI Mosquitto, -d affiche le CONNACK, mais l'affichage des propriétés varie selon les versions. Un script est plus fiable. Le test ci-dessous affiche d'abord le maximum et s'arrête s'il vaut 0.
Test 2 : les publications avec alias arrivent intactes
Ce script paho-mqtt 2.x publie un message avec le topic complet et l'alias 1, puis quatre avec un topic vide et l'alias 1, et vérifie qu'un subscriber normal reçoit les cinq avec le nom de topic complet. Ensuite il se reconnecte et envoie l'alias périmé pour voir comment réagit le broker.
import time, uuid
import paho.mqtt.client as mqtt
from paho.mqtt.properties import Properties
from paho.mqtt.packettypes import PacketTypes
HOST, PORT = "broker.connectmq.com", 1883
RUN = uuid.uuid4().hex[:8]
TOPIC = f"testmqtt/alias/{RUN}/factory/line-3/press-07/telemetry"
received = []
def client(cid, log):
c = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2, client_id=f"{cid}-{RUN}", protocol=mqtt.MQTTv5)
c.on_connect = lambda cl, u, f, rc, props: log.update(max=getattr(props, "TopicAliasMaximum", 0))
c.on_disconnect = lambda cl, u, f, rc, props: log.update(disconnect=str(rc))
return c
def alias_props(alias):
p = Properties(PacketTypes.PUBLISH)
p.TopicAlias = alias
return p
# Subscriber: a normal client that does not accept aliases from the broker
sub_log = {}
sub = client("alias-sub", sub_log)
sub.on_message = lambda cl, u, msg: received.append((msg.topic, msg.payload.decode()))
sub.connect(HOST, PORT)
sub.loop_start()
sub.subscribe(TOPIC, qos=1)
# Test 1: negotiation + valid alias use
log = {}
pub = client("alias-pub", log)
pub.connect(HOST, PORT)
pub.loop_start()
time.sleep(1)
print("broker Topic Alias Maximum:", log.get("max"))
if not log.get("max"):
raise SystemExit("broker does not accept topic aliases from clients (maximum 0)")
pub.publish(TOPIC, "m0", qos=1, properties=alias_props(1)) # set alias 1 = TOPIC
for i in range(1, 5):
pub.publish("", f"m{i}", qos=1, properties=alias_props(1)) # topic omitted, alias only
time.sleep(2)
ok = received == [(TOPIC, f"m{i}") for i in range(5)]
print("PASS" if ok else "FAIL", "aliased messages arrive with the full topic:", len(received), "of 5")
pub.disconnect(); pub.loop_stop()
# Test 2: alias mappings do not survive a reconnect
received.clear()
log = {}
pub = client("alias-pub", log)
pub.connect(HOST, PORT)
pub.loop_start()
time.sleep(1)
pub.publish("", "after-reconnect", qos=1, properties=alias_props(1)) # unknown on this connection
time.sleep(2)
print("PASS" if not received else "FAIL", "stale alias after reconnect is not delivered;",
"broker reaction:", log.get("disconnect", "no DISCONNECT, message dropped"))
pub.disconnect(); pub.loop_stop()
# Test 3: alias above the negotiated maximum (only possible if the maximum is below 65535)
if log.get("max", 0) < 65535:
log2 = {}
bad = client("alias-bad", log2)
bad.connect(HOST, PORT)
bad.loop_start()
time.sleep(1)
bad.publish(TOPIC, "too-high", qos=1, properties=alias_props(log2["max"] + 1))
time.sleep(2)
print("broker reaction to alias > maximum:", log2.get("disconnect", "none"))
bad.loop_stop()
sub.disconnect(); sub.loop_stop()Une exécution typique affiche :
broker Topic Alias Maximum: 65535
PASS aliased messages arrive with the full topic: 5 of 5
PASS stale alias after reconnect is not delivered; broker reaction: no DISCONNECT, message droppedpaho-mqtt ne gère pas les alias à votre place. Il envoie exactement l'alias que vous définissez et ne résout pas les alias venant du broker : n'annoncez donc jamais de Topic Alias Maximum sur un subscriber paho. Cela en fait aussi un bon outil pour les tests négatifs. paho refuse cependant l'alias 0 localement (TopicAlias property value must be in the range 1-65535) : pour tester la réaction du broker à l'alias 0, il vous faut un outil de paquets bruts.
Alias automatiques avec MQTT.js
MQTT.js 5 peut attribuer les alias pour vous. Avec autoAssignTopicAlias, il associe les topics aux alias selon le principe du moins récemment utilisé (LRU), dans la limite du maximum du broker. Journalisez les paquets pour vérifier ce qui passe sur le réseau :
import mqtt from "mqtt";
const topic = "testmqtt/alias/js-demo/factory/line-3/press-07/telemetry";
const client = mqtt.connect("mqtt://broker.connectmq.com:1883", {
protocolVersion: 5,
clientId: `alias-js-${Math.random().toString(16).slice(2, 10)}`,
autoAssignTopicAlias: true, // let MQTT.js pick and reuse aliases
properties: { topicAliasMaximum: 10 }, // accept up to 10 aliases from the broker
});
// Log what actually goes over the wire
client.on("packetsend", (p) => {
if (p.cmd === "publish") console.log(`sent topic="${p.topic}" alias=${p.properties?.topicAlias}`);
});
client.on("connect", (connack) => {
console.log("broker Topic Alias Maximum:", connack.properties?.topicAliasMaximum ?? 0);
let n = 0;
const timer = setInterval(() => {
client.publish(topic, JSON.stringify({ n, vibration: Math.random() }), { qos: 1 });
if (++n === 5) {
clearInterval(timer);
setTimeout(() => client.end(), 500);
}
}, 300);
});
client.on("error", (err) => console.error("error:", err.message));Sortie attendue : la première ligne montre le topic complet avec alias=1, les quatre suivantes topic="" avec alias=1. Si chaque ligne montre le topic complet, le broker a accordé un maximum de 0 et MQTT.js est revenu silencieusement aux publications normales. C'est le comportement correct, mais vous n'économisez rien. autoUseTopicAlias est l'option la plus prudente : elle ne réutilise que les alias que vous avez enregistrés vous-même.
Test 3 : les cas d'erreur
| Ce que vous envoyez | Ce que dit la spécification | Erreur que l'on recherche |
|---|---|---|
| Alias 0 | Erreur de protocole | DISCONNECT 0x94 Topic Alias invalid |
| Alias au-dessus du maximum négocié | Erreur de protocole | DISCONNECT 0x94 Topic Alias invalid |
| Topic vide, alias jamais affecté | Erreur de protocole | DISCONNECT 0x82 Protocol Error |
| N'importe quel alias avec un maximum de 0 | Erreur de protocole | 0x94, ou côté client Sending Topic Alias out of range dans MQTT.js |
| Alias périmé après reconnexion | Comme « jamais affecté » | 0x82, ou le message disparaît en silence |
Tous les brokers ne réagissent pas de la même façon. Certains envoient le DISCONNECT avec le reason code, d'autres ferment la connexion ou suppriment le message sans prévenir. L'exécution ci-dessus montre un broker qui a supprimé le message à l'alias périmé sans déconnecter. Votre test doit donc vérifier le résultat important, le message invalide n'a pas été livré sous un mauvais topic, et noter la réaction du broker à titre d'information. Décodez les reason codes avec l'outil de reason codes. Les correctifs de chaque cas sont dans les erreurs Topic Alias invalid et l'erreur de protocole MQTT 0x82.
Vérifier côté subscriber
Les subscribers ne devraient jamais remarquer les alias, sauf s'ils l'ont choisi. Ouvrez le client MQTT en ligne, abonnez-vous à testmqtt/alias/# et lancez l'un des scripts : chaque message doit afficher le topic complet. Si un subscriber qui n'a pas annoncé de Topic Alias Maximum reçoit un jour un topic vide, le broker est défaillant. C'est un bug rare mais sérieux, qui mérite d'être signalé.
Voir les messages avec alias arriver avec le topic complet
Checklist
- Journalisez le Topic Alias Maximum de chaque CONNACK et ne le dépassez jamais.
- Envoyez d'abord le topic complet avec l'alias, puis des publications avec alias seul, et vérifiez que les subscribers voient des topics complets.
- Reconnectez-vous et confirmez que les alias périmés ne sont pas utilisés.
- Essayez un alias au-dessus du maximum et un alias non affecté, et notez la réaction du broker.
- Mesurez le gain réel en octets pour vos topics avant de rendre les alias obligatoires.
Les topic aliases sont un gain peu coûteux sur les liaisons contraintes et inutiles ailleurs. Testez la négociation et le cas de reconnexion : ils économiseront de la bande passante sans devenir la raison pour laquelle un appareil se tait.
Questions fréquentes
Quelle est la valeur par défaut de Topic Alias Maximum ?
0. Si le CONNECT ou le CONNACK ne contient pas la propriété Topic Alias Maximum, le récepteur n'accepte aucun alias. Chaque sens est négocié séparément : la valeur du client limite le broker, celle du broker limite le client.
Les topic aliases survivent-ils à une reconnexion ?
Non. Les correspondances d'alias n'existent que pendant une connexion réseau, même avec une session persistante. Après chaque reconnexion, le client doit renvoyer le nom de topic complet avant de pouvoir réutiliser l'alias.
Les subscribers voient-ils l'alias ?
Seulement s'ils l'ont demandé. Les alias s'appliquent saut par saut : le broker résout l'alias du publisher en topic complet et n'utilise d'alias vers un subscriber que si celui-ci a annoncé son propre Topic Alias Maximum. La plupart des subscribers reçoivent simplement le nom complet.
