Explicação da limitação de taxa de API: algoritmos, cabeçalhos e tratamento de erros 429

  1. Início
  2. Blog
  3. Desenvolvimento de software

Desenvolvimento de Software

Explicação da limitação de taxa de API: Algoritmos, cabeçalhos e tratamento de erros 429

Os limites de taxa protegem as APIs contra sobrecarga e abuso. Aprenda como os principais algoritmos se comportam, como é uma boa resposta 429 e como os clientes devem recuar, usando uma simulação que executamos.

8 min de leitura
Explicação da limitação de taxa de API: algoritmos, cabeçalhos e tratamento de erros 429

Principais pontos

  • A limitação de taxa limita quantas solicitações um cliente pode fazer em um período de tempo.
  • O depósito de tokens permite rajadas curtas enquanto impõe uma taxa média.
  • Uma simples janela fixa pode deixar passar o dobro do limite no limite da janela.
  • Retorne 429 Too Many Requests com um cabeçalho Retry-After e faça com que os clientes recuem com instabilidade.

Um script com erros chama sua API em um loop apertado. Sem limites, isso pode tornar o serviço mais lento para todos os outros usuários ou gerar uma grande conta na nuvem. A limitação da taxa de API é a barreira de proteção que impede que um único cliente receba mais do que sua parte justa.

Para mostrar como os algoritmos comuns se comportam, escrevemos pequenas versões do Python e as alimentamos com tempos de solicitação simulados. As saídas abaixo vêm dessa execução. Eles estão ensinando modelos, não códigos de produção, e gateways reais têm mais recursos.

O que é limitação de taxa?

A limitação de taxa conta solicitações por cliente e rejeita ou atrasa solicitações acima de um limite acordado, como 100 solicitações por minuto. Uma ideia relacionada, aceleração, geralmente significa desacelerar as solicitações em vez de rejeitá-las. Uma cota geralmente é um subsídio maior durante um período mais longo, como 10.000 chamadas por mês em um plano de preços.

Por que as APIs precisam disso

  • Estabilidade: picos de tráfego não podem sobrecarregar bancos de dados ou serviços downstream.
  • Justiça: um cliente pesado não pode fazer com que os outros morram de fome.
  • Segurança: os limites retardam as tentativas de login de força bruta e a raspagem.
  • Controle de custos: operações caras, como chamadas de modelo de IA, permanecem dentro do orçamento.

A limitação de taxa é um controle central no Top 10 de segurança da API OWASP, sob consumo irrestrito de recursos. Nosso guia de teste de API com Postman mostra como enviar as solicitações repetidas necessárias para verificá-lo.

Balde de tokens

Imagine um balde que contém até 5 fichas. Cada solicitação leva um token. Os tokens são recarregados a 1 por segundo e o intervalo nunca contém mais de 5. Se o intervalo estiver vazio, a solicitação será rejeitada.

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 solicitações de uma vez e mais tarde:

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

Os primeiros 5 explodiram, depois o balde ficou vazio. Dois segundos depois, 2 tokens foram recarregados, então mais 2 solicitações foram aprovadas. Após uma longa pausa, o bucket estava cheio novamente, mas limitado a 5. Esse comportamento de intermitência e estabilização é adequado ao tráfego real, e é por isso que os buckets de token são comuns em gateways de API. O leaky bucket é um parente próximo que processa solicitações a uma taxa fixa, suavizando a saída em vez de permitir rajadas.

Janela fixa vs janela deslizante

Um contador de janela fixa é a abordagem mais simples: permita 10 solicitações por minuto e redefina o contador quando o minuto mudar. Tem uma falha conhecida no limite. Enviamos 10 solicitações em 59,9 segundos e mais 10 em 60,0 segundos, com um limite de 10 por janela de 60 segundos:

fixed window allowed around boundary: 20 of 20
sliding log allowed around boundary:  10 of 20

A janela fixa permitiu todas as 20 solicitações em um décimo de segundo, o dobro da taxa pretendida, pois caíram em duas janelas diferentes. Um registro deslizante lembra o horário de cada solicitação recente e conta as dos últimos 60 segundos, portanto, permitiu corretamente apenas 10.

