Balde furado (leaky bucket)
Um balde com um furo no fundo. A água entra na taxa que quiser, e sai pelo furo em uma taxa constante. Despeje mais rápido do que ele escoa e o balde enche; continue e ele transborda.
A água são as requisições. O furo é a sua taxa de processamento.
O balde furado (leaky bucket) mantém as requisições recebidas em uma fila e as processa em uma taxa fixa, então o que chega ao servidor é suave, não importa o quão irregular tenha sido a chegada.
Observando o balde encher e escoar
Capacidade de cinco requisições, processando duas por segundo, começando vazio:
| Segundo | Chegam | Enfileiradas | Processadas | Na fila depois | Descartadas |
|---|---|---|---|---|---|
| 1 | 4 | 4 | 2 | 2 | 0 |
| 2 | 4 | 3, então 5 na fila | 2 | 3 | 1 |
| 3 | 0 | 0 | 2 | 1 | 0 |
| 4 | 0 | 0 | 1 | 0 | 0 |
É no segundo dois que a capacidade se mostra um problema. Quatro requisições chegam contra uma fila que já tem duas, e só cabem três. A oitava requisição é descartada de imediato.
Duas propriedades surgem daí:
- A taxa de saída nunca varia. Duas por segundo, tenham chegado oito requisições ou nenhuma.
- A fila é FIFO (primeiro a entrar, primeiro a sair). A requisição que chegou primeiro é processada primeiro.
Um token bucket diz: gaste seus tokens quando quiser. Um leaky bucket diz: entre na fila, eu te processo no meu ritmo.
Requisições só são descartadas quando a própria fila está cheia, então o balde absorve uma rajada em vez de rejeitá-la.
Em que é bom e em que é ruim
| Pontos fortes | Pontos fracos |
|---|---|
| Suaviza rajadas em uma taxa de saída constante | Sem flexibilidade para um pico legítimo |
| A fila evita sobrecarga adiante no sistema | Prioriza a estabilidade do sistema em detrimento da experiência do usuário |
| Simples de entender e implementar | Clientes esperam mesmo quando o servidor teria conseguido atender |
| Carga previsível, seja lá o que chegar | A latência cresce com a profundidade da fila |
Os pontos fracos são todos a mesma escolha vista de ângulos diferentes. Um leaky bucket protege o servidor fazendo os clientes esperarem, e faz isso mesmo quando o servidor tinha capacidade sobrando.
Isso combina bem com gerenciamento de banda de rede, streaming de vídeo e tratamento constante de requisições no servidor, onde uma taxa previsível vale mais do que uma resposta rápida a uma rajada.
Isso é o ponto forte quando você precisa de carga previsível, e o ponto fraco quando um cliente está esperando por algo que o servidor poderia ter atendido na hora.
Coloque em prática
Um leaky bucket com capacidade 5, escoando 2 requisições por segundo, começando vazio.
- Seis requisições chegam de uma vez. O que acontece com cada uma?
- Quanto tempo a sexta requisição a chegar espera antes de ser processada, se é que ela consegue entrar?
- As mesmas seis chegam, mas espalhadas uma por segundo. O que acontece?
- Qual algoritmo seria mais adequado para um endpoint que chama um provedor de pagamento que cobra por requisição, e por quê?
Compare suas respostas
| # | Resposta | Por quê |
|---|---|---|
| 1 | Cinco entram na fila, uma é descartada | A fila comporta cinco e nada escoou ainda, já que a rajada é instantânea |
| 2 | Ela nunca entra | A sexta é a que é descartada. A quinta é a última aceita, e a duas por segundo ela espera dois segundos e meio |
| 3 | Todas as seis são processadas, nenhuma descartada, nenhuma esperando | Uma por segundo é mais lento do que o escoamento de duas por segundo, então a fila nunca se acumula |
| 4 | Leaky bucket | A restrição está downstream e custa dinheiro por chamada, então uma taxa de saída previsível é o que você quer. Um token bucket transformaria uma rajada de requisições em uma rajada de cobranças |
A pergunta três é a que vale a pena guardar: nenhum desses algoritmos faz absolutamente nada com o tráfego dentro do limite. Eles só ficam visíveis nas bordas.
Para onde isso vai a seguir
Cinco algoritmos, e todos eles terminam uma requisição que passa do limite com uma recusa ou uma espera imposta silenciosamente.
O throttling torna a espera deliberada e visível, desacelerando um cliente à medida que ele se aproxima de um limite em vez de recusá-lo justo no limite, e depois combina os dois em uma única solução.

