MQTT yayınla/abone ol (publish/subscribe) modeli, bir sıcaklık sensörünün, bir dashboard'un ve bir faturalandırma servisinin birbirlerinin adresini hiç bilmeden veri paylaşabilmesinin nedenidir. Bu yazıda pub/sub'ın istek/yanıt modelinden nasıl ayrıldığını, üç ayrıştırma türünün pratikte ne anlama geldiğini öğrenecek ve her birini ücretsiz bir broker'a bağlı iki terminal penceresiyle kendiniz kanıtlayacaksınız.
İstek/Yanıt ve Yayınla/Abone Ol Karşılaştırması
Çoğu geliştirici ağ iletişimini HTTP üzerinden öğrenir. Bir client bilinen bir sunucuya bağlantı açar, bir soru sorar ve yanıtı bekler. Bu desen basittir ama iki tarafı sıkı sıkıya birbirine bağlar: Client sunucunun adresini bilmelidir, sunucu tam o anda ayakta olmalıdır ve client bir yanıt gelene kadar bekler (ya da sorgulama yapar).
Yayınla/abone ol, araya bir aracı koyarak bu bağı kırar. MQTT'de bu aracı broker'dır. Client'lar asla birbiriyle konuşmaz; yalnızca broker ile konuşur:
- Bir yayıncı,
plant1/line2/press/temperaturegibi bir topic ile mesaj gönderir. - Bir abone, broker'a hangi topic'lerle ilgilendiğini söyler; isteğe bağlı olarak
plant1/+/press/#gibi joker karakterlerle. - Broker, gelen her mesajı tüm aktif aboneliklerle eşleştirir ve her eşleşmeye bir kopya iletir.
Ortadaki sunucunun rolüne yeniyseniz, bir MQTT broker'ın ne yaptığı rehberimiz yönlendirme, oturumlar ve retained durumu daha ayrıntılı ele alır.
| Özellik | İstek/Yanıt (HTTP) | MQTT Yayınla/Abone Ol |
|---|---|---|
| Kim kimi bilir | Client sunucu adresini bilir | Client'lar yalnızca broker'ı bilir |
| Yön | Client çeker | Broker geldiği anda iter |
| Çok sayıda okuyucuya dağıtım | Okuyucu başına bir istek | Bir yayın, çok sayıda teslimat |
| Bağlantı | Çoğunlukla kısa ömürlü | Uzun ömürlü tek bir TCP bağlantısı |
| Çevrimdışı alıcılar | İstek başarısız olur | Kalıcı oturumlar kuyruğa alabilir |
MQTT Yayınla/Abone Ol Modelinde Üç Ayrıştırma Türü
Pub/sub literatürü genellikle ayrıştırmanın (decoupling) üç boyutunu tanımlar. Her biri farklı bir IoT sorununu çözdüğü için bunları ayrı ayrı ele almaya değer.
Uzay ayrıştırması
Yayıncılar ve aboneler birbirlerinin IP adresini, ana bilgisayar adını, hatta kaç tane olduklarını bilmez. Bir sensör site/tank3/level topic'ine yayın yapar; bunu sıfır, bir ya da elli uygulamanın alması sensör için görünmezdir. Sahada zaten bulunan binlerce cihazın yazılımına dokunmadan gelecek yıl yeni bir analitik servisi eklemenizi sağlayan budur.
Zaman ayrıştırması
Yayıncı ve abonenin aynı anda çevrimiçi olması gerekmez. MQTT bunun için iki mekanizma sunar:
- Retained message'lar. Broker topic başına son retained message'ı saklar ve herhangi bir yeni aboneye hemen verir. 09:00'da başlayan bir dashboard, 06:00'da yayınlanan vana durumunu yine de görür.
- Kalıcı oturumlar. Clean start bayrağı false olarak (ve MQTT 5'te bir oturum süresi aralığıyla) bağlanan bir abone, bağlantısı kesikken aboneliklerini korur ve broker onun için QoS 1 ve QoS 2 mesajlarını kuyruğa alır.
Zaman ayrıştırması sınırsız değildir. Kuyruklar broker'ın oturum süresi ve kotalarıyla sınırlıdır; bu yüzden onu uzun süreli depolama değil, kısa kesintiler için bir tampon olarak görün.
Senkronizasyon ayrıştırması
Hiçbir taraf diğerini bloklamaz. Yayıncı mesajını client kütüphanesine verir ve işine devam eder; kütüphane onayları arka planda halleder. Aboneler mesajları bir döngüde beklemek yerine callback'ler aracılığıyla alır. Bir mikrodenetleyicide bu, ağ G/Ç'si eşzamansız olarak gerçekleşirken ana döngünün sensörleri okumaya devam etmesi anlamına gelir.
Topic'ler: Yayıncılar ile Aboneler Arasındaki Sözleşme
Taraflar arasında doğrudan bir bağ olmadığı için topic dizesi paylaştıkları tek sözleşmedir. Bu nedenle iyi topic tasarımı MQTT'de, REST'teki URL tasarımından daha önemlidir:
- Genelden özele gidin:
company/site/area/line/device/measurement. - Joker karakterlerin işe yarar kalması için seviyeleri kararlı ve anlamlı tutun.
- Topic adlarına asla gizli bilgi veya kişisel olarak tanımlanabilir veri koymayın.
- Topic'leri
$ile başlatmayın; bu önek$SYSgibi broker topic'leri için ayrılmıştır. - Komutları telemetriden ayırın; örneğin
.../cmd/...ile.../telemetry/....
+ joker karakteri tam olarak bir seviyeyle, # ise sondaki herhangi sayıda seviyeyle eşleşir. Bir historian acme/# topic'ine abone olabilirken bir hat sorumlusunun yalnızca acme/izmir/assembly/line4/+/status topic'ine ihtiyacı vardır.
Deneyin: broker.connectmq.com Üzerinde İki Client
Modeli kavratmanın en hızlı yolu onu gerçekleşirken izlemektir. Mosquitto komut satırı client'larını (mosquitto_pub ve mosquitto_sub) kurun, ardından iki terminal açın. Topic'lerinizin ücretsiz genel MQTT broker üzerindeki başka biriyle çakışmaması için rastgele bir sonek seçin. Genel alanın herkes tarafından okunabildiğini unutmayın; hassas hiçbir şey yayınlamayın.
Adım 1: Bir abone başlatın
# Terminal A: joker karakterle abone olun
mosquitto_sub -h broker.connectmq.com -p 1883 -i sub-demo-7f3a \
-t "connectmq/demo/7f3a/#" -v
Adım 2: Başka bir client'tan yayın yapın
# Terminal B: iki okuma yayınlayın
mosquitto_pub -h broker.connectmq.com -p 1883 -i pub-demo-7f3a \
-t "connectmq/demo/7f3a/room1/temperature" -m "21.4"
mosquitto_pub -h broker.connectmq.com -p 1883 -i pub-demo-7f3a \
-t "connectmq/demo/7f3a/room2/temperature" -m "19.8"
Terminal A her iki mesajı da topic'leriyle birlikte yazdırır. Yayıncı abonenin nerede olduğunu hiç öğrenmedi: İşte uzay ayrıştırması budur.
Adım 3: Retained message ile zaman ayrıştırmasını kanıtlayın
Aboneyi Ctrl+C ile durdurun. Şimdi kimse dinlemiyorken retained bir değer yayınlayın:
mosquitto_pub -h broker.connectmq.com -p 1883 -i pub-demo-7f3a \
-t "connectmq/demo/7f3a/door/state" -m "open" -r
Aboneyi yeniden başlatın. Mesaj o çevrimdışıyken gönderilmiş olmasına rağmen hemen connectmq/demo/7f3a/door/state open alır. Temizlemek için -r -n ile boş bir retained payload yayınlayın.
Adım 4: Fan-out
Başka bir aboneyle üçüncü bir terminal açın (sub2-demo-7f3a gibi farklı bir client ID kullanın). Bir kez yayınlayın; her iki abone de mesajı alır. Bir yayın, çok sayıda teslimat; üstelik yayıncının kodu değişmedi.
Python'da Programatik Bir Abone
Aynı modelin kodda gösterimi senkronizasyon ayrıştırmasını ortaya koyar: Programınız başka işler yapmakta serbestken veri geldiğinde callback tetiklenir.
import time
import paho.mqtt.client as mqtt
BROKER = "broker.connectmq.com"
PREFIX = "connectmq/demo/7f3a"
def on_connect(client, userdata, flags, reason_code, properties):
print("Connected:", reason_code)
client.subscribe(f"{PREFIX}/#", qos=1)
def on_message(client, userdata, msg):
print(f"{msg.topic} -> {msg.payload.decode()} (retained={msg.retain})")
client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2, client_id="py-sub-7f3a")
client.on_connect = on_connect
client.on_message = on_message
client.connect(BROKER, 1883, keepalive=60)
client.loop_start()
try:
while True:
# Uygulamanız çalışmaya devam eder; mesajlar arka planda gelir.
time.sleep(5)
client.publish(f"{PREFIX}/heartbeat", str(int(time.time())), qos=1)
except KeyboardInterrupt:
client.loop_stop()
client.disconnect()
Pub/Sub IoT'ye Neden Bu Kadar Uygun
- Güvenilmez bağlantılar. Hücresel veya Wi-Fi üzerindeki cihazlar düzenli olarak kopar. Kalıcı oturumlar ve QoS 1/2, özel yeniden deneme mantığı olmadan bu cihazların eksikleri tamamlamasını sağlar. MQTT QoS seviyeleri rehberi teslimat garantilerini ayrıntılı olarak açıklar.
- Veri noktası başına çok sayıda tüketici. Aynı titreşim okuması bir dashboard'u, bir uyarı betiğini ve bir historian'ı besleyebilir. Her biri bağımsız olarak abone olur.
- Yalnızca giden bağlantılar. Cihazlar broker'a bağlantı açar; hiçbir şeyin cihaza dışarıdan bağlanması gerekmez. Bu, her sensörde bir HTTP sunucusu çalıştırmaktan NAT ve güvenlik duvarları açısından çok daha dostanedir.
- Küçük paketler. Sabit başlık iki bayt olabilir; bu da radyo süresini ve veri paketlerini düşük tutar.
Yaygın Tuzaklar ve Bunlardan Kaçınma
Abonenin olmaması bir hata değildir. Abonesi olmayan bir topic'e yayın yaparsanız broker mesajı kabul eder ve atar (retained değilse). Geliştiriciler bazen kaybolan bir mesajın ağ sorunu olduğunu varsayar; oysa gerçekte topic'te bir yazım hatası vardır. Hata ayıklarken kendi önekinizin altında # aboneliği yapın.
Yinelenen client ID'ler. Aynı kimliğe sahip iki client birbirini bir döngü içinde düşürür. Her bağlantının benzersiz bir kimliğe ihtiyacı vardır.
Üretimde fazla geniş joker karakterler. # topic'ine abone olan bir servis, kaldıramayacağı trafik de dahil her şeyi alır. Abonelikleri ihtiyacınız olan seviyelerle sınırlayın.
Yanıt beklemek. Pub/sub'ın yerleşik bir yanıt mekanizması yoktur. İstek/yanıt semantiğine ihtiyacınız varsa MQTT 5 bir response topic ve correlation data ekler; bunu MQTT 5 özellikleri genel bakışımızda ele alıyoruz.
Topic'ler arası sıralama. MQTT, tek bir yayıncıdan gelen mesajlar için belirli bir QoS'ta topic başına sırayı korur, ancak farklı topic'ler arasında korumaz. Sıralama önemliyse payload'lara bir zaman damgası veya sıra numarası koyun.
Demodan Üretime
Genel broker deneyler için mükemmeldir, ancak paylaşımlıdır ve herkes tarafından okunabilir. Gerçek cihazlar için kimlik doğrulama, 8883 portunda TLS ve size ait izole bir isim alanı istersiniz. ConnectMQ gibi tam yönetilen bir MQTT hizmeti tam olarak bunu sunar: Portalda bir broker oluşturun, oluşturulan kullanıcı adını, parolayı ve client ID'yi kopyalayın ve aynı kodu TLS ile 8883 portuna yönlendirin. ConnectMQ MQTT 3.1.1 ve 5.0'ı destekler; böylece retained message'lar, oturum süresi ve paylaşımlı abonelikler bu yazıda anlatıldığı gibi çalışır. Protokolün daha geniş bir anlatımı için eksiksiz MQTT eğitimimizle başlayın ya da paket seviyesinde MQTT'nin nasıl çalıştığını okuyun.
ConnectMQ ile Başlayın
Pub/sub prototipinizi özel bir broker'a taşımaya hazır mısınız? app.connectmq.com adresinden kaydolun ve birkaç dakika içinde, kredi kartı gerektirmeden ücretsiz bir Serverless broker oluşturun. ConnectMQ'nun tarayıcı içi MQTT client'ı ve canlı topic gezgini, hiçbir şey kurmadan yayınların ve aboneliklerin akışını izlemenizi sağlar.
Sık Sorulan Sorular
MQTT yayınla/abone ol bir mesaj kuyruğuyla aynı şey mi?
Tam olarak değil. MQTT'de eşleşen her abone her mesajın kendi kopyasını alırken klasik bir kuyruk her mesajı tek bir tüketiciye teslim eder. MQTT 5 paylaşımlı abonelikleri, ihtiyaç duyduğunuzda kuyruk benzeri yük dengeleme ekler.
Bir client aynı anda hem yayın yapıp hem abone olabilir mi?
Evet. Tek bir MQTT bağlantısı bazı topic'lere yayın yapıp diğerlerine abone olabilir; çoğu cihaz telemetri gönderirken komutları bu şekilde alır.
Kimse abone değilken mesajlara ne olur?
Broker onları atar; mesaj retained değilse. Retained ise topic başına son retained değer gelecekteki aboneler için saklanır.
Yayıncılar bir mesajı kaç abonenin aldığını bilir mi?
Hayır. MQTT'deki onaylar yalnızca client ile broker arasındadır; yayıncıları ve aboneleri birbirinden ayrık tutan da tam olarak budur.