A compensação é a memória. Um log deslizante armazena um carimbo de data/hora por solicitação. O balcão de janela deslizante é um meio-termo popular. Ele estima a taxa combinando as contagens de janelas atuais e anteriores, usando pouca memória e com boa precisão.

Comparação de algoritmos

Algoritmo Explosões Precisão Memória
Janela fixa Até 2x nos limites Baixo Muito baixo
Registro deslizante Não Exato Alto
Balcão de janela deslizante Pequeno Bom Baixo
Balde de tokens Permitido até a capacidade Bom Baixo
Balde com vazamento Suavizado Bom Baixo

O que limitar

  • Chave de API ou ID de usuário: a opção mais justa para APIs autenticadas.
  • Endereço IP: útil para endpoints públicos, mas muitos usuários podem compartilhar um IP e os invasores podem alterná-los.
  • Endpoint: operações caras, como pesquisa, exportação ou login, merecem limites mais rígidos.
  • Nível de plano: clientes gratuitos e pagos geralmente recebem limites diferentes.

Os endpoints de login precisam de cuidados especiais. Limite por conta e por IP, para que os invasores não possam simplesmente espalhar suposições entre muitos IPs ou muitas contas.

A resposta 429

Quando um cliente ultrapassar o limite, retorne HTTP 429 Too Many Requests, e não 500 ou 403. Inclua cabeçalhos que informem ao cliente o que aconteceu e quando tentar novamente. Nossa simulação produziu este conjunto para um cliente sem solicitações restantes:

HTTP/1.1 429 Too Many Requests
RateLimit-Limit: 100
RateLimit-Remaining: 0
RateLimit-Reset: 30
Retry-After: 30

Retry-After é um cabeçalho HTTP padrão. Os RateLimit-* cabeçalhos vêm de um rascunho da IETF e muitas APIs usam suas próprias X-RateLimit-* variantes. Seja o que for que você escolher, documente. Para obter mais informações sobre códigos de status, consulte nossa folha de referências de códigos de status HTTP.

Lidando com limites como cliente

Tentar novamente imediatamente após um 429 piora as coisas. Se milhares de clientes fizerem isso ao mesmo tempo, eles atingirão o servidor em ondas sincronizadas. A solução é espera exponencial com jitter: espere mais tempo após cada falha e adicione aleatoriedade.

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]

Isso é “jitter total”: uma espera aleatória entre zero e um teto crescente exponencialmente. As esperas parecem irregulares e esse é o ponto. Os clientes se espalham em vez de tentarem juntos novamente. Propagamos o gerador aleatório para que a saída pudesse ser reproduzida.

Lista de verificação do cliente: honre Retry-After quando estiver presente, limite o número de novas tentativas, tente novamente apenas as solicitações que podem ser repetidas com segurança e observe o cabeçalho de solicitações restantes para que você possa desacelerar antes de atingir o limite.

Limitação de taxa distribuída

Com vários servidores API por trás de um balanceador de carga, cada servidor contando sozinho permite que um cliente exceda o limite, espalhando solicitações entre eles. As equipes geralmente mantêm contadores em um armazenamento compartilhado como o Redis, com operações atômicas ou um script curto para que dois servidores não possam receber o último token. Gateways como Kong, NGINX, Envoy e gateways de API em nuvem fornecem isso como configuração. Não executamos uma configuração distribuída para este artigo.

Testando limites de taxa

  • Envie solicitações até o limite e confirme se foram bem-sucedidas.
  • Envie mais um e confirme um 429 com cabeçalhos corretos.
  • Aguarde o tempo de redefinição e confirme se as solicitações foram bem-sucedidas novamente.
  • Verifique os limites por chave: o uso de um cliente não deve bloquear outro.
  • Teste o limite entre janelas para o problema de explosão dupla.
  • Use uma ferramenta de carregamento, conforme abordado em teste de carga versus teste de estresse, para verificar o comportamento sob forte simultaneidade.

