Um teste de estresse de conexões MQTT responde a uma pergunta simples: quantos clientes este broker consegue manter ao mesmo tempo e com que rapidez consegue aceitá-los? O método é aumentar conexões ociosas a uma taxa controlada enquanto você observa memória, CPU e latência de conexão do broker — e garantir que o limite atingido pertence ao broker, não à máquina que gera a carga.
A maioria das primeiras tentativas para em um número suspeitosamente redondo. Este guia mostra como remover esses limites do lado do cliente, rodar o teste com emqtt-bench ou com um script Node.js e simular a tempestade de reconexões que vem depois de cada reinício do broker.
O que você está medindo de fato
| Métrica | Por que importa |
|---|---|
| Máximo de conexões simultâneas | Tamanho de frota que o broker consegue manter ociosa |
| Taxa de conexão (CONNECT/s) | Com que rapidez uma frota volta depois de uma queda |
| Latência de conexão (p50/p99) | Tempo do SYN do TCP até o CONNACK sob carga |
| Memória do broker por conexão | Planejamento de capacidade; meça, não chute |
| Tipos de erro | Recusas, timeouts, reason codes do CONNACK |
Conexões custam ao broker memória para buffers de socket, estado de sessão e inscrições, além de CPU para handshakes TLS e processamento de keep-alive. Tudo isso depende do broker, da versão e da configuração, então o único número que importa é o que você mede com as suas configurações: mesmo TLS, mesmo keep-alive, mesma autenticação e aproximadamente as mesmas inscrições por cliente.
Corrija o gerador de carga primeiro
Uma única máquina Linux tem três limites que travam as conexões de saída muito antes de um broker decente desistir.
Descritores de arquivo
Cada socket TCP é um descritor de arquivo. O limite soft padrão costuma ser 1.024:
ulimit -n # limite soft atual
ulimit -n 200000 # aumentar neste shell (até o limite hard)
cat /proc/sys/fs/file-max # teto do sistemaPara uma mudança permanente, defina nofile em /etc/security/limits.conf ou, no Docker, passe --ulimit nofile=200000:200000.
Portas efêmeras
Cada conexão de um IP de origem para o mesmo IP e porta do broker precisa de uma porta local única. A faixa padrão do Linux é 32768–60999, cerca de 28.000 portas — o lugar clássico onde os testes empacam.
sysctl net.ipv4.ip_local_port_range
sudo sysctl -w net.ipv4.ip_local_port_range="1024 65000"Isso dá cerca de 64.000 conexões por IP de origem. Além disso, você precisa de mais IPs de origem (ou mais portas/IPs no broker, ou mais máquinas de carga).
Rastreamento de conexões
Se o gerador de carga roda um firewall com rastreamento de conexões (comum com Docker e iptables), a tabela do conntrack pode encher. O log do kernel então mostra nf_conntrack: table full, dropping packet.
sudo sysctl net.netfilter.nf_conntrack_count net.netfilter.nf_conntrack_max
sudo sysctl -w net.netfilter.nf_conntrack_max=262144Rodando o teste com emqtt-bench
O emqtt-bench foi feito para isso. O comando conn abre conexões a uma taxa fixa e as mantém vivas:
docker run --rm -it --ulimit nofile=200000:200000 emqx/emqtt-bench conn \
-h "$MQTT_HOST" -p 1883 \
-c 10000 -R 500 -k 60 \
-u "$MQTT_USER" -P "$MQTT_PASS"Defina MQTT_HOST como o seu próprio broker; o endpoint compartilhado broker.connectmq.com serve só para pequenos smoke tests. -c é o número de clientes, -R a taxa de conexão por segundo e -k o keep-alive em segundos. Use o mesmo keep-alive dos seus dispositivos: keep-alives mais curtos significam mais tráfego PINGREQ por cliente ocioso.
Para ir além de um IP de origem, adicione endereços secundários à máquina de carga e deixe o emqtt-bench distribuir os clientes entre eles com --ifaddr. Use a rede do host para que o contêiner enxergue esses endereços:
docker run --rm -it --network host --ulimit nofile=200000:200000 \
emqx/emqtt-bench conn \
-h "$MQTT_HOST" -p 1883 \
-c 50000 -R 1000 -k 60 \
--ifaddr 10.0.0.11,10.0.0.12Suba em degraus — por exemplo 10k, 25k, 50k — e mantenha cada nível por vários minutos. Um broker que aceita 50.000 conexões mas começa a derrubá-las no próximo ciclo de keep-alive não passou no teste.
Um script Node.js que você pode modificar
Quando você precisa de fluxos de autenticação reais, inscrições por cliente ou client IDs personalizados, um pequeno script com MQTT.js 5 é mais fácil de adaptar do que uma ferramenta de benchmark:
import mqtt from "mqtt";
const URL = process.env.MQTT_URL ?? "mqtt://broker.connectmq.com:1883";
const TOTAL = Number(process.argv[2] ?? 100); // padrão: um pequeno smoke test
const RATE = Number(process.argv[3] ?? 200); // novas conexões por segundo
let opened = 0, up = 0, errors = 0, closes = 0;
function open(i) {
const c = mqtt.connect(URL, {
clientId: `stress-${process.pid}-${i}`,
username: process.env.MQTT_USER,
password: process.env.MQTT_PASS,
keepalive: 60,
connectTimeout: 15_000,
reconnectPeriod: 2000 + Math.floor(Math.random() * 8000), // jitter por cliente
});
let online = false;
c.on("connect", () => {
if (!online) { online = true; up++; }
c.subscribe(`testmqtt/stress/${i}/cmd`, { qos: 1 });
});
c.on("close", () => { if (online) { online = false; up--; } closes++; });
c.on("error", () => errors++);
}
const timer = setInterval(() => {
for (let k = 0; k < RATE / 10 && opened < TOTAL; k++) open(opened++);
if (opened >= TOTAL) clearInterval(timer);
}, 100);
setInterval(() => {
console.log(`${new Date().toISOString()} opened=${opened} connected=${up} closes=${closes} errors=${errors}`);
}, 1000);npm install mqtt@5
ulimit -n 100000
MQTT_URL="mqtts://$MQTT_HOST:8883" node conn-stress.mjs 20000 300Um processo Node.js mantém tranquilamente alguns milhares de conexões ociosas; para mais, rode vários processos ou máquinas. Observe a CPU do gerador de carga — se estiver no máximo, seus números medem o cliente, não o broker. Para entender a resposta do broker a conexões recusadas, consulte o código do CONNACK na referência de reason codes.
Observe o lado do broker
Os contadores do cliente contam só metade da história. Em cada degrau, registre no host do broker:
ss -s # resumo de sockets
ss -tn state established '( sport = :1883 )' | wc -l
ps -o rss=,pcpu= -p "$(pgrep -d, mosquitto)" # memória (KB) e CPU do processo do brokerO Mosquitto também publica $SYS/broker/clients/connected; inscreva-se com o cliente online ou com mosquitto_sub -t '$SYS/broker/clients/connected' -v — veja tópicos $SYS do MQTT. Lembre-se de que o host do broker precisa da mesma folga de descritores de arquivo: para o Mosquitto com systemd, defina LimitNOFILE= em um drop-in do serviço e confira max_connections no mosquitto.conf (o gerador de configuração do Mosquitto cria uma base). Erros que aparecem só nos logs do broker são tratados em conexões demais.
A memória por conexão é fácil de calcular: (RSS com N conexões − RSS ocioso) ÷ N. Meça com e sem TLS e com o seu número real de inscrições, porque ambos mudam o resultado.
Simule uma tempestade de reconexões
Manter 50.000 clientes ociosos é a parte fácil. O momento perigoso é quando todos reconectam ao mesmo tempo — depois de um reinício do broker, de um failover do load balancer ou de uma oscilação de rede regional. É um teste simultâneo de taxa de conexão, capacidade de handshakes TLS e capacidade do backend de autenticação.
Duas formas de provocá-la no seu próprio broker:
- Reinicie o broker enquanto o script mantém as conexões e observe
connected=voltar a subir. - Corte a rede entre o gerador de carga e o broker por mais tempo que o keep-alive (por exemplo, com uma regra de iptables ou com o Toxiproxy) e depois restaure.
Registre quanto tempo leva para voltar ao total de conexões e quantas tentativas falharam no caminho. Com um intervalo de reconexão fixo, todos os clientes tentam no mesmo instante e o broker recebe ondas sincronizadas. O reconnectPeriod com jitter do script acima as espalha; compare as duas variantes e você verá por que as tempestades de reconexão são um problema de design do cliente tanto quanto de capacidade do broker.
Checklist do teste de estresse de conexões
- Aumente
ulimit -n, amplieip_local_port_rangee verifique o conntrack em cada máquina de carga. - Planeje os IPs de origem: cerca de 64.000 conexões por IP de origem por endpoint do broker.
- Reproduza a produção: TLS, keep-alive, autenticação e inscrições por cliente.
- Suba em degraus e mantenha cada um por vários intervalos de keep-alive.
- Registre conexões, memória, CPU e latência de conexão do broker em cada degrau.
- Provoque uma tempestade de reconexões e meça o tempo de recuperação.
- Repita após upgrades ou mudanças de configuração do broker.
Um teste de estresse de conexões é principalmente uma questão de honestidade: remova os limites do seu lado, imite o comportamento real dos clientes e force até que o broker — e não o gerador de carga — mostre onde está o teto. Depois planeje sua frota com folga abaixo dele e garanta que seus clientes reconectem com jitter, para que esse teto nunca seja testado por acidente.
Perguntas frequentes
Por que meu teste de conexões MQTT para em cerca de 28.000 clientes?
Normalmente é o gerador de carga ficando sem portas efêmeras: por padrão, o Linux usa cerca de 28.000 portas locais para conexões de um IP de origem para o mesmo IP e porta do broker. Amplie net.ipv4.ip_local_port_range ou adicione mais IPs de origem.
Quantas conexões um broker MQTT aguenta?
Depende do broker, da memória, da CPU, do TLS, do keep-alive e do tráfego de mensagens, então não existe um número universal. Meça: aumente as conexões registrando memória e CPU do broker e encontre o ponto em que a latência de conexão ou os erros sobem.
Posso fazer teste de estresse em um broker MQTT público?
Não. Abrir milhares de conexões em um broker público compartilhado o degrada para todos e fará você ser limitado ou bloqueado. Faça testes de estresse de conexões apenas em brokers seus ou em instâncias destinadas a isso.

