Use isto quando quiser mergulhar fundo em uma funcionalidade ou mecanismo — uma página focada com sumário na própria página, código em abas (algoritmo / config / uso), um diagrama anotado e um FAQ que responde às perguntas que os leitores de fato fazem.
Este é um exemplar copiável. Leve a seção .demo-card abaixo para uma lição construída a partir de assets/lesson-template.html — os tokens de design, o tech-toggle, as abas e os padrões de SVG já estão conectados para combinar.
Mergulho na funcionalidade · Limitação de taxa com o algoritmo de balde de tokens
Um limitador de taxa decide quantas requisições um único chamador pode fazer em uma dada janela de tempo. Se um cliente fica abaixo da sua cota, toda requisição passa. Se ele de repente inunda o servidor, o limitador começa a recusar requisições — geralmente com um HTTP 429 Too Many Requests — para que um chamador barulhento não deixe todos os outros sem recursos.
O algoritmo de balde de tokens é a forma mais comum de fazer isso. Imagine um balde que guarda tokens. Toda requisição precisa pegar um token para prosseguir. Os tokens pingam de volta a uma taxa constante, e o balde tem um tamanho máximo. Quando o balde está vazio, as requisições são negadas até ele reabastecer — mas, como o balde pode manter uma reserva, rajadas curtas são permitidas enquanto a média de longo prazo permanece limitada.
Pense nisso como… uma catraca que funciona com moedas. Cada entrada custa uma moeda. Uma máquina solta uma moeda nova na bandeja em um ritmo fixo (digamos, 5 moedas por segundo), e a bandeja comporta no máximo 10 moedas. Uma correria rápida pode gastar de uma vez as 10 moedas acumuladas, mas depois disso as pessoas só entram na velocidade em que novas moedas aparecem.
O balde tem dois parâmetros: capacidade B (máximo de tokens, o teto de rajada) e taxa de reabastecimento r (tokens adicionados por segundo, o teto sustentado). O estado por chave são apenas dois números: tokens e last_refill_timestamp.
O reabastecimento é calculado de forma preguiçosa no acesso, em vez de por um temporizador em segundo plano: tokens = min(B, tokens + (now - last_refill) * r). Uma requisição de custo c é admitida se e somente se tokens >= c, decrementando em c; caso contrário, ela é rejeitada e o chamador pode calcular Retry-After = (c - tokens) / r.
Isso difere de um contador de janela fixa (mais barato, mas permite rajadas de 2× nas bordas da janela) e de um balde furado (que molda a saída a uma taxa constante e não permite rajadas de jeito nenhum). O balde de tokens é O(1) em tempo e O(1) em memória por chave, e é por isso que ele sustenta a maioria dos limitadores em produção.
Os tokens pingam pelo topo a uma taxa constante. Cada requisição que você envia drena um token. Gaste a reserva e a próxima requisição será negada — observe o contador.
Três visões da mesma funcionalidade: o algoritmo que decide permitir/negar, a config que você ajusta em produção, e como você o usa como middleware em uma rota.
import time class TokenBucket: def __init__(self, capacity, refill_rate): self.capacity = capacity # B — teto de rajada self.refill_rate = refill_rate # r — tokens / segundo self.tokens = capacity self.updated = time.monotonic() def allow(self, cost=1): now = time.monotonic() elapsed = now - self.updated # reabastecimento preguiçoso, limitado à capacidade self.tokens = min(self.capacity, self.tokens + elapsed * self.refill_rate) self.updated = now if self.tokens >= cost: self.tokens -= cost return True, 0.0 # permitido retry_after = (cost - self.tokens) / self.refill_rate return False, retry_after # negado → 429
# uma política de balde por nível de rota. chave = token de API do cliente. buckets: default: capacity: 10 # permite rajadas curtas de até 10 refill_rate: 5 # sustentado 5 req/s no longo prazo search: capacity: 30 refill_rate: 10 auth_login: capacity: 5 # proteção contra força bruta: rajada apertada refill_rate: 1 storage: redis # estado compartilhado entre os servidores de app key_by: api_token # ou: ip, user_id on_deny: "429" # + cabeçalho Retry-After
from limiter import limit # decorator construído sobre TokenBucket @app.route("/search") @limit(policy="search") # 30 de rajada, 10/s sustentado def search(req): return do_search(req.query) # quando o balde está vazio o decorator faz curto-circuito: # HTTP/1.1 429 Too Many Requests # Retry-After: 2 # X-RateLimit-Remaining: 0
Encontre você mesmo: grep -rn "class TokenBucket" limiter/
capacity do balde é uma poupança que absorve essas rajadas legítimas, enquanto a refill_rate ainda limita a média de longo prazo. Se você realmente precisa de uma saída perfeitamente suave, a variante de balde furado é a indicada.
Retry-After e espere esse número de segundos antes de tentar de novo — não martele imediatamente. Um bom cliente recua exponencialmente com jitter em 429s repetidos. O servidor calcula a espera como (cost − tokens) / refill_rate, então é o tempo exato até existirem tokens suficientes.
storage: redis) e faça o reabastecer-e-decrementar de forma atômica — um pequeno script Lua ou um par INCR/EXPIRE — para que todos os servidores debitem do mesmo balde.