O emqtt-bench (o binário se chama emqtt_bench) é uma ferramenta open source de benchmark MQTT da EMQ, escrita em Erlang, capaz de abrir dezenas de milhares de conexões e gerar carga de publish e subscribe a partir de uma única máquina. Ela tem três comandos — conn, sub e pub — e uma longa lista de flags. Este guia explica cada comando, as flags que realmente importam, o uso de TLS e WebSocket, a medição de latência e como ler o que a ferramenta imprime.
Para o método mais amplo — o que medir e como planejar um benchmark — veja teste de carga de broker MQTT. Esta página é a referência da ferramenta em si.
Instalar ou rodar com Docker
O jeito mais rápido é a imagem Docker, cujo entrypoint é emqtt_bench:
docker run --rm -it emqx/emqtt-bench pub --helpPara execuções longas ou muito grandes, uma instalação nativa evita o overhead de rede do Docker. Há pacotes pré-compilados na página de releases do projeto no GitHub. Compilar a partir do código-fonte exige um Erlang/OTP recente e libatomic:
git clone https://github.com/emqx/emqtt-bench.git
cd emqtt-bench
make # BUILD_WITHOUT_QUIC=1 make se a compilação do QUIC falhar
./emqtt_bench conn --helpAntes de qualquer benchmark, confira host, porta e credenciais manualmente com um único cliente no cliente MQTT online. Se uma conexão falha, duas mil vão falhar mais rápido. Os exemplos usam broker.connectmq.com, um endpoint compartilhado adequado para verificações rápidas; rode benchmarks reais contra a sua própria instância privada de broker trocando -h e as credenciais.
Opções comuns a todos os comandos
| Flag | Significado | Padrão |
|---|---|---|
-h, --host | Host do broker; uma lista separada por vírgulas distribui os clientes entre vários hosts | localhost |
-p, --port | Porta do broker | 1883 |
-V, --version | Versão do protocolo MQTT: 3 (3.1), 4 (3.1.1) ou 5 | 5 |
-c, --count | Número de clientes a iniciar | 200 |
-i, --interval | Milissegundos entre novas conexões | 10 |
-R, --connrate | Conexões por segundo; 0 volta a usar -i | 0 |
-u, -P | Usuário e senha | nenhum |
-k, --keepalive | Keep alive em segundos | 300 |
-C, --clean | Clean session / clean start | true |
-x, --session-expiry | Session expiry interval do MQTT 5 em segundos | 0 |
--prefix | Prefixo do client ID (sem sufixo aleatório quando definido) | <host>_bench_<cmd>_<random>_<n> |
--shortids | Client IDs curtos: o número de sequência, ou prefixo + número | false |
-n, --startnumber | Primeiro número de sequência; evita conflito de IDs entre várias instâncias | 0 |
--ifaddr | Endereço(s) IP local(is) para bind, separados por vírgula | padrão do sistema |
--reconnect | Tentativas de reconexão após uma desconexão | 0 (desligado) |
--num-retry-connect | Novas tentativas para a conexão inicial | 0 |
-l, --lowmem | Modo de pouca memória: menos RAM por cliente, mais CPU | desligado |
Dois detalhes costumam confundir. Primeiro, a versão de protocolo padrão é MQTT 5; passe -V 4 para testar um broker ou configuração que só fala 3.1.1. Segundo, o keep alive padrão de 300 s é bem maior do que o da maioria dos dispositivos; ajuste -k para o valor da sua frota se estiver testando o comportamento de conexões ociosas.
Client IDs precisam ser únicos por broker. Ao rodar vários processos do emqtt-bench contra o mesmo broker, dê a cada um seu próprio --prefix ou faixa de -n — IDs duplicados causam session takeovers que parecem desconexões aleatórias. Você pode visualizar formatos de ID com o gerador de client ID.
conn: capacidade de conexões
conn apenas conecta e mantém as conexões. Ele responde: "quantos clientes simultâneos o broker aguenta e com que velocidade os aceita?"
docker run --rm -it emqx/emqtt-bench conn \
-h broker.connectmq.com -p 1883 \
-c 5000 -R 500 -k 60 \
-u "$MQTT_USER" -P "$MQTT_PASS"Acompanhe o connect_succ subir até a meta e o connect_fail ficar em zero. Uma tempestade de reconexões — todos os dispositivos voltando depois de uma queda — é simulada aumentando -R. Mais cenários estão no guia de teste de estresse de conexões.
sub: subscribers
sub conecta clientes, faz subscribe de cada um em um topic e conta o que recebe.
| Flag | Significado | Padrão |
|---|---|---|
-t, --topic | Filtro de topic, com placeholders (veja abaixo) | obrigatório |
-q, --qos | QoS da subscription | 0 |
--payload-hdrs | Interpreta os headers adicionados pelo publisher (ts, cnt64) | nenhum |
docker run --rm -it emqx/emqtt-bench sub \
-h broker.connectmq.com -p 1883 \
-c 100 -i 5 -q 1 \
-t 'testmqtt/bench/%i/data' \
-u "$MQTT_USER" -P "$MQTT_PASS"pub: publishers
pub conecta clientes e publica em um intervalo fixo por cliente.
| Flag | Significado | Padrão |
|---|---|---|
-t, --topic | Topic onde publicar, com placeholders | obrigatório |
-I, --interval_of_msg | Milissegundos entre mensagens, por cliente | 1000 |
-s, --size | Tamanho do payload em bytes | 256 |
-m, --message | Payload literal, ou template://<file> | bytes aleatórios |
-q, --qos | QoS do publish | 0 |
-r, --retain | Liga a flag retain | false |
-L, --limit | Para após esse número de mensagens; 0 = ilimitado | 0 |
-F, --inflight | Máximo de mensagens QoS 1/2 sem confirmação por cliente; 0 = ilimitado | 1 |
-w, --wait-before-publishing | Só começa a publicar depois que todos os publishers tentaram conectar | false |
--payload-hdrs | Prefixa o payload com ts (timestamp) e/ou cnt64 (contador) | nenhum |
docker run --rm -it emqx/emqtt-bench pub \
-h broker.connectmq.com -p 1883 \
-c 100 -I 100 -s 512 -q 1 -F 10 -w \
-t 'testmqtt/bench/%i/data' \
-u "$MQTT_USER" -P "$MQTT_PASS"A taxa alvo é clientes × (1000 / -I). Repare no -F: com a janela inflight padrão de 1, cada cliente QoS 1 espera cada PUBACK antes de enviar a próxima mensagem, então com latência alta um cliente nunca alcança seu intervalo. Se pub_overrun estiver subindo, o cliente não conseguiu manter o ritmo; aumente -F ou reduza a taxa. Estratégias de teste de throughput estão no guia de teste de throughput MQTT.
Placeholders de topic
Placeholders em -t permitem que um único comando crie muitos topics diferentes:
| Placeholder | É substituído por |
|---|---|
%i | Número de sequência do cliente (inclui o deslocamento de -n) |
%c | Client ID |
%u | O usuário informado com -u |
%s | Número de sequência da mensagem (só pub) |
%rand_N | Inteiro aleatório de 1 a N |
Usar %i dos dois lados — pub -t 'testmqtt/bench/%i/data' e sub -t 'testmqtt/bench/%i/data' com o mesmo -c — pareia o publisher N com o subscriber N: roteamento um para um. Já um único subscriber em testmqtt/bench/+/data mede fan-in, e muitos subscribers em um topic medem fan-out. Confira seus filtros com o topic matcher.
TLS, WebSockets e QUIC
| Flag | Significado |
|---|---|
-S, --ssl | Ativa TLS |
--ssl-version | Força uma versão de TLS (implica --ssl) |
--cacertfile | Bundle de CA para verificar o broker |
--certfile, --keyfile | Certificado e chave do cliente (TLS mútuo) |
--ciphers | Restringe as cipher suites |
--ws | Usa transporte WebSocket |
--quic | Usa MQTT sobre QUIC (em brokers que suportam) |
# MQTT sobre TLS
emqtt_bench conn -h broker.connectmq.com -p 8883 --ssl \
--cacertfile /etc/ssl/certs/ca-certificates.crt \
-c 1000 -R 100 -u "$MQTT_USER" -P "$MQTT_PASS"
# MQTT sobre WebSocket seguro
emqtt_bench pub -h broker.connectmq.com -p 8084 --ws --ssl \
-c 50 -I 1000 -t 'testmqtt/bench/%i/ws' -u "$MQTT_USER" -P "$MQTT_PASS"O emqtt-bench não tem uma flag separada para o path do WebSocket; o cliente emqtt por baixo usa /mqtt, que corresponde ao endpoint usado nestes exemplos. Comparar a mesma execução de conn na 1883 e na 8883 mostra diretamente o custo do handshake — veja teste de desempenho TLS no MQTT.
Medindo latência
Inicie o subscriber e o publisher com o mesmo --payload-hdrs ts. O publisher grava um timestamp em milissegundos no início de cada payload; o subscriber o subtrai do próprio relógio na chegada:
# terminal 1
emqtt_bench sub -h broker.connectmq.com -c 50 -q 1 \
-t 'testmqtt/bench/%i/lat' --payload-hdrs ts -u "$MQTT_USER" -P "$MQTT_PASS"
# terminal 2
emqtt_bench pub -h broker.connectmq.com -c 50 -I 200 -q 1 \
-t 'testmqtt/bench/%i/lat' --payload-hdrs ts -u "$MQTT_USER" -P "$MQTT_PASS"O subscriber passa a imprimir uma linha publish_latency avg=…ms. É uma média; para percentis, ative --prometheus (expõe um histograma e2e_latency) ou use o script do guia de teste de carga. Como o timestamp vem do relógio do publisher, rode os dois na mesma máquina ou mantenha os relógios das máquinas sincronizados.
Lendo a saída
A cada segundo, o emqtt-bench imprime uma linha por contador que mudou, no formato <tempo> <contador> total=<n> rate=<n>/sec:
10s connect_succ total=100 rate=0.00/sec
10s pub total=9871 rate=1000.12/sec
10s pub_succ total=9862 rate=999.40/sec| Contador | Significado |
|---|---|
connect_succ / connect_fail | Conexões aceitas / com falha |
connect_retried, reconnect_succ | Novas tentativas e reconexões bem-sucedidas |
connection_refused, connection_timeout, unreachable | Por que as conexões falharam |
connection_idle | Conexões que ficaram ociosas |
sub / sub_fail | Subscriptions aceitas / rejeitadas |
pub / pub_succ / pub_fail | Mensagens enviadas / confirmadas / com falha |
pub_overrun | Um cliente não conseguiu manter o intervalo de publish |
pub_nosub | O broker informou que não há subscribers correspondentes (MQTT 5) |
recv | Mensagens recebidas pelos subscribers |
publish_latency | Latência média ponta a ponta (com --payload-hdrs ts) |
O padrão saudável: as taxas de pub e recv batem com a meta e entre si, pub_overrun fica em zero e nenhum contador de falha aparece. Um connection_timeout ou connect_fail subindo perto de um número redondo (1.024, 65.535) normalmente aponta para limites no gerador de carga. Consulte qualquer reason code do broker na ferramenta de reason codes.
Escalando o gerador de carga
- Descritores de arquivo. Aumente o
ulimit -nbem acima de-cantes de execuções grandes deconn. - Portas. Um IP de origem só abre cerca de 64K conexões para um endereço e porta do broker. Use
--ifaddr 10.0.0.11,10.0.0.12ou várias máquinas e amplie a faixa de portas locais comsysctl. - Memória. Adicione
-lpara quantidades muito grandes de clientes, ao custo de mais CPU. - CPU. Se o gerador passar de uns 80 % de CPU, seus números descrevem o gerador, não o broker.
Veja o tráfego do benchmark no cliente online
O emqtt-bench é o jeito mais rápido de colocar uma carga realista de conexões e mensagens em um broker MQTT pela linha de comando. Aprenda o punhado de flags que moldam a carga — -c, -R, -I, -q, -F e os placeholders de topic —, confirme que TLS e versão de protocolo batem com a produção e leia os contadores como taxas que você pode comparar entre execuções.
Perguntas frequentes
Qual a diferença entre -i e -R no emqtt-bench?
-i (--interval) é a pausa em milissegundos entre novas conexões, 10 por padrão. -R (--connrate) define uma taxa de conexões por segundo; quando é 0 (o padrão), o emqtt-bench volta a usar o intervalo.
Como medir latência com o emqtt-bench?
Inicie o subscriber e o publisher com a mesma opção --payload-hdrs ts. O publisher coloca um timestamp em milissegundos no início de cada payload e o subscriber imprime uma linha publish_latency com a latência média ponta a ponta. Rode os dois na mesma máquina ou mantenha os relógios sincronizados.
Por que o emqtt-bench para por volta de 64.000 conexões?
Um IP de origem só consegue abrir cerca de 64K conexões TCP para o mesmo endereço e porta do broker. Distribua os clientes entre vários endereços locais com --ifaddr ou rode o emqtt-bench em várias máquinas, e aumente o ulimit -n.



