MQTT 5 topic alias'ları, uzun bir topic adını bağlantının geri kalanı boyunca 2 baytlık bir sayıyla değiştirir. İlk PUBLISH hem topic'i hem alias'ı taşır. Sonraki her PUBLISH boş bir topic ile birlikte alias'ı gönderir. Test etmek için broker'ın CONNACK içinde verdiği Topic Alias Maximum değerini okuyun, topic adıyla ve topic adı olmadan yayın yapın, subscriber'ların tam topic'i aldığını kontrol edin ve iki hata durumunu yeniden üretin: aralık dışındaki bir alias ve broker'ın tanımadığı bir alias.
Mekanizmanın kendisi MQTT topic alias'ları yazısında anlatılıyor. Bu makale test planıdır.
Alias'lar nasıl müzakere edilir
| Yön | Limiti kim belirler | Nerede | Varsayılan |
|---|---|---|---|
| İstemci → broker | Broker | CONNACK içinde Topic Alias Maximum | 0 (alias yok) |
| Broker → istemci | İstemci | CONNECT içinde Topic Alias Maximum | 0 (alias yok) |
Doğru bir uygulamanın izlediği kurallar:
- Alias değerleri 1'den müzakere edilen maksimuma kadardır. 0 asla geçerli değildir.
- Eşlemeyi gönderen taraf seçer. Mevcut bir alias numarasıyla yeni bir topic göndermek o alias'ı yeniden eşler.
- Eşlemeler bağlantıya ve yöne özgüdür. Oturum kalıcı olsa bile bağlantı kesilince kaybolurlar.
- Boş topic'li bir PUBLISH, bu bağlantıda zaten eşlenmiş bir alias taşımalıdır.
Bir alias ne kadar tasarruf sağlar?
Tipik bir telemetri topic'i olan factory/line-3/press-07/telemetry/vibration (43 karakter), 20 baytlık bir payload ve QoS 1 alalım:
| Alan | Tam topic | Alias ile |
|---|---|---|
| Sabit başlık | 2 bayt | 2 bayt |
| Topic adı (2 baytlık uzunluk + metin) | 45 bayt | 2 bayt (boş) |
| Paket kimliği | 2 bayt | 2 bayt |
| Özellikler (uzunluk + Topic Alias) | 1 bayt | 4 bayt |
| Payload | 20 bayt | 20 bayt |
| Toplam | 70 bayt | 30 bayt |
Bu, mesaj başına 40 bayt, yani paketin yarısından fazlası demektir. Saniyede bir mesajla tek bir cihaz günde yaklaşık 3,5 MB tasarruf eder. Tasarruf yalnızca topic'ler payload'lara göre uzunsa ve baytlar para ya da pil harcatıyorsa, örneğin hücresel, uydu veya LPWAN bağlantılarında önemlidir. 2 KB'lık payload'ların gezdiği bir LAN'da önemsizdir. Paket boyutu hesaplayıcı kendi topic'leriniz için rakamları gösterir; MQTT bant genişliği yükü yazısı da trafiği küçültmenin diğer yollarını ele alır. TLS kayıt başına kendi ek yükünü getirir, bu yüzden bütçe dar ise ölçümü hat üzerinde yapın.
Test 1: müzakere edilen maksimumu okuyun
Her şeyden önce broker'ın ne verdiğini loglayın. Broker'lar farklıdır: kimi çok sayıda alias'a izin verir, kimi yalnızca birkaçına, kimi de özelliği tamamen kapatır (maksimum 0). Kontrol etmeden alias kullanan bir istemcinin bağlantısı, hiç alias'a izin vermeyen broker'larda kesilir.
Mosquitto CLI'da -d CONNACK'i yazdırır, ancak özelliklerin çıktısı sürümden sürüme değişir. Bir betik daha güvenilirdir. Aşağıdaki test önce maksimumu yazdırır ve değer 0 ise durur.
Test 2: alias'lı yayınlar eksiksiz ulaşıyor
Bu paho-mqtt 2.x betiği tam topic ve alias 1 ile bir mesaj, boş topic ve alias 1 ile dört mesaj daha yayınlar ve normal bir subscriber'ın beşini de tam topic adıyla aldığını kontrol eder. Ardından yeniden bağlanır ve broker'ın tepkisini görmek için eskimiş alias'ı gönderir.
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()Tipik bir çalıştırma şunu yazdırır:
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 alias'ları sizin yerinize yönetmez. Ayarladığınız alias'ı aynen gönderir ve broker'dan gelen alias'ları çözmez; bu yüzden bir paho subscriber'ında asla Topic Alias Maximum bildirmeyin. Bu durum onu negatif testler için de iyi bir araç yapar. Yine de paho, alias 0'ı yerel olarak reddeder (TopicAlias property value must be in the range 1-65535); broker'ın alias 0'a tepkisini test etmek için ham paket gönderebilen bir araca ihtiyacınız vardır.
MQTT.js ile otomatik alias'lar
MQTT.js 5 alias'ları sizin için atayabilir. autoAssignTopicAlias ile topic'leri, broker'ın maksimumu dahilinde en az son kullanılan (LRU) mantığıyla alias'lara eşler. Hat üzerinden neyin gittiğini doğrulamak için paketleri loglayın:
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));Beklenen çıktı: ilk satır alias=1 ile tam topic'i, sonraki dört satır ise alias=1 ile topic="" gösterir. Her satırda tam topic görünüyorsa broker maksimum 0 vermiş ve MQTT.js sessizce normal yayınlara dönmüştür. Bu doğru davranıştır ama hiçbir tasarruf yapmadığınız anlamına gelir. autoUseTopicAlias daha temkinli seçenektir: yalnızca sizin kaydettiğiniz alias'ları yeniden kullanır.
Test 3: hata durumları
| Ne gönderiyorsunuz | Spesifikasyon ne diyor | İnsanların aradığı hata |
|---|---|---|
| Alias 0 | Protokol hatası | DISCONNECT 0x94 Topic Alias invalid |
| Müzakere edilen maksimumun üstünde alias | Protokol hatası | DISCONNECT 0x94 Topic Alias invalid |
| Boş topic, hiç eşlenmemiş alias | Protokol hatası | DISCONNECT 0x82 Protocol Error |
| Maksimum 0 iken herhangi bir alias | Protokol hatası | 0x94 ya da MQTT.js'te istemci tarafında Sending Topic Alias out of range |
| Yeniden bağlanma sonrası eskimiş alias | "Hiç eşlenmemiş" ile aynı | 0x82 ya da mesaj sessizce kaybolur |
Her broker aynı tepkiyi vermez. Bazıları reason code ile DISCONNECT gönderir, bazıları bağlantıyı kapatır ya da o tek mesajı haber vermeden atar. Yukarıdaki çalıştırma, eskimiş alias'lı mesajı bağlantıyı kesmeden atan bir broker'ı gösteriyor. Bu yüzden testiniz asıl önemli sonucu doğrulamalı, yani hatalı mesaj yanlış bir topic altında teslim edilmedi, broker'ın tepkisini ise bilgi olarak kaydetmelidir. Reason code'ları reason code aracı ile çözün. Her durumun çözümü Topic Alias invalid hataları ve MQTT protokol hatası 0x82 yazılarında.
Subscriber tarafını doğrulamak
Subscriber'lar, kendileri tercih etmedikçe alias'ları asla fark etmemelidir. Çevrimiçi MQTT istemcisini açın, testmqtt/alias/# topic'ine abone olun ve betiklerden birini çalıştırın: her mesaj tam topic'i göstermelidir. Topic Alias Maximum bildirmemiş bir subscriber bir gün boş topic alırsa broker hatalıdır. Bu nadir ama ciddi bir hatadır ve bildirilmeye değer.
Alias'lı mesajların tam topic ile gelişini izleyin
Kontrol listesi
- Her CONNACK'teki Topic Alias Maximum değerini loglayın ve asla aşmayın.
- Önce alias ile birlikte tam topic'i, sonra yalnızca alias'lı yayınları gönderin ve subscriber'ların tam topic gördüğünü doğrulayın.
- Yeniden bağlanın ve eskimiş alias'ların kullanılmadığını teyit edin.
- Maksimumun üstünde bir alias ve eşlenmemiş bir alias deneyin, broker'ın tepkisini kaydedin.
- Alias'ları zorunlu hâle getirmeden önce kendi topic'leriniz için gerçek bayt tasarrufunu ölçün.
Topic alias'lar kısıtlı bağlantılarda ucuz bir kazançtır, diğer yerlerde ise gereksizdir. Müzakereyi ve yeniden bağlanma durumunu test edin; böylece bant genişliği kazandırırken bir cihazın susmasının sebebi olmazlar.
Sıkça sorulan sorular
Topic Alias Maximum'un varsayılan değeri nedir?
0. CONNECT veya CONNACK paketinde Topic Alias Maximum özelliği yoksa alıcı hiçbir alias kabul etmez. Her yön ayrı ayrı müzakere edilir: istemcinin değeri broker'ı, broker'ın değeri istemciyi sınırlar.
Topic alias'lar yeniden bağlanmadan sonra geçerli kalır mı?
Hayır. Alias eşlemeleri, oturum kalıcı olsa bile yalnızca tek bir ağ bağlantısı boyunca var olur. Her yeniden bağlanmadan sonra istemci, alias'ı kullanabilmek için önce tam topic adını yeniden göndermelidir.
Subscriber'lar alias'ı görür mü?
Yalnızca istemişlerse. Alias'lar her atlama için ayrıdır: broker publisher'ın alias'ını tam topic'e çözer ve bir subscriber'a ancak o subscriber kendi Topic Alias Maximum değerini bildirmişse alias kullanır. Çoğu subscriber doğrudan tam topic adını alır.
