MQTT yük testi: binlerce cihaz, bağlantılar, QoS ve mesaj gecikmesi
Bir MQTT broker'ını zorlayan şey çoğu zaman mesaj hızı değil, bağlantı sayısıdır: her biri birkaç saniyede bir küçük bir mesaj gönderen on binlerce cihaz, broker'ın bellekte tuttuğu on binlerce oturum, abonelik ve keep-alive demektir. MQTT yük testi bu tabloyu kurar ve üç soruya cevap arar: broker kaç eşzamanlı cihazı kabul ediyor, bu yükte bir mesajın onayı ne kadar sürüyor, ve bir kesintiden sonra bütün cihazlar aynı anda geri bağlandığında ne oluyor.
Neyi ölçüyoruz?
- Eşzamanlı bağlantı: broker'a aynı anda bağlı kalan client sayısı. Her bağlantı bellek, dosya tanımlayıcısı ve keep-alive trafiği tüketir; sınır çoğu zaman CPU'dan önce burada gelir.
- Bağlanma hızı: saniyede kaç yeni bağlantının kabul edildiği. TLS el sıkışması ve kimlik doğrulama pahalıdır; bir ağ kesintisinden sonra binlerce cihazın aynı anda geri bağlanması (bağlantı fırtınası) sabit yükte görünmeyen bir darboğazdır.
- Publish gecikmesi: QoS'a göre değişir. QoS 0'da client mesajı yazıp geçer, broker'dan cevap beklemez; QoS 1'de broker'ın PUBACK'ine, QoS 2'de dört adımlı el sıkışmanın sonundaki PUBCOMP'a kadar geçen süre ölçülür. Testte cihazların gerçekte kullandığı QoS'u kullanın.
- Dağıtım (fan-out): bir mesajın eşleşen her aboneye kopyalanması.
devices/+/telemetrygibi geniş bir filtreye abone olan birkaç servis, broker'ın gönderdiği mesaj sayısını katlar. - Hatalar: reddedilen bağlantılar, kimlik doğrulama hataları, zaman aşımları ve broker'ın kapattığı oturumlar.
Yük modelini kurmak
MQTT'de doğal model "cihaz başına bir sanal kullanıcı"dır: her VU kendi bağlantısını açar, belli aralıklarla mesaj gönderir ve bağlı kalır. Hedef mesaj hızı cihaz sayısı ve gönderim aralığından çıkar: 500 cihaz 5 saniyede bir gönderiyorsa saniyede 100 mesaj. Aralığı sabit yazmak yerine küçük bir rastgelelik verin (4–6 sn gibi); aksi halde bütün cihazlar aynı anda gönderir ve gerçekte olmayan dalgalar oluşur.
Ramp-up süresi bağlanma hızını belirler. 2 dakikada 500 cihaza çıkmak saniyede yaklaşık 4 bağlantıdır; aynı sayıya 10 saniyede çıkmak bir bağlantı fırtınası testidir. İkisini ayrı testler olarak koşturun: biri broker'ın sabit yükteki davranışını, diğeri kesinti sonrası toparlanmasını gösterir (spike testi). Broker'ın kaç cihazda kırıldığını bulmak için cihaz sayısını basamaklarla artırın (kırılma noktası testi).
Sık yapılan hatalar
- Aynı client id. MQTT'de aynı client id ile bağlanan ikinci client birincinin oturumunu düşürür. Her cihaza ayrı bir id verin; aynı broker'a aynı anda iki test koşturuyorsanız id'lere farklı bir önek koyun.
- Az sayıda bağlantıdan çok mesaj. 10 bağlantıdan saniyede 10.000 mesaj göndermek broker'ı on bin cihazdan çok farklı zorlar. Cihaz sayısını gerçeğe yakın tutun, mesaj hızını aralıkla ayarlayın.
- Retained mesajlar ve kalıcı oturumlar. Testin
retainile gönderdiği mesajlar ve clean session kapalı oturumlar test bittikten sonra broker'da kalır. Test için ayrı bir topic ağacı kullanın ve temizliği planlayın. - Yük üreticisinin sınırı. Her bağlantı yük üreten makinede de bir soket demektir. Binlerce cihaz için dosya tanımlayıcı sınırını yükseltin ve yükü birden fazla makineye dağıtın; yoksa ölçtüğünüz broker değil yük üreticisi olur.
- Ortalama gecikme. Broker'ın kuyruğu uzundur; p95 ve p99'a bakın (p95 ve p99 rehberi).
Spitfire ile
Önce Bağlantılar'da bir MQTT bağlantısı ekleyin: broker adresleri (tcp://host:1883, ssl://host:8883 ya da ws://host:8083/mqtt), client id, kullanıcı adı ve parola, keep-alive (varsayılan 30 sn), clean session (varsayılan açık) ve gerekiyorsa TLS (CA, client sertifikası). Parola şifreli saklanır, testte yalnız bağlantının adı geçer; adresin içine parola yazılırsa kayıt reddedilir. Client id bir şablondur, varsayılanı spitfire-{{__VU}}: VU numarası bir koşuda bütün senaryolar ve runner'lar arasında tekildir.
Her VU kendi MQTT client'ını tutar, tıpkı bir cihaz gibi. Client ilk adımda bağlanır ve VU durana kadar bağlı kalır; bağlanma süresi adımın süresine katılmaz, ama bağlanamazsa adım başarısız sayılır. Bağlantı koparsa VU bir sonraki adımda yeniden bağlanır ve aboneliklerini yeniler. MQTT adımının üç işlemi vardır:
- publish: topic'e payload'u QoS 0, 1 ya da 2 ile, isterseniz
retainile gönderir. Adımın süresi QoS 0'da mesajın yazılması, QoS 1'de PUBACK'e, QoS 2'de PUBCOMP'a kadar geçen süredir. Topic ve payload'da{{__VU}},{{$randInt 18 30}},{{$timestamp}}ya da CSV veri dosyasından değişkenler kullanılabilir. - subscribe: VU topic filtresine (
+ve#yalnız burada geçerlidir) bir kez abone olur ve her adımda gelen bir mesajı alır. Adımın süresi sıradaki mesajı bekleme süresidir, gönderimden alıma geçen süre değildir; bekleme süresi (varsayılan 10 sn) dolarsa adım zaman aşımıyla başarısız olur. Gelen mesajlar VU ve filtre başına 256 mesajlık bir tamponda bekler, dolarsa en eskisi düşer. Payload kontrollere ve değişken çıkarmaya gider (JSON ise JSONPath ile);topic,qos,retained,duplicatevemessage-idheader olarak okunabilir. - request: istek-cevap düzeni için: VU
responseTopic'e abone olur, mesajı gönderir ve o topic'e gelen ilk mesajı cevap sayar. Süre gidiş-dönüştür. Bir korelasyon kimliği yoktur; cevap veren servisin hangi topic'e cevap vereceğini bilmesi ve her VU'ya ayrı bir cevap topic'i (replies/{{__VU}}gibi) verilmesi gerekir.
500 cihazın 2 dakikada bağlandığı, 10 dakika boyunca her birinin 4–6 saniyede bir QoS 1 ile telemetri gönderdiği (saniyede yaklaşık 100 mesaj) ve iki dinleyicinin bütün cihazların topic'ini izlediği bir test. Gönderim onayının p95'i 100 ms'nin, hata oranı %0,1'in altında kalmalı. Test spitfire validate ile doğrulandı.
{
"name": "MQTT: cihaz telemetrisi",
"scenarios": [
{ "name": "cihazlar",
"executor": { "type": "ramping-vus", "startVUs": 0,
"stages": [ { "duration": "2m", "target": 500 }, { "duration": "10m", "target": 500 },
{ "duration": "30s", "target": 0 } ] },
"steps": [ { "id": "telemetry", "name": "Telemetri gönder", "protocol": "mqtt", "connection": "broker",
"mqtt": { "action": "publish", "topic": "devices/{{__VU}}/telemetry", "qos": 1,
"payload": "{\"device\":{{__VU}},\"temp\":{{$randInt 18 30}},\"ts\":{{$timestamp}}}" },
"thinkTime": { "min": "4s", "max": "6s" } } ] },
{ "name": "dinleyici",
"executor": { "type": "constant-vus", "vus": 2, "duration": "12m30s" },
"steps": [ { "id": "listen", "name": "Telemetriyi dinle", "protocol": "mqtt", "connection": "broker",
"mqtt": { "action": "subscribe", "topic": "devices/+/telemetry", "qos": 1, "wait": "5s" },
"checks": [ { "type": "jsonPath", "path": "$.temp", "op": "exists" } ] } ] }
],
"thresholds": [
{ "metric": "req_duration", "filter": { "step": "telemetry" }, "expr": "p(95)<100" },
{ "metric": "req_failed", "expr": "rate<0.001" }
]
}Koşu sırasında adım bazında mesaj hızı, p95, p99, gönderilen ve alınan veri ve hata türleri (kimlik doğrulama, bağlantı reddi, zaman aşımı) canlı izlenir; dinleyicinin kontrolleri gelen mesajların biçimini doğrular. Binlerce cihazı tek makineden açmak yerine yükü birden fazla runner'a dağıtın: Spitfire VU'ları runner'lar arasında böler, toplam cihaz sayısı tanımladığınız gibi kalır. Mesaj hızını sabitleyip cihaz başına yükü görmek isterseniz cihaz senaryosunu bir varış hızı (arrival rate) yürütücüsüyle de kurabilirsiniz; o zaman bir VU bir cihaz değil, bir gönderici havuzu olur.
Spitfire'ın MQTT client'ı MQTT 3.1.1 konuşur; MQTT 5'e özgü özellikler (user property'ler, response topic ve correlation data özellikleri) testte kullanılamaz.
Spitfire tek komutla Docker'a ya da Kubernetes'e kurulur; ücretsiz sürümde bütün test özellikleri ve protokoller açıktır.