Okullar için Robotik ve Mühendislik · anaokulundan liseye

5. ünite / 10

MQTT güvenilirliği: QoS, kalıcı mesaj, son vasiyet

QoS 0/1/2 el sıkışmaları ve yinelenen teslim, kalıcı (retained) mesaj, son vasiyet ve doğum mesajı, keepalive ve kalıcı oturum.

Bu ünitenin sonunda

  • QoS 0, 1 ve 2'nin paket dizisini ve teslim garantisini açıklamak
  • Kayıplı bağlantıda yinelenen teslimin neden oluştuğunu ve nasıl zararsız hale getirileceğini göstermek
  • Kalıcı mesaj, son vasiyet ve doğum mesajıyla cihaz durumunu yayımlamak
  • Keepalive ve kalıcı oturum ayarlarını senaryoya göre seçmek

Ders notları

Wi-Fi paket kaybeder, cihaz uyur, broker yeniden başlar. MQTT, mesajın ne kadar "kesin" teslim edileceğini her yayında seçmene izin verir: QoS (hizmet kalitesi). Garanti arttıkça paket sayısı ve gecikme de artar.

Üç düzey

  • QoS 0, en çok bir kez: tek PUBLISH paketi, yanıt yok. Kaybolursa kaybolur. Sık gelen sıcaklık ölçümü için çoğu zaman yeterlidir: bir sonraki ölçüm zaten gelir.
  • QoS 1, en az bir kez: alıcı PUBACK ile onaylar. Onay gelmezse gönderen paketi DUP bayrağıyla yeniden yollar. PUBACK kaybolmuşsa alıcı mesajı iki kez alır.
  • QoS 2, tam bir kez: PUBLISH, PUBREC, PUBREL, PUBCOMP. Alıcı paket kimliğini saklar ve mesajı uygulamaya yalnız bir kez verir. En yavaşı ve en pahalısı.
kayıpsız bağlantıda mesaj başına paket: QoS 0 → 1, QoS 1 → 2, QoS 2 → 4

QoS, yayımlayan ile broker arasında ve broker ile abone arasında ayrı ayrı uygulanır. Aboneye giden QoS, yayın QoS'u ile abonelik QoS'unun küçüğüdür. Kütüphane sınırlarını da bil: PubSubClient yalnız QoS 0 yayımlar, QoS 0 ya da 1 abone olur; umqtt.simple QoS 0 ve 1 destekler.

Kalıcı mesaj

Retain bayrağıyla yayımlanan mesajı broker o konunun "son değeri" olarak saklar. Yeni abone olan pano, bir sonraki yayını beklemeden son değeri hemen alır. Konuya boş yükle kalıcı yayın yapmak saklanan mesajı siler. Komutları kalıcı yayımlamak tehlikelidir: cihaz her yeniden bağlandığında eski komutu tekrar alır.

Son vasiyet ve doğum mesajı

Son vasiyet (LWT), istemcinin CONNECT paketinde broker'a bıraktığı bir mesajdır. Bağlantı DISCONNECT gönderilmeden koparsa (güç gitti, Wi-Fi düştü, keepalive aşıldı) broker vasiyeti yayımlar. Yaygın desen: bağlanınca sera/01/durum konusuna kalıcı online, vasiyet olarak kalıcı offline. Böylece pano her cihazın canlı olup olmadığını her an bilir.

Keepalive ve oturum

İstemci keepalive süresince hiç paket göndermezse PINGREQ yollar. Broker, keepalive'ın 1,5 katı boyunca istemciden ses duymazsa bağlantıyı ölü sayar ve vasiyeti yayımlar. Kalıcı oturumda (clean session = false) broker, aynı kimlikli istemci çevrimdışıyken gelen QoS 1 ve 2 mesajları kuyrukta tutar ve geri bağlanınca teslim eder. Uyuyan cihazlar için kullanışlıdır ama broker belleği sınırlıdır.

Simülasyonlar

QoS 0, 1, 2: kayıplı bağlantıda teslim

Paket kaybı oranını artır ve aynı 20 mesajı üç QoS düzeyiyle gönder. Kaybolan, yinelenen ve teslim edilen mesajları, toplam paket sayısını ve her mesajın el sıkışma dizisini gör.

