Broker testleri

Gatling ile MQTT Yük Testi: Kurulum, Senaryo ve Raporlar

Gatling ile MQTT broker yük testi: MQTT eklentisini ekleyin, connect, subscribe ve publish check'leri içeren bir Java simülasyonu yazın ve HTML raporunu okuyun.

Güncellendi · 9 dk okuma

Gatling ile MQTT Yük Testi: Kurulum, Senaryo ve Raporlar

Gatling, MQTT eklentisiyle bir MQTT broker'ına yük testi yapabilir: bir cihazın davranışını Java, Kotlin veya Scala ile bir senaryo olarak tanımlarsınız — connect, subscribe, publish, eşleşen mesajı bekle — Gatling de sanal kullanıcıları enjekte eder ve yanıt süresi percentile'ları ile throughput içeren HTML raporunu üretir. Gatling'i zaten HTTP için kullanan ve MQTT için de aynı "simulation as code" akışını isteyen ekipler için uygundur.

Başlamadan önce lisansı bilin: MQTT bileşeni Gatling Enterprise Component License ile dağıtılır. Community Edition ile yerelde 5 sanal kullanıcı ve 5 dakikalık testlerle sınırlıdır; bu, bir simülasyonu geliştirmek ve doğrulamak için yeterlidir. Gerçek ölçekte çalıştırmak için Gatling Enterprise gerekir. Bu size uymuyorsa xk6-mqtt ile k6, JMeter veya emqtt-bench açık kaynak alternatiflerdir.

Proje kurulumu

Başlamanın en kolay yolu Gatling'in Maven veya Gradle demo projelerinden birini kullanmaktır. Ardından MQTT eklentisini standart Gatling bağımlılıklarının yanına ekleyin:

pom.xml (kesit)
<dependency>
  <groupId>io.gatling</groupId>
  <artifactId>gatling-mqtt-java</artifactId>
  <version>3.16.0</version>
  <scope>test</scope>
</dependency>

Diğer Gatling artifact'lerinizle aynı sürümü kullanın. Scala projeleri gatling-mqtt-java yerine gatling-mqtt kullanır; Gradle'da tanım gatlingImplementation("io.gatling:gatling-mqtt-java:3.16.0") şeklindedir.

MQTT DSL'i varsayılan olarak import edilmez, bu yüzden her simülasyonda şunlar gerekir:

Import'lar
import io.gatling.javaapi.mqtt.*;
import static io.gatling.javaapi.mqtt.MqttDsl.*;

Simülasyonu yazmadan önce broker, port ve kimlik bilgilerini tek bir client ile online MQTT client üzerinden doğrulayın. Böylece sonraki hataların yapılandırmadan değil yükten kaynaklandığını bilirsiniz. Paylaşımlı broker.connectmq.com endpoint'ini yalnızca senaryoyu doğrulamak için kullanın; gerçek yük için .broker(...) ayarını ve kimlik bilgilerini kendi özel broker instance'ınıza yönlendirin.

Protokol: broker, kimlik bilgileri, QoS

Protocol builder, tüm sanal kullanıcıların paylaştığı ayarları tutar:

Protokol yapılandırması
MqttProtocolBuilder mqttProtocol = mqtt
    .mqttVersion_5()                         // veya mqttVersion_3_1_1() (varsayılan)
    .broker("broker.connectmq.com", 1883)    // TLS: 8883 portu + .useTls(true)
    .credentials(System.getenv("MQTT_USER"), System.getenv("MQTT_PASS"))
    .keepAlive(30)
    .qosAtLeastOnce()                        // varsayılan QoS 0'dır
    .cleanSession(true)
    .reconnectAttemptsMax(3)
    .correlateBy(jsonPath("$.id"));

İki ayar özellikle önemlidir:

  • Client ID. clientId(...) ayarlamazsanız Gatling her sanal kullanıcı için rastgele bir ID üretir — yük testleri için güvenli varsayılan budur. ID'yi bir feeder'dan alıyorsanız değerlerin benzersiz olduğundan emin olun; aksi halde kullanıcılar birbirinin oturumunu devralır.
  • correlateBy. Gatling'e gelen bir mesajı onu bekleyen istekle nasıl eşleştireceğini söyler. Burada her payload bir id alanı taşır, böylece kullanıcının aldığı mesaj gönderdiği publish ile eşleştirilebilir.

Cihaz telemetrisi senaryosu

Aşağıdaki senaryo bir cihazı modeller: bağlanır, kendi topic'ine subscribe olur, ardından bir dakika boyunca her saniye bir ölçüm publish eder ve her birinin broker üzerinden geri gelmesini bekler.

src/test/java/mqtt/MqttTelemetrySimulation.java
package mqtt;

import static io.gatling.javaapi.core.CoreDsl.*;
import static io.gatling.javaapi.mqtt.MqttDsl.*;

import io.gatling.javaapi.core.*;
import io.gatling.javaapi.mqtt.*;
import java.time.Duration;
import java.util.Iterator;
import java.util.Map;
import java.util.stream.Stream;

public class MqttTelemetrySimulation extends Simulation {

