---
title: "Pruebas de rate limits y throttling: cómo validar comportamiento 429 con seguridad"
description: "Ejercita Retry-After y headers de cuota en staging, modela backoff con honestidad y demuestra que tus clientes degradan con gracia."
publishDate: "2026-07-09"
draft: false
keyword: "limites tasa throttling api k6"
intent: "MOFU"
cta: "Usa Performate para orquestar escenarios de rate-limit por etapas sin quemar cuotas de producción."
tags: ["k6", "pruebas-de-carga", "rendimiento-api", "rate", "limit"]
translationOf: api-rate-limits-throttling-k6
---

Tu cliente móvil reintenta al instante en cada 429—y staging nunca demostró que no amplificaría un throttle breve del gateway en tormenta de reintentos. Disparar **429 Too Many Requests** a propósito en production es negligente; demostrar comportamiento en **staging** con límites realistas es ingeniería. Las pruebas de carga de rate-limit responden otra pregunta que gráficos de RPS pico: **cuando actúan las cuotas, ¿los clientes hacen backoff, mienten los headers y el sistema se recupera limpio?**

Validar throttling con k6 implica rampar tráfico hasta que activen límites mientras asertas `Retry-After`, headers de cuota y paths de degradación del cliente—no celebrar promedios HTTP 200 mientras 429s se esconden en colas sin tags. En esta guía verás cómo diseñar escenarios seguros en staging, qué métricas importan más allá de tasas de éxito y cómo exportar evidencia para revisiones de compliance.

## Por qué los rate limits cambian el rendimiento—no solo códigos de estado

Bajo presión de cuota, latencia y semántica de fallo divergen de pruebas de carga en steady state:

- **Timing de onset 429** revela límites mal configurados mucho antes de que tráfico real los golpee.
- **Headers Retry-After** gobiernan sleep del cliente; ignorarlos produce thundering herds.
- **Cuotas por key vs por IP** hacen que el mismo RPS de un tenant se comporte distinto que keys distribuidas.
- **Saturación downstream** puede imitar throttling—`iteration_duration` en alza con límites idle apunta al cuello de botella equivocado.

Piensa en rate limits como un parking con cartel de capacidad fija. Probar solo «qué tan rápido entran autos» omite si el **cartel lleno** dispara colas ordenadas o giros en U caóticos.

Coordina con owners de API sobre tenants sintéticos: nunca martilles vendors terceros sin contratos ([dependencias de terceros](/es/blog/pruebas-carga-dependencias-api-terceros)).

## Implementación práctica en k6: ramp hasta 429, asertar headers

Modela un ramp por etapas que cruce umbrales de cuota documentados. Etiqueta iteraciones por `client_profile` para que resúmenes separen flujos móvil, batch y partner.

**Script de ejemplo (ilustrativo—no es una prueba lista para producción).** Adapta base URL, keys, cuotas y backoff a tu entorno.

**Qué demuestra este ejemplo:**

- **Ramping arrival rate** cruza un límite ficticio de 60 req/min por key en etapas controladas.
- **Métricas custom** cuentan respuestas 429 y registran valores observados de `Retry-After`.
- **Simulación de backoff del cliente:** sleep respeta segundos del header en lugar de reintento instantáneo.
- **Checks en headers de cuota:** `X-RateLimit-Remaining` baja de forma predecible cerca del umbral.

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

const BASE = __ENV.API_BASE || 'https://staging.example.com';
const rateLimited = new Counter('rate_limited_429');
const retryAfterSec = new Trend('retry_after_seconds');

export const options = {
  scenarios: {
    ramp_to_quota: {
      executor: 'ramping-arrival-rate',
      startRate: 10,
      timeUnit: '1m',
      preAllocatedVUs: 20,
      maxVUs: 80,
      stages: [
        { duration: '3m', target: 30 },
        { duration: '3m', target: 60 },
        { duration: '3m', target: 90 },
        { duration: '2m', target: 30 },
      ],
      tags: { client_profile: 'mobile-app', route: 'search' },
      exec: 'searchRequest',
    },
  },
  thresholds: {
    rate_limited_429: ['count>0'],
    'http_req_failed{status:429}': ['rate<0.5'],
    http_req_failed: ['rate<0.05'],
  },
};

