Broker testleri

MQTT Gecikme Testi: Gidiş-Dönüş Süresini Doğru Ölçün

MQTT gecikme testi nasıl yapılır: gidiş-dönüş süresini tek saatle ölçün, NTP tuzaklarından kaçının, p50/p99 raporlayın ve broker bölgelerini karşılaştırın.

Güncellendi · 8 dk okuma

MQTT Gecikme Testi: Gidiş-Dönüş Süresini Doğru Ölçün

Bir MQTT gecikme testi, bir mesajın publisher'dan broker üzerinden subscriber'a ulaşmasının ne kadar sürdüğünü ölçer. Bunu güvenilir şekilde yapmanın yolu gidiş-dönüş süresini (RTT) tek bir saatle ölçmektir: aynı süreç bir mesaj publish eder, broker'dan geri alır ve monotonik bir zamanlayıcının iki okumasını birbirinden çıkarır. İki makinenin zaman damgalarını karşılaştıran her yöntem, ağ kadar saatler arasındaki farkı da ölçer.

Bu rehber size kopyalayıp kullanabileceğiniz bir gecikme betiği verir, ölçümlerin çoğunu bozan saat tuzaklarını açıklar, yüzdeliklerin nasıl raporlanacağını ve broker'ların ya da bölgelerin nasıl adil karşılaştırılacağını gösterir.

"MQTT gecikmesi" aslında ne demek

Gecikme adı verilen birkaç farklı değer vardır. Kod yazmadan önce hangisine ihtiyacınız olduğuna karar verin:

ÖlçümNereden → nereyeGereken saat
Loopback RTTİstemci publish eder → aynı istemci kendi mesajını alırTek saat (kolay, güvenilir)
Echo RTTİstemci A → broker → echo istemcisi B → broker → istemci AA üzerinde tek saat
Tek yönlü gecikmeA host'undaki publisher → B host'undaki subscriberİki senkronize saat
Bağlantı süresiTCP + TLS handshake + CONNECT → CONNACKTek saat
Ağ referansıBroker portuna TCP bağlantısıTek saat

Kapasite planlaması ve broker karşılaştırmaları için genellikle loopback RTT yeterlidir. Broker'ın her iki yöndeki yönlendirme işini ve iki ağ geçişini içerir; tek bir istemciden fazlasına ihtiyaç duymaz.

Saat tuzakları

Kötü gecikme değerlerinin çoğu broker'dan değil, saatten gelir:

  • Duvar saati sıçrar. Python'da time.time() veya JavaScript'te Date.now(), NTP'nin her an düzeltebileceği sistem saatini izler. Aralıklar için monotonik bir saat kullanın: Python'da time.perf_counter(), Node.js'te performance.now() veya process.hrtime.bigint().
  • İki makine hiçbir zaman tam olarak uyuşmaz. NTP olsa bile host'lar arasında bir milisaniye veya daha fazla fark olması yaygındır; iyi bir zaman kaynağı olmayan cihazlarda bu fark çok daha büyüktür. Tek yönlü ölçüm bu hatayı doğrudan devralır — negatif gecikmeler bile görebilirsiniz.
  • RTT / 2 bir tahmindir. Yükleme ve indirme yolları farklı olabilir (hücresel ağ, ADSL, tıkanmış uplink'ler). RTT'yi RTT olarak raporlayın; ikiye böldüğünüzde bunu açıkça belirtin.
  • Küçük cihazlarda zamanlayıcı çözünürlüğü. Bir mikrodenetleyicideki millis() 1 ms çözünürlüğe sahiptir; tek bir okumaya güvenmek yerine çok sayıda ölçümün ortalamasını alın.

Bir loopback RTT betiği

Bu betik (paho-mqtt 2.x) benzersiz bir topic'e abone olur, sıra numaralarını tek tek publish eder ve bir sonrakini göndermeden önce her mesajın geri gelmesini bekler. Bu kapalı döngü tasarımı, kuyruk etkileri olmadan boştaki bir yolun gecikmesini ölçer.

mqtt_rtt.py
import os, statistics, sys, threading, time, uuid
import paho.mqtt.client as mqtt

HOST = os.getenv("MQTT_HOST", "broker.connectmq.com")
PORT = int(os.getenv("MQTT_PORT", "1883"))
N = int(sys.argv[1]) if len(sys.argv) > 1 else 500
QOS = int(os.getenv("MQTT_QOS", "1"))
WARMUP = 20
TOPIC = f"testmqtt/latency/{uuid.uuid4().hex[:8]}"

ready, got = threading.Event(), threading.Event()
state = {"expected": -1, "t0": 0.0}
samples, lost = [], 0

def on_connect(client, userdata, flags, reason_code, properties):
    client.subscribe(TOPIC, qos=QOS)

def on_subscribe(client, userdata, mid, reason_code_list, properties):
    ready.set()

def on_message(client, userdata, msg):
    if int(msg.payload) == state["expected"]:
        rtt = (time.perf_counter() - state["t0"]) * 1000
        if state["expected"] >= WARMUP:
            samples.append(rtt)
        got.set()

client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2)
if os.getenv("MQTT_USER"):
    client.username_pw_set(os.getenv("MQTT_USER"), os.getenv("MQTT_PASS"))