  MqttProtocolBuilder mqttProtocol = mqtt
      .mqttVersion_5()
      .broker("broker.connectmq.com", 1883)
      .credentials(System.getenv("MQTT_USER"), System.getenv("MQTT_PASS"))
      .keepAlive(30)
      .qosAtLeastOnce()
      .correlateBy(jsonPath("$.id"));

  Iterator<Map<String, Object>> devices =
      Stream.iterate(1, i -> i + 1)
          .map(i -> Map.<String, Object>of("deviceId", "dev-" + i))
          .iterator();

  ScenarioBuilder telemetry = scenario("Device telemetry")
      .feed(devices)
      .exec(mqtt("Connect").connect())
      .exec(mqtt("Subscribe").subscribe("testmqtt/gatling/#{deviceId}/data"))
      .repeat(60, "n").on(
          exec(
              mqtt("Publish")
                  .publish("testmqtt/gatling/#{deviceId}/data")
                  .message(StringBody("{\"id\":\"#{deviceId}-#{n}\",\"temp\":21.5}"))
                  .await(Duration.ofSeconds(2))
                  .check(jsonPath("$.temp").exists())
          ).pause(Duration.ofSeconds(1))
      );

  {
    int users = Integer.getInteger("users", 5);
    setUp(
        telemetry.injectOpen(rampUsers(users).during(Duration.ofSeconds(30)))
    ).protocols(mqttProtocol)
     .assertions(
         global().failedRequests().percent().lt(1.0),
         details("Publish").responseTime().percentile3().lt(200)
     );
  }
}

Her parçanın görevi:

  • Feeder. Her sanal kullanıcıya topic'te ve mesaj ID'sinde kullanılan benzersiz bir deviceId verir.
  • repeat(60, "n"). 60 kez döner ve sayacı #{n} olarak sunar; böylece her mesaj ID'si benzersiz olur — korelasyon için şarttır.
  • .await(Duration.ofSeconds(2)). Bloklayan bir check: kullanıcı, subscribe olunan bir topic'e korelasyon ID'siyle eşleşen bir mesaj gelene kadar bekler ya da 2 saniye sonra başarısız olur. .expect(...) ise bloklamayan varyanttır; beklemeden önce birden çok mesaj publish etmek istediğinizde mqtt.waitForMessages() ile birlikte kullanın.
  • .check(jsonPath("$.temp").exists()). Yalnızca mesajın gelişini değil, eşleşen mesajın içeriğini de doğrular.
  • Assertion'lar. İsteklerin %1'inden fazlası başarısız olursa ya da Publish için 95. percentile 200 ms'yi aşarsa çalıştırmayı başarısız kılar (percentile3() varsayılan olarak 95. percentile'dır). İkisini de kendi baseline'ınıza göre ayarlayın.

Topic'ler testmqtt/gatling/<device>/data desenini izler; ileride wildcard subscription'lar eklerseniz desenleri topic matcher ile doğrulayın.

Enjeksiyon profilini seçme

Bir MQTT simülasyonunda her sanal kullanıcı, senaryo boyunca bir bağlantıyı açık tutan bir cihazdır. Bu yüzden enjeksiyon profili, aynı anda kaç bağlantı bulunacağını ve bağlantıların ne hızla geleceğini belirler:

ProfilNeyi test etmek içinÖrnek
atOnceUsers(n)Bir yeniden bağlanma fırtınası: tüm cihazlar aynı anda bağlanıratOnceUsers(5)
rampUsers(n).during(d)Kademeli olarak çevrimiçi olan sabit bir filo; olağan başlangıç noktasırampUsers(5).during(Duration.ofSeconds(30))
constantUsersPerSec(r).during(d)Sürekli yeni cihaz gelişi (başlayıp biten oturumlar)constantUsersPerSec(1).during(Duration.ofMinutes(2))
rampUsersPerSec(a).to(b).during(d)Bağlantıların yavaşlamaya başladığı noktayı bulmak için artan geliş hızırampUsersPerSec(1).to(5).during(Duration.ofMinutes(1))

Eşzamanlı bağlantı sayısı yaklaşık olarak geliş hızı × senaryo süresidir. Kullanıcı başına saniyede bir yapılan 60 publish ile her kullanıcı yaklaşık bir dakika bağlı kalır; dolayısıyla constantUsersPerSec(10) yaklaşık 600 eşzamanlı cihazda dengelenir. Bir çalıştırmayı boyutlandırırken bu hesabı aklınızda tutun ve Community Edition ile toplamın 5 kullanıcıyla sınırlı kaldığını unutmayın.

Birden çok senaryoyu tek bir setUp içinde de birleştirebilirsiniz; örneğin telemetri cihazlarından oluşan bir rampa ile bir wildcard'a subscribe olan küçük bir dashboard kullanıcı grubu. Her senaryo kendi istek adlarını korur, böylece rapor iki yükü ayrı ayrı gösterir.

Simülasyonu çalıştırın

Maven ile çalıştırın
export MQTT_USER=username MQTT_PASS=password
./mvnw gatling:test \
  -Dgatling.simulationClass=mqtt.MqttTelemetrySimulation \
  -Dusers=5