export function searchRequest() {
  const res = http.get(`${BASE}/v1/search?q=load-test`, {
    headers: { Authorization: `Bearer ${__ENV.API_KEY}` },
    tags: { client_profile: 'mobile-app', route: 'search' },
  });

  if (res.status === 429) {
    rateLimited.add(1);
    const ra = res.headers['Retry-After'];
    if (ra) {
      const seconds = Number(ra);
      retryAfterSec.add(seconds);
      sleep(seconds);
    } else {
      sleep(1);
    }
    return;
  }

  check(res, {
    'search 2xx': (r) => r.status >= 200 && r.status < 300,
    'remaining header present': (r) => r.headers['X-RateLimit-Remaining'] !== undefined,
  });
  sleep(0.2);
}
```

**Patrones que funcionan**

- **Refleja cuotas documentadas** (por minuto / por key / por IP) desde docs del proveedor—la guía IETF evoluciona; valida contra tu gateway ([HTTP requests](https://k6.io/docs/using-k6/http-requests/)).
- **Etiqueta por `client_profile`** para que lógica de retry móvil no enmascare jobs batch ([metrics](https://k6.io/docs/using-k6/metrics/)).
- **Corre etapa de recuperación** tras el ramp—vigila `http_req_failed` *después* de reset de allowance.
- **Compara con [análisis de cuellos de botella](/es/blog/analisis-cuellos-de-botella-api)** cuando `iteration_duration` sube y conteos 429 se mantienen planos.

**Antipatrones a evitar**

- Martillar production o APIs de vendors sin aprobación escrita y keys sintéticas.
- Loguear bodies completos que puedan contener PII al capturar payloads 429.
- Tratar cualquier 429 como fallo sin distinguir ejercicio esperado de cuota de misconfiguración.

**Pro tip (comando de ejemplo):** muestra tendencias 429 por separado en el resumen.

```bash
k6 run rate-limit-ramp.js --summary-trend-stats="count,avg" --tag client_profile=mobile-app
```

**Qué demuestra este comando:** resúmenes etiquetados permiten a revisores de compliance ver cuándo actuaron límites y cómo se comportó `Retry-After` entre etapas.

## Marco de decisión: prueba de cuota vs RPS pico vs soak

| Situación | Acción recomendada |
|:---|:---|
| Reglas nuevas de rate en gateway o WAF | Ramp por etapas en staging; aserta onset 429 cerca del umbral documentado |
| Cliente móvil publica lógica de retry | Escenario con sleep honesto en `Retry-After`; mide decaimiento de tormenta |
| Job batch comparte key con tráfico interactivo | Escenarios separados tag `client_profile:batch` vs `mobile-app` |
| API tercera con tier contractual | Solo tenant sintético; nunca exceder cuota de prueba acordada |
| Carga steady ya en verde | Añade etapa que cruce cuota—RPS pico solo oculta comportamiento throttle |

**Usa ramp que cruce cuota si** necesitas demostrar que clientes y gateways se comportan cuando actúan límites—no solo antes.

**Usa pruebas de RPS pico si** la pregunta es saturación bajo cuota (pools, CPU, DB)—complementarias, no sustituto.

**Usa soak post-throttle si** debes probar recuperación tras reset de allowances—tormentas de retry suelen aparecer en el segundo minuto, no en el primer pico.

## Checklist pre-export para compliance y equipos cliente

Antes de compartir evidencia de rate-limit:

- [ ] Tenant sintético y API key documentados; nunca keys de production.
- [ ] Umbrales de cuota documentados citados en notas (por minuto / key / IP).
- [ ] Tasa de onset 429 y etapa registradas—no solo porcentaje agregado de éxito.
- [ ] Distribución de `Retry-After` capturada (métrica custom o muestra de log sin PII).
- [ ] Path de backoff del cliente ejercitado—sin bucles instant-retry en script salvo probar mal comportamiento explícitamente.
- [ ] Etapa de recuperación muestra `http_req_failed` asentándose tras reset de allowance.
- [ ] APIs terceras probadas solo con aprobación del owner y referencia contractual.

## Cómo Performate simplifica orquestación de escenarios rate-limit

Editar scripts a mano hace doloroso el tuning de cuotas. Abajo un **ejemplo de flujo concreto** para el ramp de search API de este artículo.

**Ejemplo: escenificar prueba que cruza cuota sin quemar allowances de production**

1. **Importa la colección** con peticiones search (o partner) y auth ya configurada. *Problema resuelto:* mismas URLs que QA—sin endpoints misteriosos en pruebas throttle.
2. **Crea escenario ramping-arrival-rate** en el editor visual: 30 → 60 → 90 req/min en etapas alineadas a cuota documentada. *Problema resuelto:* cruce honesto de límites sin editar arrays de stages cada pasada.
3. **Aplica tags:** `client_profile:mobile-app`, `route:search`. *Problema resuelto:* resúmenes separan flujos cuando batch y móvil comparten infra.
4. **Corre en staging** y filtra el reporte por respuestas 429 y latencia en recuperación. *Problema resuelto:* revisores ven timing de onset, no un pass/fail verde único.
5. **Duplica el escenario** para `client_profile:batch` con otra key—compara si jobs batch roban cuota interactiva. *Problema resuelto:* comportamiento por tenant visible sin bifurcar scripts.
6. **Exporta script k6 y resumen** para adjuntar a tickets de release o revisión con vendor. *Problema resuelto:* la prueba viaja con el change request.

Ese flujo encaja con el `cta` de este post: orquestar escenarios rate-limit por etapas sin quemar cuotas de production.

## Cierre

La confianza en rate-limit es un **problema de degradación**, no un trofeo de RPS pico. Rampa hasta que activen 429s en staging, respeta `Retry-After` en tu script, etiqueta perfiles cliente y demuestra recuperación tras reset de allowances.

Corre el ramp de staging de esta semana contra tu cuota documentada—y anota si el onset 429 coincide con el contrato o señala misconfiguración que tu prueba de pico nunca alcanzó.

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