"Mensagens por segundo" é o número de MQTT mais citado e o mais mal compreendido. Um broker pode aceitar 50.000 msg/s dos publishers e ainda assim entregar só metade, ou entregar todas com dois segundos de atraso. Um teste de throughput MQTT útil mede a taxa que o sistema consegue sustentar — entrando e saindo — enquanto a latência fica estável e nada se perde, com os seus próprios payloads e estrutura de topics.
Este guia define os números, mostra como encontrar a taxa sustentável passo a passo e explica os sinais de backpressure que avisam quando você passou do limite. Para a visão geral de conexões e latência, veja teste de carga de broker MQTT.
Entrada, saída e fan-out
| Termo | Significado | Onde medir |
|---|---|---|
| Taxa de entrada (ingress) | Pacotes PUBLISH por segundo que o broker aceita dos publishers | Lado do publisher (enviados / confirmados) |
| Taxa de saída (egress) | Pacotes PUBLISH por segundo que o broker entrega aos subscribers | Lado do subscriber (recebidos) |
| Fator de fan-out | Número médio de subscribers por mensagem | Saída ÷ entrada |
| Taxa sustentável | Maior entrada em que a saída acompanha, a latência é estável e os erros ficam em zero | Os dois lados, por minutos |
O fator de fan-out é o que as pessoas esquecem. Um publisher a 1.000 msg/s com 20 subscribers no topic gera 20.000 msg/s de saída. O trabalho do broker se aproxima mais da saída do que da entrada, então sempre informe as duas. Para os casos extremos, veja o teste de fan-out e o teste de fan-in.
Throughput de pico vs sustentável
Todo sistema consegue absorver por um tempo uma rajada acima da capacidade real: buffers de socket, filas do cliente e do broker se enchem e escondem o problema. Um teste de cinco segundos mede esses buffers, não o broker. A taxa sustentável só aparece quando você mantém cada nível de carga por tempo suficiente para as filas atingirem um estado estável — normalmente alguns minutos.
O método é uma rampa em degraus:
- Comece com uma taxa que você tem certeza que o sistema aguenta (por exemplo, 20 % do pico esperado).
- Mantenha por 2–5 minutos e registre entrada, saída, latência p99 e erros.
- Aumente em um passo fixo (por exemplo +25 %) e mantenha de novo.
- Pare quando a saída deixar de acompanhar a entrada, a latência p99 continuar subindo dentro de um degrau ou surgirem erros.
- O último degrau limpo é a sua taxa sustentável. Planeje a produção com uma margem confortável abaixo dele.
No gráfico de taxa oferecida vs latência, você vê uma linha plana seguida de um "joelho" onde a latência se curva para cima. O joelho é o número que você procura — não a taxa máxima que o gerador de carga conseguiu empurrar.
Rodando a rampa com emqtt-bench
O emqtt-bench gera taxas altas a partir de uma só máquina. Inicie primeiro os subscribers e depois os publishers em taxas crescentes. O intervalo de publish -I é por cliente, em milissegundos, então a taxa total é clientes × 1000 / I:
docker run --rm -it emqx/emqtt-bench sub \
-h broker.connectmq.com -p 1883 \
-c 50 -t 'testmqtt/tput/%i' -q 1 \
-u "$MQTT_USER" -P "$MQTT_PASS"docker run --rm -it emqx/emqtt-bench pub \
-h broker.connectmq.com -p 1883 \
-c 50 -I 50 -t 'testmqtt/tput/%i' -s 256 -q 1 \
-u "$MQTT_USER" -P "$MQTT_PASS"Nos degraus seguintes, reduza -I (50 → 40 → 30 → 20 → 10 ms) ou adicione clientes. O emqtt-bench imprime as taxas enviadas e recebidas a cada segundo; copie-as para uma planilha por degrau. Como aqui cada publisher tem seu próprio subscriber, o fator de fan-out é 1 e a saída deve ser igual à entrada.
Uma sonda em Python para lacunas e atraso
Contadores de taxa escondem duas coisas: quais mensagens sumiram e quanto as outras atrasaram. Rode esta pequena sonda com paho-mqtt 2.x ao lado do benchmark. Ela publica mensagens numeradas e com timestamp a uma taxa modesta e informa lacunas e atraso a cada segundo; o atraso da sonda subindo enquanto o bench roda é o seu sinal de backpressure:
import json, time, uuid
import paho.mqtt.client as mqtt
HOST, PORT = "broker.connectmq.com", 1883
TOPIC = f"testmqtt/tput/probe-{uuid.uuid4().hex[:6]}"
RATE = 100 # mensagens de sonda por segundo
stats = {"n": 0, "last": -1, "gaps": 0, "lag": []}
def on_message(client, userdata, msg):
m = json.loads(msg.payload)
if m["i"] > stats["last"] + 1:
stats["gaps"] += m["i"] - stats["last"] - 1
stats["last"] = max(stats["last"], m["i"])
stats["n"] += 1
stats["lag"].append((time.perf_counter() - m["t"]) * 1000)
def client(name):
c = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2, client_id=f"{name}-{uuid.uuid4().hex[:6]}")
c.connect(HOST, PORT)
c.loop_start()
return c
sub = client("probe-sub")
sub.on_message = on_message
sub.subscribe(TOPIC, qos=1)
pub = client("probe-pub")
time.sleep(1)
i, next_report = 0, time.time() + 1
while True:
pub.publish(TOPIC, json.dumps({"i": i, "t": time.perf_counter()}), qos=1)
i += 1
time.sleep(1 / RATE)
if time.time() >= next_report:
lag = sorted(stats["lag"]) or [0]
print(f"rx {stats['n']:>5}/s gaps {stats['gaps']} "
f"lag p50 {lag[len(lag)//2]:.1f} ms p99 {lag[int(len(lag)*0.99)-1]:.1f} ms")
stats.update(n=0, lag=[])
next_report += 1Um único processo Python não vai gerar dezenas de milhares de mensagens por segundo — isso é trabalho da ferramenta de benchmark. A sonda é um termômetro, não um aquecedor.
Reconhecendo backpressure
O MQTT não tem um sinal global de controle de fluxo; o backpressure aparece como filas crescendo em algum lugar. Saiba onde olhar:
| Sinal | Onde fica | O que significa |
|---|---|---|
| A taxa enviada do publisher cai abaixo da meta | Janela inflight do cliente cheia (QoS 1/2) | Os PUBACKs voltam mais devagar do que você publica — o broker ou o caminho estão saturados |
| O atraso da sonda sobe sem parar durante um degrau | Fila do broker ou do subscriber | A saída não acompanha; você está acima da taxa sustentável |
| Lacunas na sonda em QoS 0 | Broker descartando mensagens para clientes lentos | Limite de fila atingido; o broker está descartando carga |
| Subscribers desconectados com erros de fila ou cota | Limites por cliente do broker | Veja fila de mensagens cheia e consumidores lentos |
| CPU do gerador de carga em 100 % | Sua máquina de teste | O resultado mede o cliente, não o broker |
Em QoS 1 e 2, a janela inflight é o limitador principal: um cliente só pode ter um certo número de mensagens não confirmadas (max_inflight_messages_set() no paho, Receive Maximum no MQTT 5). Com 20 mensagens em voo e um round trip de 50 ms, uma conexão fica perto de 400 msg/s, por mais rápido que seja o broker. É por isso que testes em links distantes parecem piores do que na mesma região, e por isso mais conexões — e não um loop mais rápido — elevam o teto. Receive Maximum e controle de fluxo explica o mecanismo.
De msg/s para largura de banda
Throughput também é um orçamento de rede. Um PUBLISH MQTT custa aproximadamente: cabeçalho fixo (2–5 bytes) + tamanho do topic + 2 bytes + identificador de pacote (2 bytes com QoS > 0) + propriedades MQTT 5 + payload. Some os cabeçalhos TCP/IP e, se houver, o overhead dos registros TLS. QoS 1 adiciona um PUBACK de 4 bytes na direção oposta.
Exemplo: payload de 256 bytes, topic de 20 bytes, QoS 1 → cerca de 285 bytes por PUBLISH antes do TCP/IP. A 5.000 msg/s de saída, isso dá cerca de 1,4 MB/s, ou aproximadamente 11–12 Mbit/s de tráfego MQTT antes do overhead de IP e TLS. Em mensagens pequenas o overhead domina, então agrupar leituras em uma só mensagem costuma aumentar o throughput efetivo mais do que qualquer ajuste no broker. A calculadora de tamanho de pacote faz a conta para o seu topic e payload exatos.
Documentando o resultado
Um resultado de throughput só é reutilizável se informar as condições. Registre no mínimo: versão e configuração do broker, QoS, tamanho do payload, número de topics, fator de fan-out, número de conexões publisher e subscriber, TLS ligado ou não, duração de cada degrau e região do gerador de carga. Depois informe as taxas sustentáveis de entrada e saída com a latência p99, não o pico. Ao comparar execuções mais tarde, interpretando resultados de benchmark cobre as armadilhas comuns.
Antes da rampa, faça um smoke test dos topics com o cliente MQTT online para confirmar credenciais e ACLs — um erro de permissão sob carga parece exatamente um problema de throughput.
Um teste de throughput é a busca pelo joelho, não uma corrida pelo maior número. Suba em degraus, mantenha cada degrau por tempo suficiente, observe atraso e lacunas em vez de só contadores e informe a saída junto com a entrada — esse é o número com que você pode planejar capacidade.
Perguntas frequentes
Qual é um bom número de throughput MQTT?
Não existe um número universal: depende do tamanho do payload, QoS, fan-out, TLS, persistência e hardware. O número útil é a maior taxa que o seu broker sustenta com o seu próprio padrão de tráfego enquanto a latência fica estável e nada se perde.
Por que a taxa recebida é menor que a enviada?
Ou as mensagens estão em fila em algum lugar (janelas inflight, filas do broker, buffers do cliente) ou estão sendo descartadas. Se a diferença cresce com o tempo, você está acima da taxa sustentável. Em QoS 0, uma diferença crescente geralmente significa perda.
O QoS afeta o throughput MQTT?
Sim. QoS 1 adiciona um PUBACK por mensagem e por salto, e QoS 2 adiciona três pacotes extras; ambos são limitados pela janela inflight. Espere taxas de pico menores com QoS mais alto, principalmente em links de alta latência.