QoSTeslimKayıpYinelenenPaket
0 at most once16/204020
1 at least once20/200459
2 exactly once20/2000106
QoS başına hattaki paketQoS 0QoS 1QoS 21060
  1. #1gönderen → broker PUBLISH kayboldu
  2. #1gönderen → broker PUBLISH DUP kayboldu
  3. #1gönderen → broker PUBLISH DUP
  4. #1broker → gönderen PUBACK
  5. #2gönderen → broker PUBLISH
  6. #2broker → gönderen PUBACK
  7. #3gönderen → broker PUBLISH
  8. #3broker → gönderen PUBACK
  9. #4gönderen → broker PUBLISH
  10. #4broker → gönderen PUBACK
  11. #5gönderen → broker PUBLISH
  12. #5broker → gönderen PUBACK kayboldu
  13. #5gönderen → broker PUBLISH DUP
  14. #5broker → gönderen PUBACK
  15. #6gönderen → broker PUBLISH kayboldu
  16. #6gönderen → broker PUBLISH DUP
  17. #6broker → gönderen PUBACK
QoS 1 PUBACK gelene kadar yeniden yollar: PUBACK kaybolursa alıcı aynı mesajı iki kez alır. QoS 2 paket kimliğini saklar, uygulamaya bir kez verir.

Tarayıcıda MQTT broker'ı

Üç simüle cihaz ve bir pano aynı broker'a bağlı. Joker karakterli (+ ve #) abonelikler kur, mesaj yayımla, kalıcı (retained) mesajı ve bir cihazın kablosunu çekince yayımlanan son vasiyeti (LWT) izle.

sera-01
sera/01/led/set Q1
sera-02
sera/02/fan/set Q1
sera-03
abonelik yok
pano
abonelik yok
  1. –Bir şey yayımla ya da cihazlara telemetri gönderttir.
Broker'da kalıcı: sera/01/durum = online · sera/02/durum = online · sera/03/durum = online
Süzgeç sınaması: "sera/#" × "sera/02/nem" → EŞLEŞİR

Kod

Arduino C++: son vasiyet, doğum mesajı ve keepalive
#include <WiFi.h>
#include <PubSubClient.h>
#include "secrets.h"                     // MQTT_HOST, MQTT_USER, MQTT_PASS

WiFiClient net;
PubSubClient mqtt(net);
const char* STATUS = "sera/01/durum";

bool mqttConnect() {
  mqtt.setKeepAlive(30);                 // broker 45 s sessizlikten sonra ölü sayar
  // id, kullanıcı, parola, vasiyet konusu, QoS, retain, vasiyet, cleanSession
  bool ok = mqtt.connect("sera-01", MQTT_USER, MQTT_PASS, STATUS, 1, true, "offline", false);
  if (!ok) return false;
  mqtt.publish(STATUS, "online", true);  // doğum mesajı: kalıcı, vasiyetin tersi
  mqtt.subscribe("sera/01/+/set", 1);    // PubSubClient: abonelik QoS 0/1, yayın yalnız QoS 0
  return true;
}

void goToSleep() {
  mqtt.publish(STATUS, "sleeping", true);
  mqtt.disconnect();                     // DISCONNECT gönderildi: vasiyet yayımlanmaz
}

void setup() {
  WiFi.begin(WIFI_SSID, WIFI_PASS);
  while (WiFi.status() != WL_CONNECTED) delay(250);
  mqtt.setServer(MQTT_HOST, 1883);
  while (!mqttConnect()) delay(2000);
}

void loop() { mqtt.loop(); }
MicroPython: QoS 1, kalıcı oturum ve vasiyet
from umqtt.simple import MQTTClient
from secrets import MQTT_HOST, MQTT_USER, MQTT_PASS

STATUS = b'sera/01/durum'
c = MQTTClient('sera-01', MQTT_HOST, user=MQTT_USER, password=MQTT_PASS, keepalive=30)
c.set_last_will(STATUS, b'offline', retain=True, qos=1)   # CONNECT içinde gider
c.set_callback(lambda t, m: print(t, m))
c.connect(clean_session=False)           # kalıcı oturum: çevrimdışıyken QoS 1 mesajlar bekletilir
c.publish(STATUS, b'online', retain=True, qos=1)          # doğum mesajı
c.subscribe(b'sera/01/+/set', qos=1)