Community Edition ile users değerini 5 veya altında, süreyi de 5 dakikanın altında tutun — çalıştırma bu sınırlarda durur. Senaryonun, korelasyonun ve check'lerin çalıştığını kanıtlamak için bu yeterlidir. Aynı projeyi binlerce kullanıcı ve birden çok yük üreticiyle çalıştırmak için Gatling Enterprise'a yükleyin.

HTML raporunu okuma

Sonunda Gatling, target/gatling/<simulation>-<timestamp>/index.html dosyasının yolunu yazdırır. Rapor her şeyi istek adına göre gruplar; yani mqtt("…") içindeki adlar raporunuzun başlıklarıdır:

İstekYanıt süresi şunu ifade ederNelere bakmalı
ConnectBroker bağlantıyı kabul edene kadar (CONNACK), TLS dahilKullanıcı sayısı artarken hatalar veya yavaş bağlantılar
SubscribeBroker subscription'ı onaylayana kadar (SUBACK)Nadiren darboğazdır; hatalar genellikle ACL sorunlarına işaret eder
Publish (await ile)Publish'ten korelasyonlu mesajın gelişine kadarUçtan uca gecikme percentile'ları ve timeout'lar

Faydalı grafikler:

  • Zamana göre yanıt süresi percentile'ları. Kullanıcılar artarken yükselen bir p95 veya p99, broker'ın ya da ağın doymaya başladığı noktayı gösterir.
  • Saniye başına istek. Planladığınız hızla karşılaştırın (burada kullanıcı × 1 mesaj/sn). Hedefin altında sabitleniyorsa bir şey trafiği kısıtlıyordur.
  • Hata tablosu. await üzerindeki timeout'lar mesajların zamanında geri gelmediği anlamına gelir — QoS'u, kuyruk limitlerini ve mesajların neden kaybolduğunu kontrol edin. Yuvarlak bir kullanıcı sayısında görülen bağlantı hataları çoğunlukla bir limite işaret eder; broker'ın reason code'larını MQTT reason code aracı ile çözümleyin.

Broker limitlerini yük üretici limitlerinden ayırmak için daha kapsamlı bir yöntem MQTT benchmark sonuçlarını yorumlama yazısında.

Gerçekçi simülasyonlar için ipuçları

  1. İstekleri değil oturumları modelleyin. Gerçek cihazlar bağlı kalır; her mesaj için yeniden bağlanmak yerine bağlantıyı döngü boyunca açık tutun.
  2. Gerçek payload boyutlarını kullanın. Küçük JSON'u kendi payload'larınıza benzeyenlerle değiştirin; hattaki boyutlarını paket boyutu hesaplayıcı ile kontrol edin.
  3. Fan-out'u bire bir senaryodan ayırın. testmqtt/gatling/+/data topic'ine subscribe olan bir dashboard senaryosu tüm cihazların mesajlarını alır; yükünün görünür olması için onu ayrı bir senaryo olarak çalıştırın.
  4. Yük üreticiyi izleyin. Doymuş bir JVM yanıt sürelerini şişirir. Gatling'i çalıştıran makinede CPU'yu ve GC'yi kontrol edin.
  5. Simülasyonu sürüm kontrolüne alın. Gerilemeleri yakalamak için broker güncellemelerinden ve yapılandırma değişikliklerinden sonra yeniden çalıştırın.

Gatling trafiğini online client'ta izleyin

Gatling'in MQTT eklentisi, çoğu MQTT aracında bulunmayan korelasyon ve check'lerle okunabilir, sürüm kontrollü senaryolar sunar. Simülasyonu Community Edition sınırları içinde oluşturup doğrulayın, lisansınızın izin verdiği yerde büyük ölçekte çalıştırın ve publish sürelerini her zaman await check'leriyle okuyun; çünkü cihazlarınızın hissettiği gecikme budur.

Sıkça sorulan sorular

Gatling'in MQTT desteği ücretsiz mi?

MQTT eklentisi (gatling-mqtt-java), Gatling Enterprise Component License ile Maven Central'da yayımlanır. Community Edition ile 5 sanal kullanıcı ve 5 dakikalık testlerle sınırlıdır; simülasyon Gatling Enterprise üzerinde çalıştığında bu sınırlar kalkar.

Gatling MQTT 5'i destekliyor mu?

Evet, protocol builder mqttVersion_3_1(), mqttVersion_3_1_1() (varsayılan) ve mqttVersion_5() seçeneklerini sunar. Gatling, MQTT 5 özelliklerinin henüz tamamının mevcut olmayabileceğini belirtir; belirli bir özelliğe ihtiyacınız varsa dokümantasyonu kontrol edin.

Gatling MQTT yanıt süresini nasıl ölçer?

Connect ve subscribe, broker yanıt verene kadar ölçülür. Publish için bir await veya expect check'i ekleyin: Gatling bu durumda eşleşen bir gelen mesaj ulaşana kadar geçen süreyi kaydeder ve raporda uçtan uca gecikmeyi görürsünüz.