Em testes unitários, injete a hora atual, como nossa simulação faz com now, para que os testes nunca precisem dormir.

Projetando limites com os quais os usuários podem conviver

Escolher os números é tão importante quanto escolher o algoritmo. Comece com o tráfego real: veja quantas solicitações seus clientes legítimos mais frequentes fazem por minuto e defina limites confortavelmente acima disso. Um limite que bloqueia o uso normal cria tickets de suporte, não segurança.

  • Publique os limites na documentação da API, por endpoint e por plano.
  • Avisar antes de bloquear. Os cabeçalhos que mostram as solicitações restantes permitem que clientes bem comportados diminuam a velocidade por conta própria.
  • Ofereça alternativas para pesquisas pesadas, como webhooks, endpoints em massa ou páginas maiores.
  • Monitore as taxas 429. Um aumento repentino pode significar um ataque, um lançamento de cliente com bugs ou limites que agora estão muito apertados.
  • Conceder exceções deliberadamente, por exemplo, limites aumentados para um parceiro, registrados na configuração em vez de codificados.

Decida também o que acontece com as solicitações que chegam um pouco acima do limite. Algumas APIs enfileiram brevemente um pequeno número de solicitações extras em vez de rejeitá-las, o que suaviza picos curtos. Outros dão prioridade a endpoints essenciais, como pagamentos, em detrimento de endpoints menos críticos, como análises, para que o tráfego importante continue fluindo quando o sistema estiver sob pressão.

Considerações finais

Uma boa limitação de taxa é um contrato entre a API e o cliente. O servidor escolhe um algoritmo justo, geralmente um token bucket ou janela deslizante, e explica seus limites claramente com 429 e Retry-After. O cliente respeita esses sinais e recua com instabilidade. Comece com limites generosos por chave de API, observe o uso real e restrinja apenas onde for necessário.

Perguntas frequentes

O que é limitação de taxa de API?

É um limite de quantas solicitações um cliente pode fazer a uma API em um determinado momento, como 100 por minuto. Solicitações acima do limite são rejeitadas ou atrasadas.

O que significa HTTP 429?

429 Too Many Requests significa que o cliente excedeu um limite de taxa. A resposta geralmente inclui um cabeçalho Retry-After informando quanto tempo esperar.

Qual é o algoritmo do token bucket?

Cada solicitação usa um token de um balde que é recarregado a uma taxa constante até o máximo. Ele permite rajadas curtas enquanto impõe uma taxa média.

Qual é a diferença entre limitação de taxa e limitação?

A limitação de taxa geralmente rejeita solicitações acima do limite. A limitação geralmente os retarda ou os coloca na fila. Os termos são freqüentemente usados ​​de forma intercambiável.

Como um cliente deve lidar com os limites de taxas?

Respeite Retry-After, tente novamente com espera exponencial e jitter, limite o número de novas tentativas e diminua a velocidade quando as solicitações restantes ficarem baixas.

Continue aprendendo

Trabalhe com Stack Quora

Precisa de ajuda com testes, WordPress ou SEO?

Ajudamos as equipes a fornecer software melhor e a expandir seus sites. Conte-nos no que você está trabalhando e sugeriremos um próximo passo claro.

Continue lendo

Mais guias sobre testes, IA e desenvolvimento moderno

Gostou deste artigo? Escolha um tópico e vá direto para nossos tutoriais mais recentes.

Inteligência artificial

Explicação das alucinações de IA: por que os modelos de linguagem inventam as coisas e como reduzi-las

Explicação das alucinações de IA: o que são, por que os modelos de linguagem as produzem, tipos comuns, como reduzi-las com aterramento e instruções…

Leia o artigo →
DevOps

Variáveis de ambiente explicadas: arquivos .env, segredos e configuração bem feitos

Variáveis de ambiente explicadas com exemplos de Python que executamos: leitura e configuração, por que cada valor é uma string, arquivos .env, hera…

Leia o artigo →
Desenvolvimento de software

Explicação da limitação de taxa de API: algoritmos, cabeçalhos e tratamento de erros 429