client.on_connect, client.on_subscribe, client.on_message = on_connect, on_subscribe, on_message
client.connect(HOST, PORT, keepalive=30)
client.loop_start()
ready.wait(10)

for i in range(N + WARMUP):
    got.clear()
    state["expected"], state["t0"] = i, time.perf_counter()
    client.publish(TOPIC, str(i), qos=QOS)
    if not got.wait(5):
        lost += 1
    time.sleep(0.02)  # ölçümler arasında yolu boşta bırak

client.loop_stop()
q = statistics.quantiles(samples, n=100)
print(f"{HOST}:{PORT} QoS {QOS}  samples {len(samples)}  lost {lost}")
print(f"min {min(samples):.1f}  p50 {q[49]:.1f}  p95 {q[94]:.1f}  "
      f"p99 {q[98]:.1f}  max {max(samples):.1f} ms")
Çalıştırma
pip install "paho-mqtt>=2"
python mqtt_rtt.py 1000
MQTT_PORT=8883 python mqtt_rtt.py 1000   # TLS için client.tls_set() gerekir
MQTT_QOS=0 python mqtt_rtt.py 1000

İlk WARMUP mesaj atılır, çünkü soğuk önbelleklerin ve bağlantı ısınmasının bedelini öderler. TLS ile test etmeniz gerekiyorsa connect() öncesine client.tls_set() ekleyin ve 8883 portunu kullanın — handshake bir kez gerçekleştiği için mesaj başına RTT'yi değil, bağlantı süresini etkiler.

Betiğe geçmeden önce online MQTT istemcisinde hızlı bir kontrol yapmaya değer: testmqtt/latency/# topic'ine abone olun, bir mesaj publish edin ve geri geldiğini doğrulayın. Bu çalışıyorsa betik de çalışacaktır.

Ağı broker'dan ayırın

40 ms'lik bir RTT, bunun ne kadarının ağa ait olduğunu bilene kadar size hiçbir şey söylemez. Referans olarak broker portuna yalın TCP bağlantı süresini ölçün:

