¿Por qué se necesita un Rate Limit (límite de uso)?
- En un chat de Twitch con muchos participantes, si hay un solo spammer y no existe límite de uso, ese spammer puede dominar la conversación.
- Con un límite de uso, cada usuario puede tener una oportunidad justa de participar.
- Un Rate Limiter (limitador de uso) controla el tráfico de un servicio bloqueando solicitudes que exceden un límite establecido durante un período determinado. Esto es útil no solo para controlar el spam en chats.
- Por ejemplo, en un formulario de inicio de sesión, el límite de uso puede frenar ataques de fuerza bruta mientras permite una pequeña cantidad de intentos fallidos.
- Los endpoints de API también suelen tener límites de uso para evitar que un solo usuario acapare los recursos.
- Si se permite que un usuario llame un endpoint de API costoso solo 100 veces por minuto, se puede usar un contador para rastrear 100 hits por minuto, y después de eso bloquear las solicitudes.
- Este es uno de los algoritmos de límite de uso más simples: el Fixed Window Limiter.
- Es una forma común de controlar el tráfico de un servicio.
Algoritmo de Fixed windows
- El número de solicitudes se limita dentro de una ventana de tiempo fija.
- Al inicio de cada ventana de tiempo, el contador de solicitudes se reinicia a 0.
- Ventajas
- Es fácil de implementar y de entender.
- Es predecible para el usuario.
- Desventajas
- Si las solicitudes comienzan cerca del final de la ventana de tiempo, se puede permitir un burst de hasta el doble del límite.
- Caso real: la API de GitHub usa un limitador de velocidad con ventana de tiempo fija que permite 5,000 solicitudes por hora.
- En lugar de fijar la hora de inicio de la ventana con intervalos regulares, cada ventana de tiempo puede crearse en el momento de la primera solicitud del usuario dentro de esa ventana.
- En este enfoque, es especialmente importante informar al usuario cuánto tiempo queda hasta la siguiente ventana.
Algoritmo de Sliding windows
- En vez de recargar toda la capacidad de una sola vez, la sliding window repone capacidad una solicitud a la vez.
- Ventajas
- Suaviza la distribución del tráfico de solicitudes.
- Es adecuada para cargas altas.
- Desventajas
- Es menos predecible para el usuario que una ventana de tiempo fija.
- Guardar la marca de tiempo de cada solicitud consume muchos recursos.
- Como la sliding window es más útil en escenarios de alto tráfico, el hecho de que el algoritmo base consuma muchos recursos resulta contraproducente.
- Por eso, la mayoría de los limitadores de velocidad con sliding window del mundo real usan una aproximación.
- La aproximación calcula la cantidad de solicitudes permitidas en la ventana fija anterior y en la ventana fija actual, y asigna un peso a las solicitudes permitidas de la ventana anterior según su superposición con la ventana móvil que termina en el momento actual.
- Esta aproximación limita las solicitudes casi con la misma proporción, pero es mucho más eficiente.
- Caso real: el limitador de velocidad configurable de Cloudflare usa una sliding window aproximada.
Algoritmo de Token buckets
- En lugar de pensar en la duración de la ventana de tiempo, se imagina un bucket que se llena con "tokens" a una velocidad constante.
- Cada solicitud retira un token de ese bucket, y si el bucket está vacío, la siguiente solicitud se bloquea.
- La capacidad del bucket representa el número máximo de solicitudes que puede soportar un burst.
- El intervalo de reposición representa el intervalo promedio permitido entre solicitudes a largo plazo.
- Una de las principales ventajas de este algoritmo es que puede tener capacidades separadas para burst y promedio sin necesitar múltiples limitadores de velocidad.
- Ventajas
- Permite bursts de tráfico altos, pero aplica una tasa promedio de solicitudes a largo plazo.
- Es más flexible para el usuario, ya que permite picos de tráfico dentro de un rango aceptable.
- Desventajas
- Es más difícil comunicar al usuario las restricciones y el tiempo de reposición que con una ventana de tiempo fija.
- Casos reales
- Stripe usa un token bucket con un límite de 500 y un intervalo de reposición de 0.01 segundos, lo que permite sostener 100 solicitudes por segundo, pero admite bursts de hasta 500 solicitudes.
- El tier gratuito de GPT-3.5 de OpenAI usa un token bucket con un límite de 200 y un intervalo de reposición de 86400 segundos / 200, por lo que queda limitado a 200 solicitudes por día.
Consideraciones al aplicar rate limits
- Es necesario crear un almacenamiento persistente para el rate limiter.
- Si falla la conexión del servidor al almacenamiento persistente, se debe permitir el paso de todas las solicitudes en lugar de bloquearlas.
- Opcionalmente, se puede regular el tráfico en burst.
- Hay que elegir una clave adecuada (ID de usuario, API key, etc.).
- Se deben mostrar errores de límite de velocidad útiles (tiempo de espera hasta la siguiente solicitud, código de estado HTTP 429, headers de respuesta
x-ratelimit-*, etc.).
2 comentarios
Leí el artículo resumido en coreano y pensé: “Ok, entiendo de qué se trata, pero ¿no dicen todos lo mismo?”, pero al leer el artículo del enlace original, ¡de verdad está muy bien explicado y la visualización también es súper satisfactoria! 👍👍👍
Comentarios de Hacker News
Resumen de comentarios de Hacker News
Consideraciones adicionales obtenidas por años de experiencia:
Para prevenir ataques DoS en entornos multi-tenant, el fair queuing es el mejor enfoque: se asigna su propia cola a cada cliente, y una rutina en segundo plano recorre repetidamente cada cola para procesar las solicitudes. Un cliente que envía solicitudes spam solo congestiona su propia cola.
Experiencia implementando código de manejo del lado del cliente: siempre me pregunté cuál era la mejor estrategia de backoff al alcanzar un rate limit. Fue interesante leer sobre los trade-offs desde la perspectiva del servicio.
Mensaje de felicitación: es la mejor visualización para contenido corto; muy informativa y con los puntos clave muy bien organizados.
Algoritmo GCRA: creo que es un mejor algoritmo para rate limiting. Ojalá fuera más conocido y usado.
Excelente trabajo: se nota que este post requirió mucho tiempo y esfuerzo. Bien hecho.
Problema de rate limiting en AWS Lambda: intenté implementar rate limiting en NodeJS, pero en AWS Lambda los temporizadores se comportaban de forma extraña y se excedía el objetivo. En pruebas locales funcionaba, pero en Lambda fallaba. No está claro si era un problema de temporizadores o de la librería.
Qué hacer cuando la capa de rate limiting está saturada: me pregunto si hay otras opciones además de CF. También me pregunto qué tan efectivas son las reglas de nftable para defenderse de ataques DoS en un VPS pequeño.
Esos momentos en que necesitabas este recurso: es un recurso que necesité varias veces a lo largo de mi carrera. Me alegra que ahora exista.
Fan de la visualización de datos: me pregunto si está usando D3.