---
title: "Pruebas de carga WebSocket con k6: conexiones, heartbeats y backpressure"
description: "Pruebas de carga WebSocket con k6: conexiones concurrentes, heartbeats, backpressure—docs API WebSocket k6 más patrones de emparejamiento REST."
publishDate: "2026-06-18"
draft: false
keyword: "pruebas carga k6 websocket"
intent: "MOFU"
cta: "Usa Performate para convertir este playbook en escenarios k6 ejecutables, umbrales y reportes compartibles sin perder días en código de integración."
tags: ["k6", "pruebas-de-carga", "rendimiento-api", "websocket"]
translationOf: k6-websocket-load-testing-connections
---

Tu dashboard REST muestra `p99` verde en 120 ms, pero el chat en vivo se cae a los 2 000 usuarios conectados porque nadie stress-testeó **sockets concurrentes**—solo el POST de login que entrega el token. El reverse proxy tiene `worker_connections` para 1 024; el backend asume heartbeats cada 30 s; y el reconnect replay dispara un thundering herd que tumba Redis.

El protocolo WebSocket ([RFC 6455](https://www.rfc-editor.org/rfc/rfc6455)) hace upgrade de HTTP a un canal bidireccional. La carga se mide en **sockets concurrentes**, **mensajes/seg** y **churn de reconexión**—no solo en [`http_req_duration`](https://k6.io/docs/using-k6/metrics/) de llamadas REST. En esta guía verás dimensiones de estrés, un escenario k6 con el [módulo WebSocket experimental](https://k6.io/docs/javascript-api/k6-experimental/websockets/), y cómo emparejar fases HTTP + WS con realismo.

## Por qué WebSocket cambia el perfil de carga—no solo el transporte

A nivel funcional, REST y WS comparten auth. Bajo concurrencia, ejercitan recursos distintos:

- **Fan-out de conexiones** — cada socket consume FD en proxy, LB y app; superar `worker_connections` encuentra techos antes que CPU.
- **Heartbeats + idle** — ping/pong desalineados o timeouts idle del proxy crean caídas silenciosas—not errores HTTP visibles.
- **Burst tras reconnect** — clientes replay suscripciones; servidores deben sobrevivir thundering herds post-deploy.
- **Backpressure** — publicar más rápido de lo que el consumer procesa llena buffers—not lo captura latencia REST.

Piensa en medir un call center solo contando emails mientras 5 000 líneas telefónicas simultáneas son el cuello real.

### Cuando REST-only load tests pasan pero el realtime falla

La mayoría de productos intercalan REST y sockets—login HTTP, luego feed WS. Corre escenarios mixtos para que pools de conexión y tokens interactúen con realismo ([plantilla script mínimo](/es/blog/plantilla-script-k6-minimo-apis)). Etiqueta feeds lógicos con [tags de observabilidad](/es/blog/k6-observabilidad-metricas-tags). Si server→client basta sin bidireccional, compara con [SSE y long-polling](/es/blog/pruebas-carga-sse-long-polling-k6).

## Implementación práctica con k6: conexión, subscribe y heartbeat

Modela conexión WS tras auth REST, suscripción a un feed, ping periódico y cierre limpio. Coordina socket storms en staging compartido ([ética de pruebas](/es/blog/ddos-vs-etica-pruebas-de-carga)).

**Script de ejemplo (ilustrativo—no es una prueba lista para producción).** Usa API experimental de WebSocket; adapta URLs, intervals y payloads.

**Qué demuestra este ejemplo:**

- **Fase REST previa:** obtiene token antes del upgrade WS—como clientes reales.
- **Conexión + subscribe:** envía frame de suscripción tras `open`.
- **Heartbeat:** ping cada 25 s alineado a keepalive de prod.
- **Tags por feed:** `feed:orders` segmenta métricas en summary y APM.

```javascript
import http from 'k6/http';
import { check, sleep } from 'k6';
import ws from 'k6/experimental/websockets';

const BASE_HTTP = __ENV.API_BASE || 'https://staging.example.com';
const BASE_WS = __ENV.WS_BASE || 'wss://staging.example.com';
const FEED = 'orders';

export const options = {
  scenarios: {
    ws_connections: {
      executor: 'ramping-vus',
      startVUs: 0,
      stages: [
        { duration: '2m', target: 100 },
        { duration: '5m', target: 500 },
        { duration: '2m', target: 500 },
        { duration: '1m', target: 0 },
      },
      exec: 'wsSession',
      tags: { protocol: 'websocket' },
    },
  },
  thresholds: {
    http_req_failed: ['rate<0.01'],
    ws_connecting: ['p(95)<2000'],
    ws_msgs_received: ['count>0'],
  },
};

export function wsSession() {
  const login = http.post(
    `${BASE_HTTP}/v1/auth/token`,
    JSON.stringify({ clientId: 'load-bot' }),
    { headers: { 'Content-Type': 'application/json' }, tags: { route: 'auth' } }
  );
  check(login, { 'auth ok': (r) => r.status === 200 });
  const token = login.json('accessToken');

  const url = `${BASE_WS}/v1/ws?token=${token}`;
  const res = ws.connect(url, { tags: { feed: FEED } }, (socket) => {
    socket.on('open', () => {
      socket.send(JSON.stringify({ action: 'subscribe', feed: FEED }));
    });

    socket.on('message', (data) => {
      check(data, { 'message received': (d) => d.length > 0 });
    });

    socket.setInterval(() => {
      socket.ping();
    }, 25000);

    socket.setTimeout(() => {
      socket.close();
    }, 120000);
  });

  check(res, { 'ws connected': (r) => r && r.status === 101 });
  sleep(1);
}
```

**Patrones que funcionan**

- **Ramp gradual de conexiones** — encuentra `worker_connections` antes del cliff.
- **Keepalive = prod** — replica intervalos ping/pong y proxy idle timeouts.
- **Escenario mixto REST+WS** — auth, REST setup, luego socket en la misma VU.
- **Reconnect churn** — escenario separado que cierra y reabre sockets en ráfaga post-ramp.

**Anti-patrones a evitar**

- Medir solo REST cuando el incidente es fan-out de sockets.
- Abrir 10 000 conexiones instantáneas en staging compartido sin ventana acordada.
- Ignorar FD limits en el generador de carga—el benchmark miente si k6 es el cuello.

**Tip pro (comando de ejemplo):**

```bash
k6 run ws-load.js -e API_BASE=https://staging.example.com -e WS_BASE=wss://staging.example.com
```

**Qué demuestra este comando:** variables separadas para HTTP y WS—patrón común cuando el upgrade host difiere del API REST.

## Marco de decisión: qué dimensionar primero

| Situación | Acción recomendada |
|:---|:---|
| Producto nuevo realtime | Ramp de conexiones; encuentra techo de proxy/LB |
| Incidente post-deploy | Escenario reconnect burst + replay subscribe |
| Caídas silenciosas tras idle | Alinear heartbeat a prod; probar timeout proxy |
| Gaming / trading bursts | Mensajes/seg + backpressure, no solo conexiones |
| Solo server→client | Evaluar [SSE/long-polling](/es/blog/pruebas-carga-sse-long-polling-k6) antes de WS |

**Dimensiona conexiones primero si** el síntoma es « too many open files » o L4 limits.

**Dimensiona heartbeats si** las caídas correlacionan con idle, no con CPU.

**Dimensiona reconnect si** deploys o network blips disparan thundering herds.

## Observabilidad, documentación y siguientes pasos

Las pruebas WS solo sirven si documentas límites y coordinación. Antes de escalar sockets:

- [ ] Documenta `worker_connections`, FD limits en generators y expectativas de ephemeral ports.
- [ ] Coordina ventana con platform en staging compartido ([ética](/es/blog/ddos-vs-etica-pruebas-de-carga)).
- [ ] Correlaciona tags `feed:*` en k6 con traces APM por canal lógico.
- [ ] Registra intervalos ping/pong de prod en el README del escenario.
- [ ] Archiva summary con `ws_connecting` y conteos de mensajes por release.

## Cómo Performate simplifica journeys REST + WebSocket

Mantener auth REST en un script y WS en otro produce drift. Abajo hay un **ejemplo concreto de flujo** para feed de orders—adapta feeds y payloads a tu producto.

**Ejemplo: login REST → subscribe WS → heartbeat en un workspace**

1. **Importa requests REST** (auth token) y define URL WS en variables de entorno. *Problema resuelto:* pre-step HTTP y socket en un journey visible para PM.
2. **Crea escenario ramping-vus** 100→500 conexiones con stages graduales. *Problema resuelto:* fan-out realista sin script WS aislado.
3. **Configura payload de subscribe** y tag `feed:orders` en el panel. *Problema resuelto:* segmentación alineada al ejemplo k6.
4. **Define intervalo heartbeat 25 s** en el flujo visual—match prod keepalive. *Problema resuelto:* caídas idle detectables antes de prod.
5. **Corre y compara** métricas WS vs REST en reporte integrado—detecta si auth REST es el cuello previo al upgrade. *Problema resuelto:* un export para backend y platform.
6. **Exporta script k6** con módulo experimental WS para nightly ([CI/CD](/es/blog/pruebas-de-carga-en-ci-cd)).

Ese flujo conecta directo con el `cta` de este post: escenarios ejecutables sin días de código de integración REST+WS.

## Cierre

El riesgo realtime es un **problema de conexiones y churn**, no solo de latencia REST. Stress-testea sockets concurrentes, heartbeats alineados a prod y bursts de reconnect—etiquetados por feed—antes del próximo launch que promete « live » en el hero.

Corre una rampa a 500 conexiones en staging esta semana—and anota en qué stage apareció el primer timeout de proxy o FD limit.

[Try Performate free](https://performate.app) | [Book a demo](/demo) | [k6 WebSocket docs](https://k6.io/docs/javascript-api/k6-experimental/websockets/)
