Uma API sem limite de requisições funciona lindamente até o momento exato em que um cliente escreve um laço sem nenhuma pausa dentro. Então um único chamador consome a capacidade que todos dividem, a latência sobe para todos os outros usuários e a falha parece uma indisponibilidade em vez de um script mal comportado. Um limite de requisições é o mecanismo que transforma esse cenário em um erro pequeno, contido e bem rotulado para um único cliente.
Acertar nos limites é, acima de tudo, uma questão de ser explícito: decidir o que você está contando, em que período, por quem, e o que você diz a um cliente que passa do ponto. Este guia cobre os algoritmos, como escolher números defensáveis, os cabeçalhos que permitem a um cliente bem escrito ficar dentro dos seus limites, e como recuar quando o cliente é você.
Por que o limite de requisições importa
Limites costumam ser introduzidos depois de um incidente, mas resolvem quatro problemas distintos ao mesmo tempo:
- Proteção de capacidade. Seu serviço tem uma vazão máxima sustentável. Um limite mantém a demanda abaixo dela por projeto, não por sorte.
- Equidade. Sem um limite por cliente, quem faz mais barulho fica com mais recursos. Com um limite, cada cliente recebe uma fatia previsível.
- Controle de custos. Se cada requisição dispara uma consulta ao banco, uma chamada a terceiros ou uma invocação de modelo, uma API sem limite é uma fatura sem limite.
- Resistência a abusos. Preenchimento de credenciais, raspagem e enumeração dependem de volume. Um limite os torna lentos o bastante para serem inviáveis e visíveis o bastante para gerar alerta.
Há um quinto benefício, mais discreto: um limite documentado é um contrato. Clientes podem ser construídos para respeitá-lo, o que é muito melhor do que descobrir seu teto batendo nele.
Os algoritmos que vale conhecer
Todo limitador responde à mesma pergunta — esta requisição é permitida agora? — mas eles diferem em como tratam picos, e é essa diferença que você sente como cliente.
| Algoritmo | Permite picos? | Melhor para |
|---|---|---|
| Token bucket | Sim, até o tamanho do balde | APIs públicas; o padrão usual |
| Leaky bucket | Não, a saída é perfeitamente uniforme | Proteger um backend de capacidade fixa |
| Janela fixa | Sim, mas de forma injusta nas bordas | Cotas simples onde a precisão não importa |
| Janela deslizante | Só dentro do limite real | Aplicação exata; custa mais estado |
Token bucket
Imagine um balde que guarda um número fixo de fichas e se reabastece a uma taxa constante. Cada requisição retira uma ficha. Se o balde está vazio, a requisição é rejeitada. Dois números o descrevem por completo: a taxa de reabastecimento, que é sua vazão sustentada, e o tamanho do balde, que é o maior pico que você vai tolerar.
Um balde de 100 fichas reabastecido a 10 por segundo deixa um cliente inativo disparar 100 requisições de imediato e depois o acomoda em 10 por segundo. Isso normalmente é o que você quer: clientes reais são irregulares, então um pico curto é tráfego normal e não abuso, enquanto a média de longo prazo segue limitada. O token bucket é o padrão por bons motivos: é barato de implementar, precisa apenas de uma contagem de fichas e um registro de tempo por cliente, e seu comportamento é fácil de explicar na documentação.
Leaky bucket
O leaky bucket é a imagem espelhada. As requisições entram em uma fila e saem a uma taxa constante, como água por um furo. Se a fila está cheia, novas requisições são rejeitadas. A saída é perfeitamente uniforme, exatamente o que você quer diante de um backend que não absorve pico algum, como um sistema legado ou uma API de terceiros que você revende.
O custo é latência. Uma requisição que chega a uma fila quase cheia espera em vez de falhar rápido, e um cliente não distingue um servidor lento de uma requisição enfileirada. Use-o para moldar tráfego que entra em algo frágil; prefira token bucket quando estiver protegendo seu próprio serviço elástico.
Janelas fixas e deslizantes
Uma janela fixa conta requisições por período de calendário: 1.000 por hora, zerada na hora cheia. É trivial de implementar com um contador e uma chave, e tem um defeito bem conhecido: o pico de borda. Um cliente que envia 1.000 requisições às 10:59:59 e outras 1.000 às 11:00:01 ficou dentro da política enquanto entregava 2.000 requisições em dois segundos, o dobro do seu pico pretendido.
Uma janela deslizante corrige isso contando sobre o período anterior em vez do bloco de calendário atual. Às 11:00:01 ela ainda vê as requisições das 10:59:59 e rejeita o excesso. A versão exata guarda um registro de tempo por requisição, o que custa memória; um meio-termo comum pondera a contagem da janela anterior pela parte que ainda se sobrepõe, preciso o bastante para quase qualquer API com uma fração do estado.
Como escolher seus limites
Escolha números a partir de medições, não de uma cifra redonda que pareça generosa. Uma sequência que funciona:
- Meça seu teto. Faça testes de carga até a latência degradar. Essa vazão, menos uma folga, é sua capacidade real.
- Divida pelos clientes simultâneos esperados. Esse é o ponto de partida de um limite por cliente, não a resposta final.
- Olhe seu tráfego atual. Encontre o percentil 95 e o 99 de requisições por cliente. Um limite abaixo do percentil 99 vai te acordar por causa de usuários legítimos.
- Dê folga para picos. De 10 a 20 vezes a taxa por segundo é um tamanho de balde comum; absorve carregamentos de página normais sem permitir abuso sustentado.
- Divida em faixas. Clientes anônimos, autenticados e pagantes não deveriam dividir um limite. Cobrar mais por um teto maior também é a forma mais limpa de precificar uma API.
- Observe antes de aplicar. Registre por uma semana o que teria sido rejeitado antes de começar a rejeitar.
A chave pela qual você conta importa tanto quanto o número. Por IP é a única opção para tráfego anônimo, mas castiga redes compartilhadas e NAT; por chave de API é justo e o padrão correto para chamadas autenticadas; por conta impede que um cliente compre capacidade extra criando chaves. Muitas APIs aplicam as três ao mesmo tempo, como um limite global, um por chave e um por endpoint nas rotas caras.
Com um número em mãos, a aritmética de convertê-lo em intervalo entre requisições é fácil de errar por pouco. A calculadora de limite de requisições converte um limite e uma janela no atraso mínimo entre requisições, na taxa sustentada segura e em um valor de Retry-After que você pode publicar.
Os cabeçalhos que os clientes precisam
Um limite que o cliente não consegue ver é um limite no qual o cliente vai bater. Envie seu estado em todas as respostas, não apenas nas rejeições:
RateLimit-Limit— o teto da janela atual.RateLimit-Remaining— quantas requisições restam nela.RateLimit-Reset— quando a cota se renova, em segundos a partir de agora.Retry-After— em um429ou503, quanto esperar. Um número de segundos ou uma data HTTP.
As grafias X-RateLimit-* continuam muito difundidas e funcionam perfeitamente; os nomes sem prefixo acima são a forma padronizada, e enviar ambos durante uma transição não custa nada. O importante é que os valores estejam presentes e corretos, porque permitem a um bom cliente marcar seu próprio ritmo e nunca ver um 429.
Quando você rejeitar, devolva 429 Too Many Requests, nunca 403 e nunca um 500 genérico. O 429 é o único código que diz ao cliente que a requisição estava correta e vai funcionar depois, que é o único sinal capaz de produzir uma repetição correta. Nossa referência de códigos de status HTTP cobre os códigos relacionados e o que cada um exige de um cliente.
Como lidar com um 429 como cliente
Do outro lado da conexão, as regras são curtas e quase sempre subimplementadas:
- Respeite o
Retry-After. Se o servidor diz quanto esperar, espere isso. Nada que você faça estará melhor informado. - Caso contrário, recue exponencialmente. Espere 1 s, 2 s, 4 s, 8 s, até um teto. Repetir na hora transforma uma sobrecarga em uma correria autoinfligida.
- Adicione variação aleatória. Varie cada espera em até algumas centenas de milissegundos. Sem isso, todos os clientes que falharam juntos repetem juntos, e seu plano de espera reproduz o pico que devia espalhar.
- Limite as tentativas. De três a cinco repetições e então reporte a falha. Repetições infinitas escondem uma indisponibilidade real.
- Marque seu ritmo pelos cabeçalhos. Leia o
RateLimit-Remaininge desacelere antes de ser rejeitado. É a diferença entre um cliente que funciona e um que funciona quase sempre. - Nunca repita um
4xxque não seja429. Um400ou422falhará igual todas as vezes, porque o problema é a própria requisição.
Erros comuns a evitar
- Devolver
403em vez de429. Clientes leem403como permanente e param, ou repetem às cegas; nenhum dos dois comportamentos serve. - Omitir o
Retry-After. Você pediu ao cliente que adivinhasse, e o palpite comum é «agora mesmo». - Limitar só por IP. Um escritório inteiro atrás de um único NAT vira um cliente, e um raspador distribuído vira mil.
- Contar todos os endpoints igual. Uma leitura em cache e um relatório de oito segundos não deveriam custar uma ficha cada; pondere as rotas caras ou dê a elas um limite próprio.
- Uma janela fixa com limite apertado. O pico de borda faz seu pico real valer o dobro do número publicado.
- Nenhuma folga para picos. Um limite perfeitamente uniforme rejeita tráfego normal, porque clientes reais chegam em grupos.
- Limites não documentados. Se o número não está na sua documentação e nos seus cabeçalhos, cada integrador o descobre em produção.
- Repetir sem variação aleatória. Repetições sincronizadas são o caminho para um pico breve se tornar duradouro.
Calcule seus próprios limites
Um bom limite de requisições é entediante: os clientes marcam o ritmo pelos seus cabeçalhos, picos são absorvidos, abusos são contidos e ninguém percebe. Chegar lá é, sobretudo, aritmética e honestidade sobre sua capacidade real. Parta de um limite e uma janela que você realmente sustenta, converta-os no intervalo e no Retry-After de que seus clientes precisam, publique os dois e registre os quase-excessos para distinguir um limite apertado demais de um cliente mal comportado.
Ferramentas e guias relacionados:
- Calculadora de limite de requisições — transforma limite e janela em intervalos, picos e
Retry-After. - Códigos de status HTTP — o que
429,503e os demais exigem de um cliente. - Códigos de status HTTP: guia completo — todas as classes de resposta explicadas.
- Consulta de DNS — confirme qual host o tráfego da sua API realmente alcança.
Perguntas frequentes
Qual é um bom limite padrão para uma API pública?⌄
Não há número universal, porque depende do que uma requisição custa a você. Um ponto de partida comum para uma API JSON com muita leitura é 1.000 requisições por hora por chave com um pico de 20 a 60, e depois ajustar pelos seus próprios percentis. Meça sua vazão sustentável, divida pelos clientes simultâneos esperados e mantenha o limite acima do percentil 99 do tráfego legítimo para não ser acordado por usuários reais.
Qual é a diferença entre token bucket e leaky bucket?⌄
O token bucket permite picos até o tamanho do balde e depois se acomoda na taxa de reabastecimento, o que combina com APIs públicas porque clientes reais chegam em grupos. O leaky bucket enfileira as requisições e as libera a taxa constante, então a saída é perfeitamente uniforme, mas as requisições esperam em vez de falhar rápido. Use leaky bucket diante de um backend que não absorve pico algum e token bucket para todo o resto.
Por que uma janela fixa é um problema?⌄
Por causa do pico de borda. Um cliente que gasta toda a cota no fim de uma janela e toda a cota no início da seguinte entrega o dobro do seu pico pretendido em poucos segundos, enquanto tecnicamente fica dentro da política. Uma janela deslizante conta sobre o período anterior, então esse padrão é corretamente rejeitado.
Qual código de status um limitador deve devolver?⌄
429 Too Many Requests, com um cabeçalho Retry-After. É o único código que diz ao cliente que a requisição era válida e vai funcionar depois, e é isso que produz uma repetição correta. Um 403 se lê como permanente e um 500 como falha do servidor, então ambos levam os clientes a se comportar mal.
Como meu cliente deve lidar com um 429?⌄
Respeite o Retry-After se estiver presente. Se não estiver, recue exponencialmente (1 s, 2 s, 4 s, 8 s) com variação aleatória em cada espera, para que clientes que falharam juntos não repitam juntos. Limite as tentativas a três ou cinco e então reporte a falha. Melhor ainda: leia o RateLimit-Remaining em cada resposta e desacelere antes de ser rejeitado.
Devo limitar por endereço IP ou por chave de API?⌄
Por chave de API para tráfego autenticado: é justo, sobrevive a mudanças de rede do cliente e permite oferecer faixas. O IP é a única opção para requisições anônimas, mas trata um escritório inteiro atrás de um NAT como um único cliente e um raspador distribuído como muitos. A maioria das APIs maduras aplica os dois, mais um limite por endpoint mais rígido nas rotas caras.
Mais de 15 anos de experiência prática em desenvolvimento web e segurança. Foco em segurança web prática: manter sites seguros, confiáveis e fáceis de diagnosticar. O BuildToolForge existe para tornar essas verificações gratuitas, privadas e compreensíveis. As ferramentas rodam no seu navegador sempre que possível, e nada do que você digita em uma ferramenta é armazenado.
Como escrevemos nossos guias: Cada guia nasce da experiência prática, é conferido com os padrões oficiais e testado com nossas próprias ferramentas em domínios reais. Atualizamos os guias quando padrões ou ferramentas mudam. Encontrou um erro? Escreva para contact@buildtoolforge.com.