As bancadas
Data: 24 de julho de 2026 · Protocolo: MQTT 3.1.1 · Ferramenta: cliente de carga próprio cmd/loadtest construído sobre o codec do projeto, sem bibliotecas MQTT de terceiros.
Os testes foram feitos em duas bancadas para separar o comportamento do próprio broker da influência do ambiente: rede contra loopback, hardware modesto contra hardware potente.
| Bancada A — pela rede | Bancada B — loopback | |
|---|---|---|
| Processador do broker | 12 núcleos | 2× Xeon E5-2690 v4 a 2,6 GHz (28 núcleos / 56 threads) |
| Memória do broker | 16 GB | 128 GB |
| Endereço | 192.168.1.84:1883 (LAN) | 127.0.0.1:1883 (loopback) |
| Gerador de carga | Máquina separada na LAN | A mesma máquina do broker |
| Portas efêmeras do cliente | 16 384 (padrão) | 55 000 (ampliado) |
Resumo executivo
- Latência. Pela rede, a latência ponta a ponta «publicador → broker → assinante» sob carga normal fica em torno de 1 ms; por loopback é de 73 µs (~16 vezes menor, sem a rede).
- Conexões. Pela rede o broker sustentou 10 000 sessões sem falhas (além disso esbarramos no limite de portas do cliente). Em hardware potente por loopback: 30 000 sem falhas e ~41 000 numa tentativa de 50 000 (o limite de uma única máquina, não do broker).
- Ingestão. O pico pela rede foi de ≈277 000 mensagens/s; por loopback a ingestão é menor (≈185 000/s) porque o gerador disputa núcleos com o broker.
- Leque (roteamento). Em hardware potente o broker entregou ≈1 350 000 mensagens/s aos assinantes (leque ×100) contra ≈22 000/s pela rede.
- Robustez. Em nenhuma bancada o broker travou ou caiu. Em sobrecarga, mensagens QoS 0 destinadas a assinantes atrasados são descartadas de forma ordenada; o log do broker não contém um único erro em todas as execuções.
Capacidade de conexões simultâneas
Cada conexão é um ciclo completo CONNECT → CONNACK com autenticação; depois a sessão é mantida aberta (verificada com PINGREQ).
Bancada A — pela rede
| Alvo | Estabelecidas | Falhas | Estabelecimento p50 | p99 |
|---|---|---|---|---|
| 10 | 10 | 0 | 146 ms | 162 ms |
| 100 | 100 | 0 | 702 ms | 1,12 s |
| 1000 | 1000 | 0 | 4,21 s | 9,78 s |
| 5000 | 5000 | 0 | 4,64 s | 8,59 s |
| 10 000 | 10 000 | 0 | 4,92 s | 10,52 s |
| 15 000 | 14 879 | 121 | 7,43 s | 14,09 s |
Bancada B — loopback (subida gradual)
| Alvo | Estabelecidas | Falhas | Estabelecimento p50 | p99 |
|---|---|---|---|---|
| 1000 | 1000 | 0 | 886 ms | 1,06 s |
| 10 000 | 10 000 | 0 | 903 ms | 1,55 s |
| 30 000 | 30 000 | 0 | 923 ms | 1,90 s |
| 50 000 | 41 219 | 0 | 984 ms | 1,90 s |
Análise
- Pela rede, até 10 000 sem uma única falha; as 121 falhas em 15 000 são esgotamento das portas efêmeras do cliente (16 384). É o limite do gerador, não do broker.
- Por loopback, depois de ampliar a faixa de portas, o broker sustentou 30 000 sessões sem defeito; em 50 000 restavam vivas cerca de 41 000 ao fim do período de retenção — os dois lados dividem uma máquina. O log do broker permaneceu limpo o tempo todo, sem erros.
- Achado lateral. Por loopback, uma rajada de conexões brusca demais (1000
dials simultâneos) provocaconnection refused: a fila de aceitação transborda, porque sem atraso de rede todos os SYN chegam ao mesmo tempo. Uma subida gradual (200 por vez) elimina o efeito por completo. Em uma rede, a latência suaviza a rajada sozinha.
Vazão de ingestão
Um conjunto de publicadores publica o mais rápido possível; mede-se a taxa de ingestão do broker.
QoS 0 · payload de 64 bytes
| Publicadores | Bancada A (rede) | Bancada B (loopback) |
|---|---|---|
| 10 | 271 006/s | 185 012/s |
| 100 | 236 422/s | 101 457/s |
| 500 | 103 546/s | 125 324/s |
A ingestão é maior pela rede — não porque o broker da bancada A seja mais rápido, mas porque ali o gerador roda em uma máquina separada. Por loopback, cliente e broker dividem os mesmos núcleos, o que limita a taxa conjunta.
QoS 1 (com confirmação PUBACK) · 64 B
| Publicadores | Bancada A (rede) | Bancada B (loopback) |
|---|---|---|
| 10 | 10 292/s | 63 606/s |
| 100 | 22 085/s | 48 983/s |
O cliente de teste de QoS 1 é síncrono (espera um PUBACK depois de cada mensagem), então fica preso ao tempo de ida e volta. Por loopback esse tempo é quase nulo, daí o ganho de cerca de 6 vezes. Isso mostra com clareza que os números de QoS 1 são ditados pela latência de rede, não pelo broker.
Varredura de tamanhos de mensagem · QoS 0 · 50 publicadores
| Tamanho | Bancada A (rede) | Bancada B (loopback) |
|---|---|---|
| 64 B | 277 198/s · 17,7 MB/s | 101 961/s · 6,5 MB/s |
| 256 B | 124 997/s · 32,0 MB/s | 102 029/s · 26,1 MB/s |
| 1024 B | 38 458/s · 39,4 MB/s | 102 151/s · 104,6 MB/s |
Dois tetos diferentes:
- Pela rede esbarramos no enlace por volta de 40 MB/s: quando a mensagem cresce, as msg/s caem enquanto os MB/s ficam perto do limite.
- Por loopback o enlace é enorme, então a contagem de mensagens se mantém (~102 000/s com 50 conexões) e o volume sobe para 104,6 MB/s. Aqui o gargalo é o processamento por mensagem (CPU), não os bytes.
Entrega ponta a ponta
Um carimbo de tempo é embutido no corpo da mensagem; medem-se a entrega real e a latência ponta a ponta. Leque significa entrega a cada assinante cujo filtro corresponda.
Bancada A — pela rede
| Cenário | Publicação | Entrega | média / p50 / p99 |
|---|---|---|---|
| 10 ass. / 10 pub. / 100 msg/s — normal | 986/s | 9863/s | 1,17 / 1,0 / 3,6 ms |
| 100 ass. / 10 pub. / sem freio | 261 551/s | 22 351/s | 780 / 453 / 678 ms |
| 100 ass. / 10 pub. / 500 msg/s | 4934/s | 12 150/s | 1,87 / 1,77 / 2,83 s |
| 1000 ass. / 5 pub. / 100 msg/s | 494/s | 178 961/s | 2,29 s / 480 / 952 ms |
Bancada B — loopback
| Cenário | Publicação | Entrega | média / p50 / p99 |
|---|---|---|---|
| 10 ass. / 10 pub. / 100 msg/s — normal | 987/s | 9867/s | 73 / ~0 / 555 µs |
| 100 ass. / 10 pub. / sem freio | 47 557/s | 1 353 431/s | 514 / 135 / 251 ms |
| 100 ass. / 10 pub. / 500 msg/s | 3608/s | 360 834/s | 17,1 / 10,5 / 71,6 ms |
| 1000 ass. / 5 pub. / 100 msg/s | 494/s | 183 746/s | 4,73 / 4,54 / 15,1 ms |
Análise
- Latência sob carga normal: 1,17 ms pela rede contra 73 µs por loopback. A diferença é o trajeto de rede.
- Roteamento sob carga: a máquina potente entregou ≈1,35 milhão de mensagens/s aos assinantes (leque ×100) — duas ordens de grandeza acima da bancada de rede (22 mil/s), onde tanto o broker quanto o enlace são pequenos.
- Em cenários de leque grande o gerador também vira gargalo (todos os assinantes em um processo e uma máquina), então os picos de entrega são um piso do que o broker consegue fazer.
Frente a frente
| Indicador | Bancada A — rede (12 núcleos) | Bancada B — loopback (28 núcleos) |
|---|---|---|
| Conexões sem falhas | 10 000 | 30 000 |
| Pico de conexões | 14 879 (limite do cliente) | ~41 000 (limite de uma máquina) |
| Ingestão QoS 0 (64 B), pico | 271 006/s | 185 012/s |
| Ingestão QoS 1 (64 B), pico | 22 085/s | 63 606/s |
| Teto de volume | ≈40 MB/s (enlace) | ≈105 MB/s (CPU) |
| Latência (normal), mediana | 1,0 ms | ~0 (73 µs em média) |
| Entrega com leque, pico | 22 351/s | 1 353 431/s |
| Erros no log do broker | nenhum | nenhum |
Ressalvas metodológicas
- A taxa de ingestão não é diretamente comparável entre as bancadas: na bancada B gerador e broker dividem núcleos; na bancada A o gerador é uma máquina separada.
- Em cada bancada a carga vem de uma única máquina cliente; em alguns cenários (leque grande, dezenas de milhares de conexões) o gargalo é essa máquina e não o broker.
- O cliente de teste de QoS 1 é síncrono — os números de QoS 1 subestimam o potencial do broker.
- As métricas de sistema do broker (CPU e memória durante as execuções) não foram coletadas; o estado do servidor é inferido do log dele (sem erros) e do comportamento do lado cliente.
Reproduzir
Cada execução parte de um único binário loadtest; abaixo estão os comandos dos três modos.
go build -o loadtest ./cmd/loadtest
# Capacidade de conexões (subida gradual contra a fila de aceitação)
./loadtest -addr HOST:1883 -user myelx -pass *** \
-mode conn -levels 1000,10000,30000,50000 -hold 3s -dial-concurrency 200
# Vazão de ingestão
./loadtest -addr HOST:1883 -user myelx -pass *** \
-mode pub -pubs 10 -qos 0 -payload 64 -duration 10s
# Entrega ponta a ponta e latência
./loadtest -addr HOST:1883 -user myelx -pass *** \
-mode pubsub -subs 10 -pubs 10 -qos 0 -rate 100 -payload 64 -duration 10s