Los bancos
Fecha: 24 de julio de 2026 · Protocolo: MQTT 3.1.1 · Herramienta: cliente de carga propio cmd/loadtest construido sobre el códec del proyecto, sin bibliotecas MQTT de terceros.
Se probó en dos bancos para separar el comportamiento propio del broker de la influencia del entorno: red frente a bucle local, hardware modesto frente a hardware potente.
| Banco A — por red | Banco B — bucle local | |
|---|---|---|
| Procesador del broker | 12 núcleos | 2× Xeon E5-2690 v4 a 2,6 GHz (28 núcleos / 56 hilos) |
| Memoria del broker | 16 GB | 128 GB |
| Dirección | 192.168.1.84:1883 (LAN) | 127.0.0.1:1883 (bucle local) |
| Generador de carga | Máquina aparte en la LAN | La misma máquina que el broker |
| Puertos efímeros del cliente | 16 384 (por defecto) | 55 000 (ampliado) |
Resumen ejecutivo
- Latencia. Por red, la latencia de extremo a extremo «publicador → broker → suscriptor» con carga normal ronda 1 ms; por bucle local es de 73 µs (~16 veces menos, sin la red).
- Conexiones. Por red el broker mantuvo 10 000 sesiones sin fallos (más allá topamos con el límite de puertos del cliente). En hardware potente por bucle local: 30 000 sin fallos y ~41 000 en un intento de 50 000 (el límite de una sola máquina, no del broker).
- Ingesta. El pico por red fue de ≈277 000 mensajes/s; por bucle local la ingesta es menor (≈185 000/s) porque el generador compite con el broker por los núcleos.
- Abanico (encaminamiento). En hardware potente el broker entregó ≈1 350 000 mensajes/s a los suscriptores (abanico ×100) frente a ≈22 000/s por red.
- Robustez. En ningún banco el broker se cayó ni se quedó colgado. En sobrecarga, los mensajes QoS 0 hacia suscriptores rezagados se descartan de forma ordenada; el registro del broker no contiene ni un solo error en todas las pruebas.
Capacidad de conexiones simultáneas
Cada conexión es un ciclo completo CONNECT → CONNACK con autenticación; después la sesión se mantiene abierta (comprobada con PINGREQ).
Banco A — por red
| Objetivo | Establecidas | Fallidas | Establecimiento 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 |
Banco B — bucle local (subida gradual)
| Objetivo | Establecidas | Fallidas | Establecimiento 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álisis
- Por red, hasta 10 000 sin un solo fallo; los 121 fallos a 15 000 son agotamiento de los puertos efímeros del cliente (16 384). Es el límite del generador, no del broker.
- Por bucle local, tras ampliar el rango de puertos, el broker mantuvo 30 000 sesiones sin defecto; a 50 000 quedaban vivas unas 41 000 al final del periodo de retención, porque ambos lados comparten una máquina. El registro del broker se mantuvo limpio en todo momento, sin errores.
- Hallazgo lateral. Por bucle local, una ráfaga de conexiones demasiado brusca (1000
dials simultáneos) provocaconnection refused: la cola de aceptación se desborda, porque sin retardo de red todos los SYN llegan a la vez. Una subida gradual (200 cada vez) elimina el efecto por completo. En una red, la latencia suaviza la ráfaga por sí sola.
Rendimiento de ingesta
Un conjunto de publicadores publica lo más rápido posible; se mide el ritmo de ingesta del broker.
QoS 0 · carga útil de 64 bytes
| Publicadores | Banco A (red) | Banco B (bucle local) |
|---|---|---|
| 10 | 271 006/s | 185 012/s |
| 100 | 236 422/s | 101 457/s |
| 500 | 103 546/s | 125 324/s |
La ingesta es mayor por red, no porque el broker del banco A sea más rápido, sino porque allí el generador corre en una máquina aparte. Por bucle local, cliente y broker comparten los mismos núcleos, lo que limita el ritmo conjunto.
QoS 1 (con confirmación PUBACK) · 64 B
| Publicadores | Banco A (red) | Banco B (bucle local) |
|---|---|---|
| 10 | 10 292/s | 63 606/s |
| 100 | 22 085/s | 48 983/s |
El cliente de prueba de QoS 1 es síncrono (espera un PUBACK tras cada mensaje), así que queda limitado por el ida y vuelta. Por bucle local ese ida y vuelta es casi nulo, de ahí la mejora de unas 6 veces. Esto muestra con claridad que las cifras de QoS 1 las fija la latencia de red, no el broker.
Barrido de tamaños de mensaje · QoS 0 · 50 publicadores
| Tamaño | Banco A (red) | Banco B (bucle local) |
|---|---|---|
| 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 |
Dos techos distintos:
- Por red topamos con el enlace en torno a 40 MB/s: al crecer el mensaje, los msg/s caen mientras los MB/s se mantienen cerca del límite.
- Por bucle local el enlace es enorme, así que el número de mensajes se mantiene (~102 000/s con 50 conexiones) y el volumen sube a 104,6 MB/s. Aquí el cuello de botella es el procesamiento por mensaje (procesador), no los bytes.
Entrega de extremo a extremo
Se incrusta una marca de tiempo en el cuerpo del mensaje; se mide la entrega real y la latencia de extremo a extremo. Abanico significa entrega a cada suscriptor cuyo filtro coincida.
Banco A — por red
| Escenario | Publicación | Entrega | media / p50 / p99 |
|---|---|---|---|
| 10 sus. / 10 pub. / 100 msg/s — normal | 986/s | 9863/s | 1,17 / 1,0 / 3,6 ms |
| 100 sus. / 10 pub. / sin freno | 261 551/s | 22 351/s | 780 / 453 / 678 ms |
| 100 sus. / 10 pub. / 500 msg/s | 4934/s | 12 150/s | 1,87 / 1,77 / 2,83 s |
| 1000 sus. / 5 pub. / 100 msg/s | 494/s | 178 961/s | 2,29 s / 480 / 952 ms |
Banco B — bucle local
| Escenario | Publicación | Entrega | media / p50 / p99 |
|---|---|---|---|
| 10 sus. / 10 pub. / 100 msg/s — normal | 987/s | 9867/s | 73 / ~0 / 555 µs |
| 100 sus. / 10 pub. / sin freno | 47 557/s | 1 353 431/s | 514 / 135 / 251 ms |
| 100 sus. / 10 pub. / 500 msg/s | 3608/s | 360 834/s | 17,1 / 10,5 / 71,6 ms |
| 1000 sus. / 5 pub. / 100 msg/s | 494/s | 183 746/s | 4,73 / 4,54 / 15,1 ms |
Análisis
- Latencia con carga normal: 1,17 ms por red frente a 73 µs por bucle local. La diferencia es el trayecto de red.
- Encaminamiento bajo carga: la máquina potente entregó ≈1,35 millones de mensajes/s a los suscriptores (abanico ×100), dos órdenes de magnitud por encima del banco de red (22 mil/s), donde tanto el broker como el enlace son pequeños.
- En escenarios de gran abanico el generador se convierte también en cuello de botella (todos los suscriptores en un proceso y una máquina), así que las cifras pico de entrega son una cota inferior de lo que el broker puede dar.
Cara a cara
| Indicador | Banco A — red (12 núcleos) | Banco B — bucle local (28 núcleos) |
|---|---|---|
| Conexiones sin fallos | 10 000 | 30 000 |
| Pico de conexiones | 14 879 (límite del cliente) | ~41 000 (límite de una máquina) |
| Ingesta QoS 0 (64 B), pico | 271 006/s | 185 012/s |
| Ingesta QoS 1 (64 B), pico | 22 085/s | 63 606/s |
| Techo de volumen | ≈40 MB/s (enlace) | ≈105 MB/s (procesador) |
| Latencia (normal), mediana | 1,0 ms | ~0 (73 µs de media) |
| Entrega con abanico, pico | 22 351/s | 1 353 431/s |
| Errores en el registro del broker | ninguno | ninguno |
Salvedades metodológicas
- El ritmo de ingesta no es directamente comparable entre bancos: en el banco B generador y broker comparten núcleos; en el banco A el generador es una máquina aparte.
- En cada banco la carga procede de una sola máquina cliente; en algunos escenarios (gran abanico, decenas de miles de conexiones) el cuello de botella es esa máquina y no el broker.
- El cliente de prueba de QoS 1 es síncrono, así que las cifras de QoS 1 subestiman el potencial del broker.
- No se registraron las métricas de sistema del broker (procesador y memoria durante las pruebas); el estado del servidor se deduce de su registro (sin errores) y del comportamiento del lado cliente.
Reproducir
Cada prueba se lanza desde un único binario loadtest; abajo están las órdenes de los tres modos.
go build -o loadtest ./cmd/loadtest
# Capacidad de conexiones (subida gradual frente a la cola de aceptación)
./loadtest -addr HOST:1883 -user myelx -pass *** \
-mode conn -levels 1000,10000,30000,50000 -hold 3s -dial-concurrency 200
# Rendimiento de ingesta
./loadtest -addr HOST:1883 -user myelx -pass *** \
-mode pub -pubs 10 -qos 0 -payload 64 -duration 10s
# Entrega de extremo a extremo y latencia
./loadtest -addr HOST:1883 -user myelx -pass *** \
-mode pubsub -subs 10 -pubs 10 -qos 0 -rate 100 -payload 64 -duration 10s