Demo Tipo · 14

Pesquisa / explicador de funcionalidade

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

1

O que a limitação de taxa faz


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.

Por baixo dos panos

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.

2

O balde, desenhado


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.

reabastece r capacidade B = 10 requisição pega 1 200 OK
Leia da esquerda → direita: uma requisição pega 1 token do balde; um balde cheio deixa rajadas passarem, um balde vazio retorna 429.
tokens 10 / 10 · negadas 0
3

O código


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.

limiter/token_bucket.py
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

Encontre você mesmo: grep -rn "class TokenBucket" limiter/

4

FAQ


O tráfego real é irregular. Uma página que dispara seis chamadas de API ao carregar estouraria um teto perfeitamente constante mesmo que o usuário esteja se comportando bem. A 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.
Leia o cabeçalho 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.
Cada servidor mantendo seu próprio balde em memória multiplicaria o limite real pelo número de servidores. Coloque o estado do balde em um armazenamento compartilhado (a config define 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.
Um contador de janela fixa é o mais barato de construir, mas deixa um chamador enviar uma janela inteira de requisições bem no fim de uma janela e de novo no início da seguinte — uma rajada de 2× na emenda. O balde de tokens suaviza isso e te dá uma separação limpa entre rajada e sustentado. Escolha janela fixa apenas quando a limitação aproximada serve e a simplicidade vence.