Testes de brokers

Guia do emqtt-bench: todos os comandos e flags explicados

Guia completo do emqtt-bench: modos conn, pub e sub, as flags importantes, opções de TLS e WebSocket, headers de latência e como ler os contadores de saída.

Atualizado · 10 min de leitura

Guia do emqtt-bench: todos os comandos e flags explicados

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:

Rodar com Docker
docker run --rm -it emqx/emqtt-bench pub --help

Para 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:

Compilar a partir do código-fonte
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 --help

Antes 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

FlagSignificadoPadrão
-h, --hostHost do broker; uma lista separada por vírgulas distribui os clientes entre vários hostslocalhost
-p, --portPorta do broker1883
-V, --versionVersão do protocolo MQTT: 3 (3.1), 4 (3.1.1) ou 55
-c, --countNúmero de clientes a iniciar200
-i, --intervalMilissegundos entre novas conexões10
-R, --connrateConexões por segundo; 0 volta a usar -i0
-u, -PUsuário e senhanenhum
-k, --keepaliveKeep alive em segundos300
-C, --cleanClean session / clean starttrue
-x, --session-expirySession expiry interval do MQTT 5 em segundos0
--prefixPrefixo do client ID (sem sufixo aleatório quando definido)<host>_bench_<cmd>_<random>_<n>
--shortidsClient IDs curtos: o número de sequência, ou prefixo + númerofalse
-n, --startnumberPrimeiro número de sequência; evita conflito de IDs entre várias instâncias0
--ifaddrEndereço(s) IP local(is) para bind, separados por vírgulapadrão do sistema
--reconnectTentativas de reconexão após uma desconexão0 (desligado)
--num-retry-connectNovas tentativas para a conexão inicial0
-l, --lowmemModo de pouca memória: menos RAM por cliente, mais CPUdesligado

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?"

5.000 clientes a 500 conexões por segundo
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.

FlagSignificadoPadrão
-t, --topicFiltro de topic, com placeholders (veja abaixo)obrigatório
-q, --qosQoS da subscription0
--payload-hdrsInterpreta os headers adicionados pelo publisher (ts, cnt64)nenhum
100 subscribers, um topic cada
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.

FlagSignificadoPadrão
-t, --topicTopic onde publicar, com placeholdersobrigatório
-I, --interval_of_msgMilissegundos entre mensagens, por cliente1000
-s, --sizeTamanho do payload em bytes256
-m, --messagePayload literal, ou template://<file>bytes aleatórios
-q, --qosQoS do publish0
-r, --retainLiga a flag retainfalse
-L, --limitPara após esse número de mensagens; 0 = ilimitado0
-F, --inflightMáximo de mensagens QoS 1/2 sem confirmação por cliente; 0 = ilimitado1
-w, --wait-before-publishingSó começa a publicar depois que todos os publishers tentaram conectarfalse
--payload-hdrsPrefixa o payload com ts (timestamp) e/ou cnt64 (contador)nenhum
100 publishers, 10 msg/s cada = 1.000 msg/s
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
%iNúmero de sequência do cliente (inclui o deslocamento de -n)
%cClient ID
%uO usuário informado com -u
%sNúmero de sequência da mensagem (só pub)
%rand_NInteiro 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

FlagSignificado
-S, --sslAtiva TLS
--ssl-versionForça uma versão de TLS (implica --ssl)
--cacertfileBundle de CA para verificar o broker
--certfile, --keyfileCertificado e chave do cliente (TLS mútuo)
--ciphersRestringe as cipher suites
--wsUsa transporte WebSocket
--quicUsa MQTT sobre QUIC (em brokers que suportam)
TLS e WebSocket seguro
# 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:

Latência ponta a ponta
# 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:

Saída típica do pub
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
ContadorSignificado
connect_succ / connect_failConexões aceitas / com falha
connect_retried, reconnect_succNovas tentativas e reconexões bem-sucedidas
connection_refused, connection_timeout, unreachablePor que as conexões falharam
connection_idleConexões que ficaram ociosas
sub / sub_failSubscriptions aceitas / rejeitadas
pub / pub_succ / pub_failMensagens enviadas / confirmadas / com falha
pub_overrunUm cliente não conseguiu manter o intervalo de publish
pub_nosubO broker informou que não há subscribers correspondentes (MQTT 5)
recvMensagens recebidas pelos subscribers
publish_latencyLatê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 -n bem acima de -c antes de execuções grandes de conn.
  • 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.12 ou várias máquinas e amplie a faixa de portas locais com sysctl.
  • Memória. Adicione -l para 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.