# QoS 1 "en az bir kez" demektir: komut iki kez gelebilir.
# Bu yüzden komutlar mutlak değer taşır (1/0), "çevir" değil.
while True:
    c.wait_msg()

Kendin dene

QoS simülasyonunda paket kaybını %0'dan %30'a çıkar ve aynı 20 mesajı QoS 0, 1 ve 2 ile gönder. Her düzeyde kaybolan, yinelenen ve teslim edilen mesaj sayısını ve toplam paket sayısını bir tabloya yaz. QoS 1'de yinelenen bir mesajın izini bul: hangi paket kaybolmuştu? Sonra broker simülasyonunda sera/01/durum konusuna kalıcı "online" yayımla, panoyu yeniden abone et ve mesajın hemen geldiğini gör; cihazın kablosunu çek ve vasiyetin geldiğini izle. Wokwi'de vasiyetli kodu çalıştırıp simülasyonu durdurarak aynı şeyi gerçek broker'da dene.

Sık yapılan hatalar

  • QoS 1'in "tam bir kez" olduğunu sanmak: PUBACK kaybolunca aynı mesaj iki kez gelir, komutlar idempotent olmalı.
  • Komutları retain bayrağıyla yayımlamak: cihaz her yeniden bağlandığında eski komutu yeniden uygular.
  • Son vasiyeti kalıcı yapmamak: vasiyetten sonra abone olan pano cihazı hâlâ çevrimiçi sanar.
  • Uykudan uyanan cihazda her seferinde farklı istemci kimliği kullanmak: kalıcı oturum ve kuyruk her seferinde kaybolur.
  • Keepalive'ı derin uyku aralığından kısa tutmak: broker her uykuda vasiyeti yayımlar ve pano sürekli "offline" gösterir.

Yazılım mühendisliği bağlantısı

Dağıtık sistemlerde "tam bir kez" pahalıdır; pratikte en az bir kez + idempotent alıcı kullanılır.

  • Her komuta bir kimlik ver ve alıcı son kimlikleri hatırlasın: yinelenen teslim ikinci kez uygulanmaz. 7. ünitenin eyleyici simülasyonu bunu ölçer.
  • Durum konusu (online / offline / sleeping) bir sağlık sinyalidir: izleme ve uyarı bunun üstüne kurulur.
  • Simülasyondaki simulateQos tohumlu bir rastgele sayı üreteci kullanır: aynı tohum aynı kayıpları verir, hata yeniden üretilebilir. Ağ testlerinde de belirlenimci tohum kullan.

Kendini sına

  1. QoS 1 ile gönderilen bir mesajın PUBACK paketi kayboldu. Ne olur?

  2. Cihaz QoS 2 ile yayımlıyor, pano aynı konuya QoS 1 ile abone. Panoya hangi QoS ile gelir?

  3. Keepalive 20 s. İstemci tamamen sustu. Broker yaklaşık kaç saniye sonra bağlantıyı ölü sayar?

  4. Bir konudaki kalıcı mesajı nasıl silersin?

Bu üniteden sonra bitirme projesinde

  • Konu ağacı ve MQTT sözleşmesi: Konu ağacını, yük biçimlerini, QoS ve retain kararlarını ve son vasiyeti bir sayfalık sözleşme olarak yaz; broker simülasyonunda dene.

Parçalar ve ilgili sayfalar

Esc
  • PanelAna sayfaSayfa
  • ModüllerTüm modüllerSayfa
  • ParçalarParça ansiklopedisiSayfa
  • Mühendislik yoluBüyükler için robotik: 128 parça, 7 seviyeSayfa
  • Robotik dersi (ESOF 323)Üniversite robotik dersi, 14 haftaSayfa
  • Drone dersiBüyükler için: parça, simülasyon, yazılım; 10 üniteSayfa
  • Blok atölyesiSerbest blok programlamaAraç
  • Devre laboratuvarıSanal Arduino ve devreAraç
  • Robot arenasıSanal robot sürüşüAraç
  • OyunlarBloklarla 8 öğretici oyunAraç
  • Mikro Kart atölyesiSanal LED kartı bloklarla programlaAraç
  • Robot atölyesiMikro Kart'ı robota tak, bloklarla görev yapAraç