Explicación de la limitación de velocidad de API: Algoritmos, encabezados y manejo de errores 429
Los límites de velocidad protegen las API de sobrecargas y abusos. Aprenda cómo se comportan los algoritmos principales, cómo es una buena respuesta 429 y cómo los clientes deberían retroceder, utilizando una simulación que ejecutamos.
- La limitación de tarifas limita la cantidad de solicitudes que un cliente puede realizar en un período de tiempo.
- El depósito de tokens permite ráfagas cortas y al mismo tiempo aplica una tasa promedio.
- Una simple ventana fija puede permitir el doble del límite en el límite de una ventana.
- Devuelve 429 demasiadas solicitudes con un encabezado Retry-After y hace que los clientes retrocedan con inquietud.
Un script con errores llama a su API en un bucle cerrado. Sin límites, puede ralentizar el servicio para todos los demás usuarios o generar una gran factura de la nube. La limitación de la tasa API es la barrera que impide que un solo cliente obtenga más de lo que le corresponde.
Para mostrar cómo se comportan los algoritmos comunes, escribimos pequeñas versiones de Python y las alimentamos con tiempos de solicitud simulados. Los resultados a continuación provienen de esa ejecución. Son modelos de enseñanza, no códigos de producción, y las puertas de enlace reales tienen más funciones.
¿Qué es la limitación de velocidad?
La limitación de velocidad cuenta las solicitudes por cliente y rechaza o retrasa las solicitudes que superan un límite acordado, como 100 solicitudes por minuto. Una idea relacionada, limitar, a menudo significa ralentizar las solicitudes en lugar de rechazarlas. Una cuota suele ser una asignación mayor durante un período más largo, como 10 000 llamadas por mes en un plan de precios.
Por qué las API lo necesitan
- Estabilidad: los picos de tráfico no pueden abrumar las bases de datos ni los servicios posteriores.
- Equidad: un cliente pesado no puede matar de hambre a los demás.
- Seguridad: los límites ralentizan los intentos de inicio de sesión por fuerza bruta y el raspado.
- Control de costos: las operaciones costosas, como las llamadas a modelos de IA, se mantienen dentro del presupuesto.
La limitación de velocidad es un control central en el Top 10 de seguridad de API de OWASP, bajo consumo de recursos sin restricciones. Nuestra guía de Prueba de API con Postman muestra cómo enviar las solicitudes repetidas necesarias para comprobarlo.
Cubo de fichas
Imagínese un cubo que contiene hasta 5 fichas. Cada solicitud requiere un token. Los tokens se recargan a 1 por segundo y el depósito nunca contiene más de 5. Si el depósito está vacío, la solicitud se rechaza.
class TokenBucket:
def __init__(self, capacity, refill_per_sec):
self.capacity = capacity
self.rate = refill_per_sec
self.tokens = capacity
self.last = 0.0
def allow(self, now):
elapsed = now - self.last
self.tokens = min(self.capacity, self.tokens + elapsed * self.rate)
self.last = now
if self.tokens >= 1:
self.tokens -= 1
return True
return False
Enviamos 7 solicitudes a la vez y luego más:
burst of 7 at t=0: [True, True, True, True, True, False, False]
t=2.0: [True, True, False]
t=10: 5 allowed of 10
Los primeros 5 salieron como una ráfaga, luego el cubo quedó vacío. Dos segundos después, se habían recargado 2 tokens, por lo que se aprobaron 2 solicitudes más. Después de una larga pausa, el depósito se llenó nuevamente, pero con un límite de 5. Este comportamiento de ráfaga y luego constante se adapta al tráfico real, razón por la cual los depósitos de tokens son comunes en las puertas de enlace API. El depósito con fugas es un pariente cercano que procesa solicitudes a una velocidad fija, suavizando la salida en lugar de permitir ráfagas.
Ventana fija vs ventana corredera
Un contador de ventana fija es el enfoque más simple: permita 10 solicitudes por minuto y reinicie el contador cuando cambie el minuto. Tiene un defecto conocido en el límite. Enviamos 10 solicitudes a los 59,9 segundos y 10 más a los 60,0 segundos, con un límite de 10 por ventana de 60 segundos:
fixed window allowed around boundary: 20 of 20
sliding log allowed around boundary: 10 of 20
La ventana fija permitió las 20 solicitudes en una décima de segundo, el doble de la velocidad prevista, porque caían en dos ventanas diferentes. Un registro deslizante recuerda la hora de cada solicitud reciente y cuenta las de los últimos 60 segundos, por lo que solo permitió 10 correctamente.
La compensación es la memoria. Un registro deslizante almacena una marca de tiempo por solicitud. El mostrador con ventana corrediza es un término medio popular. Estima la tasa combinando los recuentos de ventanas actuales y anteriores, utilizando poca memoria con buena precisión.
Comparación de algoritmos
| Algoritmo | Explosiones | Precisión | Memoria |
|---|---|---|---|
| ventana fija | Hasta 2x en los límites | Bajo | muy bajo |
| Registro deslizante | No | exacto | Alto |
| Mostrador de ventana corredera | pequeño | bueno | Bajo |
| Cubo de fichas | Permitido hasta la capacidad | bueno | Bajo |
| balde con fugas | suavizado | bueno | Bajo |
Que limitar por
- Clave API o ID de usuario: la opción más justa para API autenticadas.
- Dirección IP: útil para puntos finales públicos, pero muchos usuarios pueden compartir una IP y los atacantes pueden rotarlas.
- Punto final: las operaciones costosas, como la búsqueda, las exportaciones o el inicio de sesión, merecen límites más estrictos.
- Nivel del plan: los clientes gratuitos y pagos suelen obtener límites diferentes.
Los puntos finales de inicio de sesión necesitan atención especial. Limite tanto por cuenta como por IP, de modo que los atacantes no puedan simplemente distribuir conjeturas entre muchas IP o muchas cuentas.
La respuesta 429
Cuando un cliente supera el límite, devuelva HTTP 429 Demasiadas solicitudes, no 500 o 403. Incluya encabezados que le indiquen al cliente qué sucedió y cuándo volver a intentarlo. Nuestra simulación produjo este conjunto para un cliente al que no le quedaban solicitudes:
HTTP/1.1 429 Too Many Requests
RateLimit-Limit: 100
RateLimit-Remaining: 0
RateLimit-Reset: 30
Retry-After: 30
Retry-After es un encabezado HTTP estándar. Los encabezados RateLimit-* provienen de un borrador del IETF y muchas API utilizan sus propias variantes X-RateLimit-*. Elijas lo que elijas, documentalo. Para obtener más información sobre los códigos de estado, consulte nuestra hoja de referencia sobre códigos de estado HTTP.
Manejar los límites como cliente
Volver a intentarlo inmediatamente después de un 429 empeora las cosas. Si miles de clientes lo hacen al mismo tiempo, llegan al servidor en ondas sincronizadas. La solución es retroceso exponencial con fluctuación: espere más después de cada falla y agregue aleatoriedad.
def backoff(attempt, base=0.5, cap=30, rng=random.Random(4)):
return round(min(cap, base * 2 ** attempt) * rng.random(), 2)
[backoff(a) for a in range(6)]
# [0.12, 0.1, 0.79, 0.62, 0.53, 6.43]
Esto es “full jitter”: una espera aleatoria entre cero y un techo que crece exponencialmente. Las esperas parecen irregulares, y ese es el punto. Los clientes se dispersan en lugar de volver a intentarlo juntos. Sembramos el generador aleatorio para que se pudiera reproducir la salida.
Lista de verificación del cliente: respete Retry-After cuando esté presente, limite el número de reintentos, reintente solo las solicitudes que sean seguras para repetir y observe el encabezado de solicitudes restantes para poder reducir la velocidad antes de alcanzar el límite.
Limitación de tasa distribuida
Con varios servidores API detrás de un equilibrador de carga, cada servidor por sí solo permite que un cliente supere el límite al distribuir las solicitudes entre ellos. Los equipos suelen mantener contadores en una tienda compartida como Redis, con operaciones atómicas o un script corto para que dos servidores no puedan tomar el último token. Las puertas de enlace como Kong, NGINX, Envoy y las puertas de enlace API en la nube proporcionan esto como configuración. No ejecutamos una configuración distribuida para este artículo.
Límites de tasa de prueba
- Envíe solicitudes hasta el límite y confirme que tienen éxito.
- Envíe uno más y confirme un 429 con los encabezados correctos.
- Espere el tiempo de reinicio y confirme que las solicitudes se hayan realizado nuevamente.
- Verificar límites por clave: el uso de un cliente no debe bloquear a otro.
- Pruebe el límite entre ventanas para detectar el problema de la doble ráfaga.
- Utilice una herramienta de carga, como se explica en pruebas de carga frente a pruebas de estrés, para comprobar el comportamiento en condiciones de alta concurrencia.
En las pruebas unitarias, inyecte la hora actual, como lo hace nuestra simulación con now, para que las pruebas nunca tengan que dormir.
Diseñar límites con los que los usuarios puedan vivir
Elegir los números es tan importante como elegir el algoritmo. Comience con tráfico real: observe cuántas solicitudes realizan por minuto sus clientes legítimos más importantes y establezca límites cómodamente por encima de eso. Un límite que bloquea el uso normal genera tickets de soporte, no seguridad.
- Publique los límites en la documentación de su API, por punto final y por plan.
- Advertir antes de bloquear. Los encabezados que muestran las solicitudes restantes permiten que los clientes con buen comportamiento disminuyan la velocidad por sí solos.
- Ofrezca alternativas a las encuestas intensas, como webhooks, puntos finales masivos o páginas más grandes.
- Supervise las tarifas de 429. Un aumento repentino puede significar un ataque, la liberación de un cliente con errores o límites que ahora son demasiado estrictos.
- Otorgar excepciones deliberadamente, por ejemplo, límites elevados para un socio, registrados en la configuración en lugar de codificados.
Decida también qué sucede con las solicitudes que llegan justo por encima del límite. Algunas API ponen en cola brevemente una pequeña cantidad de solicitudes adicionales en lugar de rechazarlas, lo que suaviza los picos breves. Otros dan prioridad a puntos finales esenciales, como los pagos, sobre otros menos críticos como los análisis, de modo que el tráfico importante siga fluyendo cuando el sistema está bajo presión.
Conclusión
Una buena limitación de tasa es un contrato entre API y cliente. El servidor elige un algoritmo justo, generalmente un depósito de tokens o una ventana deslizante, y explica sus límites claramente con un 429 y un reintento posterior. El cliente respeta esas señales y retrocede con nerviosismo. Comience con límites generosos por clave API, observe el uso real y ajuste solo donde sea necesario.
Preguntas frecuentes
¿Qué es la limitación de la tasa API?
Es un límite a la cantidad de solicitudes que un cliente puede realizar a una API en un tiempo determinado, como 100 por minuto. Las solicitudes que superen el límite se rechazan o se retrasan.
¿Qué significa HTTP 429?
429 Demasiadas solicitudes significa que el cliente ha excedido un límite de tarifa. La respuesta a menudo incluye un encabezado Retry-After que indica cuánto tiempo esperar.
¿Qué es el algoritmo del depósito de tokens?
Cada solicitud utiliza un token de un depósito que se recarga a un ritmo constante hasta un máximo. Permite ráfagas cortas al tiempo que aplica una tasa promedio.
¿Cuál es la diferencia entre limitación y estrangulamiento de velocidad?
La limitación de tarifas normalmente rechaza las solicitudes que superan el límite. La aceleración a menudo los ralentiza o los pone en cola. Los términos se utilizan frecuentemente indistintamente.
¿Cómo debe manejar un cliente los límites de tarifas?
Respete el reintento posterior, reintente con retroceso y fluctuación exponencial, limite el número de reintentos y reduzca la velocidad cuando las solicitudes restantes se agoten.
sigue aprendiendo
¿Necesitas ayuda con pruebas, WordPress o SEO?
Ayudamos a los equipos a enviar mejor software y hacer crecer sus sitios. Cuéntenos en qué está trabajando y le sugeriremos un siguiente paso claro.
Más guías sobre testing, IA y desarrollo moderno
¿Te gustó este artículo? Elige un tema y salta directo a nuestros tutoriales más recientes.
Explicación de las alucinaciones de la IA: por qué los modelos de lenguaje inventan cosas y cómo reducirlas
Se explicaron las alucinaciones de la IA: qué son, por qué los modelos de lenguaje las producen, tipos comunes, cómo reducirlas con conexión a tierr…
Leer artículo →DevOpsExplicación de las variables de entorno: archivos .env, secretos y configuración bien hechos
Variables de entorno explicadas con ejemplos de Python que ejecutamos: leerlas y configurarlas, por qué cada valor es una cadena, archivos .env, her…
Leer artículo →Desarrollo de softwareExplicación de la limitación de velocidad de API: algoritmos, encabezados y manejo de errores 429
La limitación de la tasa de API se explica con una simulación que ejecutamos: depósito de tokens, ventana fija, ventana deslizante, 429 respuestas, …
Leer artículo →Automatización de pruebasBurlarse en Python: unittest.mock, patch y los errores que hacen que las pruebas mientan
Burlarse en Python con unittest.mock, probado: Mock y return_value, side_effect, parches donde se usa un nombre, especificación y autospec, fechas d…
Leer artículo →Pruebas de softwareExplicación de la cobertura del código: cobertura de línea versus sucursal y lo que realmente significa 100%
Cobertura del código explicada con una ejecución real de cobertura.py: cobertura de línea, rama y condición, lectura de un informe, por qué una cobe…
Leer artículo →Bases de datos y SQLDELETE vs TRUNCATE vs DROP en SQL: diferencias, reversión y cuándo usar cada uno
DELETE vs TRUNCATE vs DROP explicado con SQL probado: qué elimina cada uno, reversión, activadores, restablecimiento de identidad, velocidad y en qu…
Leer artículo →Bases de datos y SQLVistas SQL explicadas: cree, use y evite los errores, con ejemplos
Vistas SQL explicadas con consultas que ejecutamos: creación de una vista, resultados en vivo, ocultación de columnas, rendimiento, vistas actualiza…
Leer artículo →Desarrollo de softwareInterfaz TypeScript versus tipo: diferencias reales, probadas con el compilador
Interfaz TypeScript versus tipo, verificado con el compilador real: qué pueden hacer ambos, qué puede hacer solo uno, fusión de declaraciones, exten…
Leer artículo →Desarrollo de softwarePython *args y **kwargs explicados: funciones flexibles con ejemplos claros
Python *args y **kwargs explicados con el código que ejecutamos: empaquetado y desempaquetado, orden de parámetros, argumentos solo de palabras clav…
Leer artículo →Desarrollo de softwareFunciones Lambda de Python: sintaxis, usos reales y cuándo no utilizarlas
Funciones lambda de Python explicadas con el código que ejecutamos: sintaxis, clasificación con clave, mapa y filtro, cierres, trampa de enlace tard…
Leer artículo →Inteligencia artificial¿Qué son los agentes de IA? Cómo funcionan, con un bucle de agente simple que puedes ejecutar
¿Qué son los agentes de IA? Una guía sencilla sobre el bucle del agente, las herramientas, la memoria y las barreras de seguridad, con un pequeño bu…
Leer artículo →DevOpsMonitoreo versus observabilidad: la verdadera diferencia, con registros, métricas y seguimientos
Explicación del monitoreo versus observabilidad: fallas conocidas y desconocidas, registros, métricas y seguimientos, un recorrido por incidentes de…
Leer artículo →DevOpsDocker Volumes versus Bind Mounts: persistir los datos del contenedor de la manera correcta
Se explican los volúmenes de Docker frente a los montajes de enlace: por qué desaparecen los datos del contenedor, volúmenes con nombre, montajes de…
Leer artículo →Automatización de pruebasTDD vs BDD: diferencias clave, una función creada en ambos sentidos y cuándo usar cada una
TDD vs BDD explicado con una característica de descuento construida en ambos sentidos: refactor rojo-verde con el código que ejecutamos, escenarios …
Leer artículo →Desarrollo de softwareGit merge vs rebase: diferencias, ejemplos y cuándo usar cada uno
Git merge vs rebase explicado con salida real del log, una tabla comparativa, la regla de oro del rebase y un flujo de trabajo seguro para equipos.
Leer artículo →Desarrollo de softwareList comprehension en Python: sintaxis, ejemplos y cuándo evitarla
List comprehension en Python explicada: sintaxis, filtros, if-else, bucles anidados, tiempos medidos y cuándo es mejor un bucle for normal.
Leer artículo →