O que é Rate Limiting
Rate Limiting (Limitação de Taxa) é um mecanismo que limita o número de requisições de API em um determinado período. Mantém a estabilidade do serviço e protege o sistema contra uso malicioso ou acessos excessivos causados por bugs.
Por que é necessário: Se requisições forem aceitas sem limite, um único usuário pode consumir todos os recursos do sistema, ou ataques DDoS podem derrubar o serviço.
Objetivos do Rate Limiting
| Objetivo | Descrição |
|---|---|
| Proteção do serviço | Prevenir quedas por sobrecarga |
| Garantir equidade | Distribuir recursos de forma justa para todos os usuários |
| Prevenção de abuso | Impedir scraping, ataques de força bruta |
| Gestão de custos | Garantir previsibilidade nos custos de infraestrutura |
Principais Algoritmos
1. Janela Fixa (Fixed Window)
Reseta o contador a cada janela de tempo fixa.
Configuração: Janela de 1 minuto (00:00~00:59), limite de 100 requisições/minuto
| Horário | Requisições | Resultado |
|---|---|---|
| 00:00-00:30 | 90 | OK |
| 00:30-00:59 | 10 | OK (total 100) |
| 01:00 | Contador reseta | |
| 01:00-01:30 | 100 | OK |
Problema: Na fronteira da janela, momentaneamente é possível o dobro de requisições
| Horário | Requisições | Problema |
|---|---|---|
| 00:59 | 100 | OK |
| 01:00 | 100 | OK |
| -> 200 requisições em 2 segundos! |
2. Log de Janela Deslizante (Sliding Window Log)
Registra o timestamp de cada requisição e conta as requisições nos últimos N segundos.
Hora atual: 01:00:30, Janela: últimos 60 segundos (00:00:30~01:00:30)
| Timestamp | Status |
|---|---|
| 00:00:25 | Fora da janela (removido) |
| 00:00:35 | OK Válido |
| 00:00:50 | OK Válido |
| 01:00:10 | OK Válido |
Vantagem: Rate limiting preciso Desvantagem: Alto uso de memória
3. Contador de Janela Deslizante (Sliding Window Counter)
Versão melhorada da janela fixa. Calcula ponderando os contadores das janelas anterior e atual.
| Janela | Número de requisições |
|---|---|
| Anterior (00:00-00:59) | 80 |
| Atual (01:00-01:59) | 30 |
| Hora atual | 01:00:20 (33% decorrido) |
Cálculo: Requisições estimadas = 80 × 0.67 + 30 = 83.6
4. Token Bucket (Balde de Tokens)
Tokens são adicionados ao balde a uma taxa constante, e cada requisição consome um token.
Configuração: Capacidade do balde 10 tokens, taxa de reposição 1 token/segundo
| Estado | Tokens | Observação |
|---|---|---|
| Estado inicial | 10/10 | Cheio |
| Após 5 requisições | 5/10 | 5 tokens consumidos |
| Após 3 segundos | 8/10 | 3 tokens repostos |
Burst: Atualmente 8 requisições possíveis
Vantagens: Suporta bursts, eficiente em memória
5. Leaky Bucket (Balde Furado)
Requisições são processadas do balde a uma taxa constante.
flowchart LR
In["Entrada<br/>(variável)"] --> Bucket["Balde<br/>(fila)"] --> Out["Saída<br/>(taxa fixa)"]
Vantagem: Taxa de saída estável Desvantagem: Não lida bem com bursts
Padrões de Implementação
Headers de Resposta
HTTP/1.1 200 OK
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 45
X-RateLimit-Reset: 1640000000
Resposta de Limite Excedido
HTTP/1.1 429 Too Many Requests
Retry-After: 30
Content-Type: application/json
{
"error": "rate_limit_exceeded",
"message": "Limite de taxa excedido. Tente novamente em 30 segundos.",
"retry_after": 30
}
Exemplo de Implementação com Redis
async function checkRateLimit(userId, limit, windowSec) {
const key = `ratelimit:${userId}`;
const current = await redis.incr(key);
if (current === 1) {
await redis.expire(key, windowSec);
}
if (current > limit) {
const ttl = await redis.ttl(key);
return { allowed: false, retryAfter: ttl };
}
return { allowed: true, remaining: limit - current };
}
Granularidade do Limite
Baseado em Usuário
| Usuário | Limite |
|---|---|
| Usuário A | 100 requisições/minuto |
| Usuário B | 100 requisições/minuto |
Baseado em Endereço IP
| Endereço IP | Limite |
|---|---|
| 192.168.1.1 | 100 requisições/minuto |
| 192.168.1.2 | 100 requisições/minuto |
Baseado em Endpoint
| Endpoint | Limite | Observação |
|---|---|---|
| GET /api/users | 100 requisições/minuto | |
| POST /api/users | 10 requisições/minuto | Criação é mais restrita |
Hierárquico
| Plano | Limite |
|---|---|
| Free tier | 100 requisições/dia |
| Pro tier | 10.000 requisições/dia |
| Enterprise | Ilimitado |
Considerações em Sistemas Distribuídos
Centralizado
flowchart LR
S1["Servidor 1"] --> Redis["Redis<br/>(contador compartilhado)"]
S2["Servidor 2"] --> Redis
S3["Servidor 3"] --> Redis
Vantagem: Preciso Desvantagem: Latência para o Redis
Cache Local + Sincronização
flowchart LR
S1["Servidor 1<br/>Contador local"] <-->|Sincronização periódica| S2["Servidor 2<br/>Contador local"]
Vantagem: Baixa latência Desvantagem: Tolera pequenas ultrapassagens
Tratamento no Lado do Cliente
Exponential Backoff
async function fetchWithRetry(url, maxRetries = 3) {
for (let i = 0; i < maxRetries; i++) {
const response = await fetch(url);
if (response.status === 429) {
const retryAfter = response.headers.get('Retry-After') || Math.pow(2, i);
await sleep(retryAfter * 1000);
continue;
}
return response;
}
throw new Error('Rate limit exceeded after retries');
}
Resumo
Rate limiting é um mecanismo importante para garantir a estabilidade e equidade da API. Escolhendo o algoritmo adequado ao caso de uso, como token bucket ou sliding window, e configurando limites com a granularidade apropriada, é possível proteger o serviço enquanto proporciona uma boa experiência ao usuário.
← Voltar para a lista