TCP referansı (ilk çağrı DNS'i içerir)
python3 -c "import socket,time
for _ in range(5):
    t=time.perf_counter(); socket.create_connection(('broker.connectmq.com',1883)).close()
    print(f'{(time.perf_counter()-t)*1000:.1f} ms')"

Bir TCP bağlantısı bir ağ gidiş-dönüşüne karşılık gelir. QoS 0 ile ölçtüğünüz MQTT loopback RTT bu referansa yakınsa broker neredeyse hiçbir şey eklemiyordur ve kalan gecikme mesafeden kaynaklanır. Çok daha yüksekse broker'a, istemciye veya yola bakın — yüksek gecikme sorun giderme yazısı yaygın nedenleri ele alır.

Işık fiberde milisaniyede yaklaşık 200 km yol alır; yani 2.000 km uzaktaki bir broker, daha hiçbir yazılım çalışmadan en az ~20 ms RTT'ye mal olur. Hiçbir broker ayarı fiziği yenemez; cihazlarınıza yakın bir bölge seçin.

Ortalama değil, yüzdelik raporlayın

Gecikme dağılımlarının uzun kuyrukları vardır. 12 ms'lik bir ortalama 300 ms'lik bir p99'u gizleyebilir ve cihazlarda timeout'a yol açan, dashboard'ları takılttıran şey p99'dur. Her zaman en az şunları raporlayın:

  • min — ağın belirlediği taban; çalıştırmalar arasında kararlı olmalıdır.
  • p50 — tipik deneyim.
  • p95 / p99 — kuyruk; yapılandırmalar arasında bu değerleri karşılaştırın.
  • max ve lost — tekil aykırı değerler ve timeout'lar gürültü değil, sinyaldir.

Raporladığınız yüzdelik için yeterli örnek toplayın. 100 örnekle p99 pratikte tek bir mesajdır; bir p99 değeri vermeden önce en az 1.000 örnek hedefleyin.

Gecikmeyi neler değiştirir

EtkenRTT'ye etkisi
QoS 0 → QoS 1Teslimat PUBACK'i beklemez, ancak yük altında broker tarafındaki kalıcılık ve inflight limitleri süre ekleyebilir
QoS 2Her atlamada dört paketlik el sıkışma; belirgin şekilde daha yavaş, bkz. QoS 0 vs 1 vs 2 benchmark
TLSBağlanırken handshake maliyeti; mesaj başına küçük şifreleme maliyeti
WebSocketsEk çerçeveleme ve çoğu zaman bir proxy atlaması
Payload boyutuBüyük payload'lar yavaş bağlantılarda daha uzun sürer
Broker yüküKuyruklar büyür, önce kuyruk gecikmesi (tail latency) artar
İstemci callback'leriYavaş bir on_message sonraki tüm mesajları geciktirir

Gecikmenin yük altında nasıl davrandığını görmek için, bir yük üreteci trafik gönderirken bu betiği çalıştırın — yöntem MQTT broker yük testi yazısında anlatılıyor. Boştaki RTT en iyi durumunuzdur; yük altındaki RTT ise planlamayı üzerine yaptığınız değerdir.

Broker'ları ve bölgeleri adil karşılaştırmak

Bir karşılaştırma, ancak broker dışındaki her şey aynı olduğunda adildir:

  1. Aynı makineden ve aynı ağdan ölçün; tercihen cihazlarınızın veya backend'inizin bulunduğu bölgedeki bir VM'den.
  2. Her hedef için aynı QoS, payload, port ve TLS ayarını kullanın.
  3. Önce tüm A'yı sonra tüm B'yi ölçmek yerine hedefleri dönüşümlü (A, B, A, B) çalıştırın; böylece geçici bir ağ aksaklığı her ikisini de etkiler.
  4. Her hedef için min, p50, p99 ve lost değerlerini TCP referansıyla birlikte tek bir tabloya kaydedin.
  5. Sonuca varmadan önce günün başka bir saatinde tekrarlayın.

Çok bölgeli kararlar için kullanıcılarınızın bulunduğu her bölgede küçük bir VM başlatın ve aynı betiği her broker uç noktasına karşı çalıştırın. (İstemci bölgesi, broker bölgesi) başına p50/p99 değerlerinden oluşan matris, elde edebileceğiniz en dürüst veridir.

Gecikme testi kontrol listesi

  • RTT için monotonik bir saat ve tek bir süreç kullanın.
  • Isınma mesajlarını atın; bağlantı süresini ayrıca ölçün.
  • 1.000'den fazla örnek toplayın ve min, p50, p95, p99, max ile lost değerlerini raporlayın.
  • Her MQTT sonucunun yanına bir TCP referansı kaydedin.
  • Boşta ve yük altında, cihazlarınızın gerçekten kullandığı ağdan test edin.
  • Betiği deponuzda tutun ve broker veya ağ değişikliklerinden sonra yeniden çalıştırın.

Gidiş-dönüşü tarayıcınızda kontrol edin

Güvenilir bir MQTT gecikme testi büyük ölçüde disiplin meselesidir: tek saat, yeterli örnek, ortalama yerine yüzdelikler ve sayının ne kadarının ağa ait olduğunu gösteren bir referans. Bunları doğru yaptığınızda 15 dakikalık bir betik, üretici benchmark'larının asla yanıtlamayacağı soruları yanıtlar.

Sıkça sorulan sorular

Senkronize saatler olmadan MQTT gecikmesini nasıl ölçerim?

Gidiş-dönüş süresini tek bir saatle ölçün: bir istemci kendisinin de abone olduğu bir topic'e (ya da mesajı geri yayınlayan bir echo istemcisine) publish eder ve aynı süreç gönderme ile alma anını monotonik bir saatle damgalar.

MQTT gidiş-dönüş süresi tek yönlü gecikmenin iki katı mıdır?

Yalnızca yaklaşık olarak. RTT / 2 her iki yönün simetrik olduğunu varsayar; hücresel veya asimetrik bağlantılarda bu çoğu zaman doğru değildir. Gerçek tek yönlü değerler için, ölçtüğünüz gecikmeden çok daha hassas senkronize edilmiş saatler gerekir.

İlk MQTT mesajım neden diğerlerinden çok daha yavaş?

İlk mesajlar DNS çözümlemesinin, TCP ve TLS ısınmasının, aboneliğin kurulmasının ve soğuk önbelleklerin bedelini öder. Ölçüm kaydetmeden önce bir ısınma grubunu atın ve bağlantı süresini ayrıca ölçün.