---
title: "HTTP/2 y HTTP/3 bajo carga: qué cambia en latencia, errores y costo TLS"
description: "Pruebas de carga HTTP/2 vs HTTP/3: multiplexación, QUIC, costos TLS y comparaciones honestas en k6—notas de evolución MDN y métricas HTTP de Grafana k6."
publishDate: "2026-08-31"
draft: false
keyword: "pruebas carga http2 http3 latencia"
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", "http3"]
translationOf: http2-http3-load-testing-latency
---

HTTP/3 recortó 20 ms en un slide de laboratorio—y luego las colas en producción empeoraron porque buffers UDP, cadenas de certificados y PoPs de CDN no se mantuvieron constantes. Los benchmarks de protocolo se vuelven arqueología operativa si no congelas política TLS, tamaños de payload y geografía.

HTTP/2 multiplexa muchas peticiones sobre una conexión TCP; **HTTP/3** mueve el transporte a QUIC (basado en UDP) y suele mejorar el **head-of-line blocking** a costa de perfiles distintos de CPU y handshake ([Evolution of HTTP](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Guides/Basics_of_HTTP/Evolution_of_HTTP), [RFC 9114](https://www.rfc-editor.org/rfc/rfc9114) visión general de QUIC para HTTP/3). Para equipos de API, la pregunta no es qué logo de RFC gana sino **qué stack negocian tu edge y tus clientes** bajo la política de certificados y cifrados de producción. Esta guía muestra cómo comparar H2 y H3 con honestidad en k6, qué modos de fallo difieren por protocolo y cuándo escalar colas vs tasa de error.

Combina experimentos con [comportamiento de caché CDN](/es/blog/pruebas-carga-cdn-cache-headers) y [pruebas geo-distribuidas](/es/blog/pruebas-de-carga-distribuidas-geo) cuando los edges terminan stacks por región.

## Por qué los cambios de protocolo mueven colas—no solo promedios

Bajo carga, las diferencias aparecen en:

- **Setup de conexión** — handshakes QUIC vs reutilización TCP+TLS; cold starts exageran latencia de primer byte.
- **Paths con pérdida** — HTTP/3 puede reducir head-of-line blocking en redes móviles; labs LAN quizá no muestran ganancia.
- **Middleboxes** — filtrado UDP causa resets que HTTP/2 no vio en el mismo path.
- **CPU del servidor** — cifrado y stacks QUIC en user-space desplazan costo de espera en kernel a quema de CPU.

Los promedios ocultan esos efectos. Compara `p95`/`p99` con RPS idéntico ([p95 vs p99](/es/blog/p95-vs-p99-latencia)) y etiqueta corridas `proto:h2` vs `proto:h3` ([tags and groups](https://k6.io/docs/using-k6/tags-and-groups/)).

**k6 no reemplaza captura de paquetes.** Usa pruebas de carga para cuantificar latencia visible al usuario y presupuestos de error bajo RPS sostenido; usa pcaps o logs de edge cuando necesites probar drops UDP en middleboxes o tormentas de renegociación TLS. El script anterior sirve para gates de regresión, no para certificación de conformidad RFC.

### Cuando una «victoria» de protocolo es deriva de configuración

Cambiar publicidad ALPN sin actualizar límites `udp` del kernel o `max_open_files` en generadores produce regresiones falsas ([fine-tuning OS](https://k6.io/docs/misc/fine-tuning-os/)). Documenta cambios de infra junto a toggles de protocolo para que los reportes sigan comparables.

## Implementación práctica con k6: escenarios de protocolo etiquetados

k6 registra [`http_req_duration`](https://k6.io/docs/using-k6/metrics/) y tiempos relacionados—compara corridas solo si congelas cadena de certificados, política TLS, tamaños de payload y comportamiento del PoP CDN.

**Script de ejemplo (ilustrativo—no listo para producción).** Los endpoints deben exponer H2 y H3 en tu infra; hosts ficticios.

**Qué demuestra este ejemplo:**

- **Escenarios paralelos** golpeando URLs solo-H2 y capaces-H3 (o alias de host) al mismo RPS.
- **Tags de protocolo** para umbrales segmentados.
- **Payload y headers idénticos** para que compresión y auth coincidan.
- **Umbrales de fallos y colas** por protocolo, no una línea agregada.

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

const H2_BASE = __ENV.H2_BASE || 'https://h2.staging.example.com';
const H3_BASE = __ENV.H3_BASE || 'https://h3.staging.example.com';
const BODY = JSON.stringify({ query: 'latency-probe', size: 'medium' });

export const options = {
  scenarios: {
    proto_h2: {
      executor: 'constant-arrival-rate',
      rate: Number(__ENV.TARGET_RPS || 80),
      timeUnit: '1s',
      duration: '8m',
      preAllocatedVUs: 30,
      maxVUs: 120,
      tags: { proto: 'h2' },
      exec: 'hitH2',
    },
    proto_h3: {
      executor: 'constant-arrival-rate',
      rate: Number(__ENV.TARGET_RPS || 80),
      timeUnit: '1s',
      duration: '8m',
      preAllocatedVUs: 30,
      maxVUs: 120,
      tags: { proto: 'h3' },
      exec: 'hitH3',
    },
  },
  thresholds: {
    'http_req_duration{proto:h2}': ['p(95)<420', 'p(99)<750'],
    'http_req_duration{proto:h3}': ['p(95)<400', 'p(99)<720'],
    'http_req_failed{proto:h2}': ['rate<0.005'],
    'http_req_failed{proto:h3}': ['rate<0.008'],
  },
};

export function hitH2() {
  const res = http.post(`${H2_BASE}/api/search`, BODY, {
    headers: { 'Content-Type': 'application/json' },
    tags: { proto: 'h2', route: 'search' },
  });
  check(res, { 'h2 2xx': (r) => r.status >= 200 && r.status < 300 });
  sleep(0.1);
}

export function hitH3() {
  const res = http.post(`${H3_BASE}/api/search`, BODY, {
    headers: { 'Content-Type': 'application/json' },
    tags: { proto: 'h3', route: 'search' },
  });
  check(res, { 'h3 2xx': (r) => r.status >= 200 && r.status < 300 });
  sleep(0.1);
}
```

**Patrones que funcionan**

- **Línea base del mix real de clientes** (upgrades HTTP/1.1, H2 en todas partes o publicidad H3) antes de toggles sintéticos.
- **Rampa modelos idénticos de RPS/VU**; compara colas, no solo promedios.
- **Registrar negociación** desde ingress en la ventana de prueba; alinear tags con splits observados.
- **Pares mesh on/off** en Kubernetes cuando sidecars terminan TLS distinto ([microservicios Kubernetes](/es/blog/pruebas-carga-microservicios-kubernetes)).

**Antipatrones a evitar**

- Benchmarkear tamaños de payload distintos «porque H3 es más nuevo».
- Ignorar tuning UDP del generador mientras culpas a la app por resets tempranos.
- Declarar victoria en staging LAN cuando paths móviles con pérdida mandan colas en prod.

**Pro tip (comando de ejemplo):**

```bash
k6 run http-proto-compare.js --summary-trend-stats="p(95),p(99)" -e TARGET_RPS=80
```

**Qué demuestra este comando:** tendencias de percentiles lado a lado para tags `proto:h2` y `proto:h3` en un resumen.

## Marco de decisión: cuándo invertir en H3 bajo carga

| Señal | Suele ser protocolo cuando | Acción recomendada |
|:---|:---|:---|
| Cola de latencia en alza, CPU estable | Buffering / pérdida QUIC en el path | Capturas; perfil de enlace con pérdida |
| Resets de conexión tempranos | Middleboxes que manejan mal UDP | Lab de firewall; política de fallback |
| Sesiones más cortas | Timeouts idle agresivos en path nuevo | Alinear keep-alive CDN/proxy con baseline H2 |
| H3 gana en `p99` solo móvil | Paths radio con pérdida | Pruebas geo + mix de dispositivos ([geo-distribuidas](/es/blog/pruebas-de-carga-distribuidas-geo)) |
| H3 más CPU, colas similares | Costo cifrado/stack | Planificar headroom CPU |

**Quédate en H2** si staging no muestra ganancia en colas y el costo ops de depurar UDP es alto.

**Pilota H3** cuando logs de ingress muestran share material de H3 y colas móviles dominan incumplimientos de SLO.

**Frena release** cuando `http_req_failed{proto:h3}` supera presupuesto aunque `p95` se vea mejor—los errores mandan sobre promedios.

## Narrativa para stakeholders

Explica trade-offs con [throughput vs latencia](/es/blog/throughput-vs-latencia-stakeholders): HTTP/3 puede bajar colas en redes con pérdida mientras desplaza CPU del servidor—presupuesta ambos. Adjunta tags de protocolo a reportes ([cómo leer reportes](/es/blog/como-leer-reportes-pruebas-de-carga)) para que liderazgo vea los mismos splits que ingeniería.

## Checklist pre-release

- [ ] Documentar cadena TLS, política de cifrado y ALPN para corridas H2 vs H3.
- [ ] Congelar tamaño de payload, compresión y headers de auth entre escenarios de protocolo.
- [ ] Registrar tuning OS del generador (buffers `udp`, `max_open_files`) en corridas H3.
- [ ] Comparar `p95`/`p99` y `http_req_failed` por tag `proto`, no agregados globales.
- [ ] Archivar stats de negociación de ingress de la ventana de prueba junto a exports k6.

## Cómo Performate simplifica corridas A/B de protocolo

Alterna endpoints sin reescribir colecciones enteras cada release.

**Ejemplo: comparar endpoints H2 y H3 desde una colección**

1. **Importar** requests de búsqueda/checkout una vez; duplicar hosts para alias `h2.` y `h3.`. *Problema resuelto:* mismos bodies y headers entre protocolos.
2. **Crear dos escenarios** con la misma tasa de llegada y tags `proto:h2` / `proto:h3`. *Problema resuelto:* RPS honesto sin forkear scripts.
3. **Correr y abrir vista de comparación** filtrada por tag de protocolo. *Problema resuelto:* colas visibles por stack en un export.
4. **Adjuntar notas de infra** (PoP CDN, cambio de cert) en el pie del reporte para la reunión de adopción.
5. **Exportar k6** para regresión CI cuando el share de H3 cruce tu umbral de adopción.
6. **Compartir con SRE** junto al [runbook de depuración](/es/blog/runbook-depurar-prueba-carga-fallida) si los resets pican a mitad de prueba.

## Cierre

Las comparaciones de protocolo son **experimentos controlados**, no slides con slogans. Congela TLS, payloads y geografía; etiqueta cada petición; juzga colas y errores antes que promedios.

Corre tu próximo par H2/H3 a RPS idéntico—y registra si se movió primero `p99` o `http_req_failed`. Esa respuesta dice si el stack está listo, no solo más rápido en papel.

[Try Performate free](https://performate.app) | [Book a demo](/demo) | [k6 HTTP requests](https://k6.io/docs/using-k6/http-requests/)
