Gatling puede hacer pruebas de carga a un broker MQTT con su plugin MQTT: describes el comportamiento de un dispositivo como un escenario en Java, Kotlin o Scala — connect, subscribe, publish, esperar el mensaje correspondiente — y Gatling inyecta usuarios virtuales y genera su informe HTML con percentiles de tiempo de respuesta y throughput. Encaja con equipos que ya usan Gatling para HTTP y quieren el mismo flujo de simulación como código para MQTT.
Antes de empezar, conoce la licencia: el componente MQTT se distribuye bajo la Gatling Enterprise Component License. En local con la Community Edition está limitado a 5 usuarios virtuales y pruebas de 5 minutos, suficiente para desarrollar y validar una simulación. Ejecutarla a escala real requiere Gatling Enterprise. Si eso no te encaja, k6 con xk6-mqtt, JMeter o emqtt-bench son alternativas open source.
Configurar el proyecto
La forma más fácil de empezar es uno de los proyectos de demo de Gatling para Maven o Gradle. Después añade el plugin MQTT junto a las dependencias estándar de Gatling:
<dependency>
<groupId>io.gatling</groupId>
<artifactId>gatling-mqtt-java</artifactId>
<version>3.16.0</version>
<scope>test</scope>
</dependency>Usa la misma versión que el resto de artefactos de Gatling. Los proyectos Scala usan gatling-mqtt en lugar de gatling-mqtt-java; en Gradle se declara como gatlingImplementation("io.gatling:gatling-mqtt-java:3.16.0").
El DSL de MQTT no se importa por defecto, así que cada simulación necesita:
import io.gatling.javaapi.mqtt.*;
import static io.gatling.javaapi.mqtt.MqttDsl.*;Antes de escribir la simulación, confirma broker, puerto y credenciales con un único cliente en el cliente MQTT online. Así sabrás que cualquier fallo posterior viene de la carga, no de la configuración. Usa el endpoint compartido broker.connectmq.com solo para validar el escenario; para carga real, apunta .broker(...) y las credenciales a tu propia instancia privada de broker.
El protocolo: broker, credenciales, QoS
El protocol builder contiene la configuración compartida por todos los usuarios virtuales:
MqttProtocolBuilder mqttProtocol = mqtt
.mqttVersion_5() // o mqttVersion_3_1_1() (por defecto)
.broker("broker.connectmq.com", 1883) // TLS: puerto 8883 + .useTls(true)
.credentials(System.getenv("MQTT_USER"), System.getenv("MQTT_PASS"))
.keepAlive(30)
.qosAtLeastOnce() // por defecto es QoS 0
.cleanSession(true)
.reconnectAttemptsMax(3)
.correlateBy(jsonPath("$.id"));Dos ajustes merecen atención:
- Client ID. Si no defines
clientId(...), Gatling genera uno aleatorio por usuario virtual, la opción segura para pruebas de carga. Si lo tomas de un feeder, asegúrate de que los valores sean únicos o los usuarios se quitarán la sesión unos a otros. correlateBy. Le dice a Gatling cómo asociar un mensaje entrante con la petición que lo espera. Aquí cada payload lleva un campoid, así que el mensaje que recibe un usuario se puede emparejar con el publish que envió.
Un escenario de telemetría de dispositivo
El escenario siguiente modela un dispositivo: se conecta, se suscribe a su propio topic y luego publica una lectura por segundo durante un minuto, esperando a que cada una vuelva a través del broker.
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)
);
}
}Qué hace cada parte:
- Feeder. Da a cada usuario virtual un
deviceIdúnico, que se usa en el topic y en el id del mensaje. repeat(60, "n"). Repite 60 veces y expone el contador como#{n}, de modo que cada id de mensaje es único, algo necesario para la correlación..await(Duration.ofSeconds(2)). Un check bloqueante: el usuario espera a que llegue a un topic suscrito un mensaje con el id de correlación, o falla a los 2 segundos..expect(...)es la variante no bloqueante; combínala conmqtt.waitForMessages()cuando quieras publicar varios mensajes antes de esperar..check(jsonPath("$.temp").exists()). Valida el contenido del mensaje emparejado, no solo su llegada.- Assertions. Hacen fallar la ejecución si más del 1 % de las peticiones falla o si el percentil 95 de
Publishsupera 200 ms (percentile3()es el percentil 95 por defecto). Ajusta ambos a tu propia línea base.
Los topics siguen el patrón testmqtt/gatling/<device>/data; si más adelante añades suscripciones con wildcards, verifica los patrones en el topic matcher.
Elegir un perfil de inyección
En una simulación MQTT, cada usuario virtual es un dispositivo que mantiene una conexión durante todo el escenario, así que el perfil de inyección decide cuántas conexiones existen a la vez y a qué ritmo llegan:
| Perfil | Úsalo para probar | Ejemplo |
|---|---|---|
atOnceUsers(n) | Una tormenta de reconexiones: todos los dispositivos se conectan a la vez | atOnceUsers(5) |
rampUsers(n).during(d) | Una flota estable que se va conectando; el punto de partida habitual | rampUsers(5).during(Duration.ofSeconds(30)) |
constantUsersPerSec(r).during(d) | Llegada continua de nuevos dispositivos (sesiones que empiezan y terminan) | constantUsersPerSec(1).during(Duration.ofMinutes(2)) |
rampUsersPerSec(a).to(b).during(d) | Una tasa de llegada creciente, para encontrar el punto en que las conexiones se ralentizan | rampUsersPerSec(1).to(5).during(Duration.ofMinutes(1)) |
Las conexiones concurrentes son aproximadamente la tasa de llegada × la duración del escenario. Con 60 publicaciones de un segundo por usuario, cada usuario permanece conectado alrededor de un minuto, así que constantUsersPerSec(10) se estabiliza en unos 600 dispositivos concurrentes. Ten en cuenta este cálculo al dimensionar una ejecución, y recuerda que con la Community Edition el total sigue limitado a 5 usuarios.
También puedes combinar escenarios en un mismo setUp, por ejemplo una rampa de dispositivos de telemetría y un pequeño grupo de usuarios de dashboard suscritos a un wildcard. Cada escenario conserva sus propios nombres de petición, así que el informe muestra ambas cargas por separado.
Ejecutar la simulación
export MQTT_USER=username MQTT_PASS=password
./mvnw gatling:test \
-Dgatling.simulationClass=mqtt.MqttTelemetrySimulation \
-Dusers=5Con la Community Edition, mantén users en 5 o menos y la duración por debajo de 5 minutos: la ejecución se detiene al alcanzar esos límites. Es suficiente para demostrar que el escenario, la correlación y los checks funcionan. Sube el mismo proyecto a Gatling Enterprise para ejecutarlo con miles de usuarios y varios generadores de carga.
Leer el informe HTML
Al final Gatling muestra la ruta a target/gatling/<simulation>-<timestamp>/index.html. El informe agrupa todo por nombre de petición, así que los nombres de mqtt("…") son tus títulos:
| Petición | El tiempo de respuesta significa | Qué buscar |
|---|---|---|
| Connect | Hasta que el broker acepta la conexión (CONNACK), TLS incluido | Fallos o conexiones lentas a medida que suben los usuarios |
| Subscribe | Hasta que el broker confirma la suscripción (SUBACK) | Rara vez es un cuello de botella; los fallos suelen indicar problemas de ACL |
Publish (con await) | Desde el publish hasta que llega el mensaje correlacionado | Percentiles de latencia extremo a extremo y timeouts |
Gráficas útiles:
- Percentiles del tiempo de respuesta en el tiempo. Un p95 o p99 que sube mientras aumentan los usuarios muestra dónde empieza a saturarse el broker o la red.
- Peticiones por segundo. Compáralas con la tasa prevista (usuarios × 1 msg/s aquí). Si se estancan por debajo del objetivo, algo está limitando.
- Tabla de errores. Los timeouts en
awaitsignifican que los mensajes no volvieron a tiempo: revisa QoS, límites de colas y por qué se pierden mensajes. Los errores de conexión en un número redondo de usuarios suelen indicar un límite; decodifica los reason codes del broker con la herramienta de reason codes MQTT.
Un método más amplio para separar los límites del broker de los del generador de carga está en interpretar resultados de benchmarks MQTT.
Consejos para simulaciones realistas
- Modela sesiones, no peticiones. Los dispositivos reales permanecen conectados; mantén la conexión abierta durante el bucle en lugar de conectarte por cada mensaje.
- Usa tamaños de payload reales. Sustituye el JSON mínimo por payloads con la forma de los tuyos; comprueba su tamaño en la red con la calculadora de tamaño de paquetes.
- Separa el fan-out del uno a uno. Un escenario de dashboard que se suscribe a
testmqtt/gatling/+/datarecibe los mensajes de todos los dispositivos; ejecútalo como escenario propio para que su carga sea visible. - Vigila el generador de carga. Una JVM saturada infla los tiempos de respuesta. Revisa CPU y GC en la máquina que ejecuta Gatling.
- Versiona la simulación. Vuelve a ejecutarla tras actualizaciones y cambios de configuración del broker para detectar regresiones.
Observa el tráfico de Gatling en el cliente online
El plugin MQTT de Gatling te da escenarios legibles y versionados, con correlación y checks que la mayoría de herramientas MQTT no tienen. Construye y valida la simulación dentro de los límites de la Community Edition, ejecútala a escala donde tu licencia lo permita y lee siempre los tiempos de publish con checks await, porque esa es la latencia que sienten tus dispositivos.
Preguntas frecuentes
¿El soporte MQTT de Gatling es gratuito?
El plugin MQTT (gatling-mqtt-java) se publica en Maven Central bajo la Gatling Enterprise Component License. Con la Community Edition está limitado a 5 usuarios virtuales y pruebas de 5 minutos; los límites desaparecen cuando la simulación se ejecuta en Gatling Enterprise.
¿Gatling soporta MQTT 5?
Sí, el protocol builder ofrece mqttVersion_3_1(), mqttVersion_3_1_1() (por defecto) y mqttVersion_5(). Gatling advierte que quizá no todas las funciones de MQTT 5 estén disponibles todavía, así que revisa la documentación si dependes de una concreta.
¿Cómo mide Gatling el tiempo de respuesta MQTT?
Connect y subscribe se miden hasta que responde el broker. Para publish, añade un check await o expect: Gatling registra entonces el tiempo hasta que llega un mensaje entrante correspondiente, lo que te da la latencia extremo a extremo en el informe.



