Implementación de Rate Limiting en APIs
El rate limiting en sistemas distribuidos requiere gestión consistente del estado, la elección correcta del algoritmo y comunicación clara con los clientes.
Descripción concisa
La implementación de rate limiting en APIs consiste en establecer límites técnicos sobre las solicitudes que llegan a un servicio. En sistemas distribuidos, el límite debe aplicarse consistentemente en todas las instancias, lo que requiere un almacenamiento centralizado como Redis o una base de datos. Los algoritmos principales son Fixed Window, Sliding Window, Token Bucket y Leaky Bucket. Cada uno tiene propiedades distintas en cuanto a equidad, comportamiento ante picos de tráfico y complejidad de implementación. Al implementar, hay que considerar detalles críticos como la identificación del cliente, operaciones atómicas, headers de estado, manejo de errores con 429 y Retry-After, así como la selección de límites apropiados. El rate limiting no debería estar solo en el código de la aplicación, sino también ser configurable en el API Gateway o Load Balancer para ofrecer protección en múltiples capas.
Componentes clave
Identificación del cliente
El rate limiting necesita identificar de forma única a cada cliente. Esto se puede hacer mediante API Keys, IDs de usuario, direcciones IP o combinaciones de varios factores. Para clientes autenticados, la ID de usuario suele ser la mejor opción, ya que las direcciones IP cambian y múltiples clientes pueden compartir una misma IP.
Implementación de Fixed Window
Fixed Window cuenta solicitudes en ventanas de tiempo fijas. En Redis se almacena un contador por ventana y cliente. El contador se crea en la primera solicitud de la ventana y expira después del tiempo establecido. Si el contador supera el límite, se rechaza la solicitud.
Implementación de Sliding Window
Sliding Window es más justo que Fixed Window, pero más complejo. Una variante es Sliding Window Log, donde se mantiene una lista de timestamps de todas las solicitudes recientes de cada cliente. Se eliminan las solicitudes que caen fuera de la ventana. Si la cantidad de solicitudes restantes supera el límite, se rechaza la nueva solicitud.
Implementación de Token Bucket
Token Bucket es un algoritmo muy usado. Un bucket tiene una capacidad máxima y se llena con tokens a una tasa constante. Cada solicitud consume un token. Si el bucket está vacío, se rechaza la solicitud o se retrasa. Redis es ideal para Token Bucket usando scripts Lua para operaciones atómicas.
Implementación de Leaky Bucket
Leaky Bucket procesa solicitudes a una tasa constante. Las solicitudes se ponen en cola y se procesan de forma uniforme. El algoritmo es excelente para procesamiento consistente, pero puede causar tiempos de espera y rechazo cuando la cola está llena.
Redis para rate limiting distribuido
Redis ofrece operaciones atómicas rápidas y TTL, lo que lo hace ideal para rate limiting. Los scripts Lua permiten ejecutar múltiples comandos de forma atómica. Redis Cluster o Redis Sentinel proporcionan alta disponibilidad. En casos de muy alta demanda, Redis puede convertirse en un cuello de botella, por lo que se pueden complementar con caché local o proxys con caché local.
Operaciones atómicas
El rate limiting debe ser atómico para evitar race conditions. Si múltiples solicitudes verifican simultáneamente si queda límite disponible, el límite no debe ser superado. Los scripts Lua en Redis o transacciones en bases de datos garantizan la atomicidad.
Headers para indicar estado
Los clientes deben saber cuál es su estado actual. Headers como X-RateLimit-Limit, X-RateLimit-Remaining y X-RateLimit-Reset son ampliamente usados. Alternativamente, se puede usar el esquema RFC-RateLimit. Estos headers permiten que los clientes ajusten su tasa de solicitudes.
Manejo de errores con 429
Cuando se supera el límite, la API responde con 429 Too Many Requests. El header Retry-After debe indicar cuándo el cliente puede reintentar. La respuesta de error debe seguir RFC 7807 Problem Details y no contener detalles internos.
Límites por endpoint y por usuario
Diferentes endpoints tienen costos distintos. Las operaciones de escritura y consultas costosas deben tener límites más estrictos que operaciones simples de lectura. De igual forma, distintos grupos de usuarios pueden recibir límites diferentes, por ejemplo clientes gratuitos y de pago.
Rate limiting en API Gateway
Los API Gateways como Kong, Nginx o AWS API Gateway incluyen rate limiting integrado. Protegen la API antes de que las solicitudes lleguen al backend. Los gateways son particularmente efectivos para límites globales y reglas simples, mientras que el código de la aplicación puede manejar reglas más complejas y específicas de usuario.
Ejemplo práctico
Un servicio Node.js implementa Token Bucket rate limiting con Redis.
const redis = require('redis');
const client = redis.createClient();
const LIMIT = 100;
const WINDOW_SECONDS = 60;
async function isAllowed(clientId) {
const key = `rate_limit:${clientId}`;
const lua = `
local key = KEYS[1]
local limit = tonumber(ARGV[1])
local window = tonumber(ARGV[2])
local current = redis.call('GET', key)
if current == false then
current = 0
end
current = tonumber(current)
if current >= limit then
return 0
end
redis.call('INCR', key)
if current == 0 then
redis.call('EXPIRE', key, window)
end
return 1
`;
const result = await client.eval(lua, { keys: [key], arguments: [String(LIMIT), String(WINDOW_SECONDS)] });
return result === 1;
}
Middleware en Express:
async function rateLimit(req, res, next) {
const clientId = req.user?.id || req.ip;
const allowed = await isAllowed(clientId);
if (!allowed) {
res.set('Retry-After', String(WINDOW_SECONDS));
return res.status(429).json({
type: 'https://api.example.com/problems/rate-limit-exceeded',
title: 'Rate limit excedido',
status: 429,
detail: `Has excedido el límite de ${LIMIT} solicitudes por ${WINDOW_SECONDS} segundos.`
});
}
next();
}
Este enfoque es atómico, funciona en múltiples instancias de servidor y comunica claramente los límites al cliente.
FAQ: Implementación de Rate Limiting en APIs
1. ¿Cómo se identifica a un cliente para rate limiting?
2. ¿Por qué Redis es adecuado para rate limiting?
3. ¿Qué es Token Bucket en la implementación?
4. ¿Qué es rate limiting atómico?
5. ¿Qué es Sliding Window Log?
6. ¿Qué es Fixed Window?
7. ¿Qué es Leaky Bucket?
8. ¿Qué es una race condition en rate limiting?
9. ¿Qué headers se deben establecer en rate limiting?
10. ¿Qué es 429 Too Many Requests?
11. ¿Debería ocurrir rate limiting en el Gateway o en el código?
12. ¿Qué son límites por endpoint?
13. ¿Qué es un cuello de botella en rate limiting?
14. ¿Qué es una buena estrategia de rate limiting?
15. ¿Cuál es la ventaja de Retry-After?
Continuamos en el itinerario de aprendizaje de APIs
El siguiente artículo en el itinerario de aprendizaje de APIs aborda Rate Limiting y Throttling para APIs — estrategias y algoritmos para Rate Limiting, así como diferencias entre Rate Limiting y Throttling.
Fuentes
- https://www.rfc-editor.org/rfc/rfc6585
- https://redis.io/docs/manual/programmability/eval-intro/
- https://www.konghq.com/kong
Recomendaciones de libros para el desarrollo de APIs
Si deseas continuar profundizando en Rate Limiting, sistemas distribuidos y arquitectura de APIs, te recomendamos los siguientes libros:
Keine Bücher für Kategorie "api-development" gefunden.



