Pular para o conteudo principal

Rate limiting: quando, como e por quê

Como pensar em rate limiting como proteção de capacidade compartilhada, quais estratégias existem e o que realmente importa na prática.

Andrews Ribeiro

Andrews Ribeiro

Founder & Engineer

Trilha

Trilha de system design para entrevistas

Etapa 10 / 19

O problema

Rate limiting aparece em muita conversa como detalhe rápido.

Alguém fala:

  • “coloca um limiter na borda”

e parece que o assunto acabou.

Só que a parte importante não é citar a existência do limitador.

É explicar:

  • o que ele está protegendo
  • para quem o limite vale
  • qual comportamento ele cria quando a carga aperta

Sem isso, o sistema corre dois riscos bem comuns:

  • um cliente consome capacidade demais e piora a vida dos outros
  • o próprio sistema degrada de forma caótica em vez de previsível

Modelo mental

Pense assim:

rate limiting é um contrato de capacidade.

Em português simples, você está dizendo:

  • acima de certo ritmo, este cliente vai ter de esperar, falhar ou ser desacelerado

Isso pode servir para coisas diferentes:

  • proteger API pública
  • reduzir abuso
  • distribuir recurso compartilhado
  • conter burst
  • limitar ações caras, como login, envio de SMS ou geração de relatório

Então a pergunta útil não é:

  • “precisa de rate limiting?”

É esta:

qual capacidade eu estou protegendo, para quem, e com qual comportamento quando o limite for atingido?

Quebrando o problema

Onde o rate limiter costuma ficar

O lugar mais comum é perto da entrada do sistema:

  • API gateway
  • load balancer com regra
  • camada HTTP da aplicação

Quanto mais cedo o bloqueio acontece, menos recurso inútil você gasta.

Mas isso não significa que todo limite vive só na borda.

Tem limite que faz mais sentido perto da regra:

  • por usuário
  • por ação específica
  • por recurso caro
  • por integração externa

Exemplo:

  • limitar requests por API key na borda faz sentido
  • limitar “no máximo 3 SMS por hora para o mesmo usuário” já é mais domínio do produto

Algoritmo muda o comportamento

Não precisa decorar fórmula.

Precisa entender como cada opção se comporta.

Fixed window:

  • simples
  • barato de explicar
  • mas cria efeito estranho na virada da janela

O cliente pode mandar muito no fim de um minuto e muito de novo no começo do próximo.

Sliding window:

  • suaviza essa borda
  • tende a ser mais justo
  • mas costuma ser um pouco mais caro de manter

Token bucket:

  • enche um balde com tokens ao longo do tempo
  • cada request gasta um token
  • permite burst controlado

Em entrevista, token bucket costuma ser uma boa resposta porque equilibra clareza e comportamento real.

Rate limiting distribuído quase sempre pede estado compartilhado

Se você tem várias instâncias e cada uma conta localmente, o cliente pode driblar o limite passando por instâncias diferentes.

Por isso, em sistema distribuído, o contador costuma ir para algum lugar compartilhado.

Redis aparece muito aqui porque:

  • é rápido
  • lida bem com contador e expiração
  • permite operação atômica útil para esse caso

Não é obrigatório em todo cenário.

Mas é um desenho comum e fácil de defender.

A chave do limite muda o efeito

Você pode limitar por:

  • IP
  • usuário
  • API key
  • tenant
  • rota
  • combinação de atributos

Cada escolha protege uma coisa diferente.

Por IP ajuda contra burst de origem específica.

Por usuário ajuda a isolar comportamento individual.

Por API key costuma funcionar bem para integrações de terceiros.

Não existe chave universal.

Existe a chave que melhor separa quem divide aquele recurso.

Limitar demais também machuca uso legítimo

Esse é um ponto que muita gente esquece.

Rate limiting ruim não protege só o sistema.

Também pode punir cliente bom.

Se o limite for duro demais, o produto fica com cara de portão travado.

Então a pergunta madura não é só:

  • “qual o máximo permitido?”

Também é:

  • “qual burst legítimo o uso normal precisa aguentar?”

A resposta ao cliente faz parte do design

Quando o limite estoura, o sistema precisa se comportar de forma compreensível.

Em HTTP, o padrão mais comum é:

  • 429 Too Many Requests

E idealmente com sinal claro sobre:

  • quando tentar de novo
  • qual política está valendo

Cabeçalhos como Retry-After ajudam.

O importante é:

o limite não deve parecer falha aleatória.

Exemplo simples

Imagine uma API pública de consulta de preço.

Sem rate limiting, um cliente descuidado ou agressivo pode disparar milhares de requests por segundo e piorar a latência para todo mundo.

Uma resposta madura poderia ser:

“Vou limitar por API key na borda porque quero proteger capacidade compartilhada por consumidor. Como preciso permitir burst curto, token bucket faz sentido. Como tenho várias instâncias, guardo contagem em Redis. Quando o limite estourar, devolvo 429 com orientação de retry.”

Repare no que essa resposta explica:

  • o que está sendo protegido
  • para quem o limite vale
  • qual algoritmo encaixa
  • onde o estado vive
  • como o cliente descobre o que aconteceu

Erros comuns

  • Tratar rate limiting como detalhe de segurança e esquecer capacidade.
  • Contar localmente em cada instância e achar que está protegido.
  • Escolher algoritmo só pelo nome, sem explicar o comportamento.
  • Bloquear sem resposta clara para o cliente.
  • Usar o mesmo limite para tudo.
  • Não distinguir burst legítimo de abuso real.

Como um senior pensa

Quem tem mais experiência raramente fala só:

  • “coloca rate limiter”

Costuma falar algo mais útil:

“Quero proteger capacidade compartilhada sem punir uso normal. Então vou escolher a chave do limite, o algoritmo e a resposta ao cliente de acordo com quem divide esse recurso e com o burst que o produto precisa tolerar.”

Essa resposta mostra maturidade porque sai do binário “tem ou não tem” e entra no comportamento real do sistema.

Também mostra que rate limiting não é só defesa.

É mecanismo de previsibilidade.

O que o entrevistador quer ver

Em entrevista, rate limiting revela rápido se você pensa em confiabilidade como parte do produto.

O entrevistador normalmente quer ver se você:

  • entende o que está protegendo
  • diferencia algoritmo por comportamento
  • considera distribuição entre instâncias
  • lembra que a resposta ao cliente também faz parte do design

Uma resposta forte costuma ter esta forma:

“Eu começo definindo qual recurso compartilhado está sob risco e quem precisa ser isolado. Depois escolho a chave do limite e o algoritmo de acordo com o burst aceitável. Se o sistema é distribuído, guardo a contagem em estado compartilhado. E trato o estouro de limite como comportamento previsto da API, não como erro genérico.”

Rate limiting não é só muro de defesa. É uma forma de deixar a capacidade compartilhada previsível.

O limite bom protege o sistema sem transformar o produto em punição para quem está usando direito.

Resumo rápido

O que vale manter na cabeça

Checklist de pratica

Use isto ao responder

Você concluiu este artigo

Parte da trilha: Trilha de system design para entrevistas (10/19)

Próximo artigo Load balancing sem caixa preta Artigo anterior Replicação e sharding sem mistério

Continue explorando

Artigos relacionados