Pruebas de carga
Ya que Socket.IO tiene su propio protocolo, incluyendo handshake, heartbeats y codificación de paquetes personalizada, la forma más fácil de hacer pruebas de carga a tu servidor Socket.IO es usar la biblioteca cliente de Socket.IO y crear muchos clientes.
Hay dos soluciones clásicas para hacer esto:
Artillery
Artillery es una gran herramienta para hacer pruebas de carga a tu aplicación. Permite crear conexiones, enviar eventos y verificar acknowledgements.
La documentación se puede encontrar aquí.
Nota importante: la instalación predeterminada viene con un cliente v2, que no es compatible con un servidor v3/v4. Necesitas instalar un motor personalizado para esto: https://github.com/ptejada/artillery-engine-socketio-v3
Instalación:
$ npm install artillery artillery-engine-socketio-v3
Escenario de ejemplo:
# my-scenario.yml
config:
target: "http://localhost:3000"
phases:
- duration: 60
arrivalRate: 10
engines:
socketio-v3: {}
scenarios:
- name: Mi escenario de ejemplo
engine: socketio-v3
flow:
# esperar la actualización a WebSocket (opcional)
- think: 1
# emit básico
- emit:
channel: "hello"
data: "world"
# emitir un objeto
- emit:
channel: "hello"
data:
id: 42
status: "en progreso"
tags:
- "tag1"
- "tag2"
# emitir en un namespace personalizado
- namespace: "/my-namespace"
emit:
channel: "hello"
data: "world"
# emitir con acknowledgement
- emit:
channel: "ping"
acknowledge:
match:
value: "pong"
# no hacer nada por 30 segundos y luego desconectar
- think: 30
Para ejecutar este escenario:
$ npx artillery run my-scenario.yml
Artillery también viene con muchas características increíbles, como la capacidad de publicar las métricas a varios endpoints o ejecutar las pruebas desde AWS.
Su única limitación es que no puedes probar fácilmente eventos de servidor a cliente, ya que el DSL de Artillery está más orientado a la comunicación clásica de cliente a servidor. Lo que nos lleva a nuestra siguiente sección.
Creación manual de clientes
Aquí hay un script básico para crear mil clientes Socket.IO y monitorear el número de paquetes recibidos por segundo:
const { io } = require("socket.io-client");
const URL = process.env.URL || "http://localhost:3000";
const MAX_CLIENTS = 1000;
const POLLING_PERCENTAGE = 0.05;
const CLIENT_CREATION_INTERVAL_IN_MS = 10;
const EMIT_INTERVAL_IN_MS = 1000;
let clientCount = 0;
let lastReport = new Date().getTime();
let packetsSinceLastReport = 0;
const createClient = () => {
// para fines de demostración, algunos clientes permanecen atascados en HTTP long-polling
const transports =
Math.random() < POLLING_PERCENTAGE ? ["polling"] : ["polling", "websocket"];
const socket = io(URL, {
transports,
});
setInterval(() => {
socket.emit("evento de cliente a servidor");
}, EMIT_INTERVAL_IN_MS);
socket.on("evento de servidor a cliente", () => {
packetsSinceLastReport++;
});
socket.on("disconnect", (reason) => {
console.log(`desconectado debido a ${reason}`);
});
if (++clientCount < MAX_CLIENTS) {
setTimeout(createClient, CLIENT_CREATION_INTERVAL_IN_MS);
}
};
createClient();
const printReport = () => {
const now = new Date().getTime();
const durationSinceLastReport = (now - lastReport) / 1000;
const packetsPerSeconds = (
packetsSinceLastReport / durationSinceLastReport
).toFixed(2);
console.log(
`cantidad de clientes: ${clientCount} ; promedio de paquetes recibidos por segundo: ${packetsPerSeconds}`
);
packetsSinceLastReport = 0;
lastReport = now;
};
setInterval(printReport, 5000);
Puedes usarlo como punto de partida para hacer pruebas de carga a tu propia aplicación.