Limitação de taxa de API explicada com uma simulação que executamos: token bucket, janela fixa, janela deslizante, 429 respostas, cabeçalhos de limi…

Leia o artigo →
Automação de testes

Zombando em Python: unittest.mock, patch e os erros que fazem os testes mentirem

Zombaria em Python com unittest.mock, testado: Mock e return_value, side_effect, patch onde um nome é usado, especificação e autospec, zombaria de d…

Leia o artigo →
Teste de software

Cobertura de código explicada: cobertura de linha versus filial e o que 100% realmente significa

Cobertura de código explicada com uma execução cobertura.py real: cobertura de linha, ramal e condição, leitura de um relatório, por que 100% de cob…

Leia o artigo →
Bancos de dados e SQL

DELETE vs TRUNCATE vs DROP em SQL: diferenças, reversão e quando usar cada um

DELETE vs TRUNCATE vs DROP explicado com SQL testado: o que cada um remove, rollback, aciona, redefinição de identidade, velocidade e como PostgreSQ…

Leia o artigo →
Bancos de dados e SQL

Exibições SQL explicadas: crie, use e evite as armadilhas, com exemplos

Visualizações SQL explicadas com consultas que executamos: criação de uma visualização, resultados ao vivo, ocultação de colunas, desempenho, visual…

Leia o artigo →
Desenvolvimento de software

Interface TypeScript vs tipo: diferenças reais, testadas com o compilador

Interface TypeScript versus tipo, verificada com o compilador real: o que ambos podem fazer, o que apenas um pode fazer, mesclagem de declarações, e…

Leia o artigo →
Desenvolvimento de software

Python *args e **kwargs explicados: funções flexíveis com exemplos claros

Python *args e **kwargs explicados com o código que executamos: empacotamento e descompactação, ordem dos parâmetros, argumentos somente de palavras…

Leia o artigo →
Desenvolvimento de software

Funções Python Lambda: sintaxe, usos reais e quando não usá-los

Funções lambda do Python explicadas com o código que executamos: sintaxe, classificação com chave, mapa e filtro, fechamentos, armadilha de ligação …

Leia o artigo →
Inteligência artificial

O que são agentes de IA? Como eles funcionam, com um loop de agente simples que você pode executar

O que são agentes de IA? Um guia simples para o loop do agente, ferramentas, memória e proteções, com um pequeno loop Python que executamos, riscos …

Leia o artigo →
DevOps

Monitoramento versus observabilidade: a verdadeira diferença, com logs, métricas e rastreamentos

Explicação do monitoramento versus observabilidade: falhas conhecidas e desconhecidas, logs, métricas e rastreamentos, um passo a passo do incidente…

Leia o artigo →
DevOps

Docker Volumes vs Bind Mounts: persista os dados do contêiner da maneira certa

Volumes Docker versus montagens de ligação explicadas: por que os dados do contêiner desaparecem, volumes nomeados, montagens de ligação, tmpfs, exe…

Leia o artigo →
Automação de testes

TDD vs BDD: principais diferenças, um recurso criado de ambas as maneiras e quando usar cada um

TDD vs BDD explicado com um recurso de desconto construído em ambos os sentidos: refatoração vermelho-verde com o código que executamos, cenários da…

Leia o artigo →
Desenvolvimento de software

Git merge vs rebase: diferenças, exemplos e quando usar cada um

Git merge vs rebase explicado com saída real do log, uma tabela comparativa, a regra de ouro do rebase e um fluxo de trabalho seguro para equipes.

Leia o artigo →
Desenvolvimento de software

List comprehension em Python: sintaxe, exemplos e quando evitar

List comprehension em Python explicada: sintaxe, filtros, if-else, laços aninhados, tempos medidos e quando um laço for comum é a melhor escolha.

Leia o artigo →
Bancos de dados e SQL

SQL JOIN explicado com exemplos (Inner, Left, Right, Full)

Entenda os joins SQL passo a passo com tabelas e consultas de exemplo: INNER, LEFT, RIGHT, FULL, CROSS e SELF, além de erros comuns e dicas de desem…

Leia o artigo →