Arquitetura real · Pleno
Stripe: escalando a API com rate limiters
Arquitetura real em produção. Pontos centrais: algoritmos de rate limiting e controle de sobrecarga.
Resposta curta
Arquitetura real em produção. Pontos centrais: algoritmos de rate limiting e controle de sobrecarga. Nas primeiras vezes em que o tráfego sobe de repente, é razoável apenas somar capacidade de infraestrutura. Numa API em produção, porém, também é preciso garantir que um mau ator não afete a disponibilidade para os demais, de propósito ou sem querer.
01 · CONTEXTO
Por que limitar uma API em produção
Nas primeiras vezes em que o tráfego sobe de repente, é razoável apenas somar capacidade de infraestrutura. Numa API em produção, porém, também é preciso garantir que um mau ator não afete a disponibilidade para os demais, de propósito ou sem querer.
Segundo o Stripe, limitar o tráfego ajuda em cenários como estes: um usuário provoca um pico e os outros precisam continuar atendidos; um usuário manda muitas requisições de baixa prioridade que não podem atrapalhar as de alta prioridade; algo falha internamente e é preciso descartar requisições de baixa prioridade.
O Stripe distingue dois mecanismos. O limitador de taxa é apropriado quando os usuários podem mudar o ritmo das chamadas sem alterar o resultado. O load shedding, por sua vez, descarta requisições de baixa prioridade durante incidentes para que as críticas passem, e decide pelo estado do sistema inteiro, não por quem fez a requisição.
| Critério | Limitador de taxa | Load shedder |
|---|---|---|
| Quando age | Na operação do dia a dia | Durante incidentes |
| Quando é apropriado | Quando os usuários podem mudar o ritmo sem afetar o resultado | Quando é preciso descartar baixa prioridade para as críticas passarem |
| Base da decisão | O ritmo de cada usuário | O estado do sistema inteiro |
02 · OS QUATRO LIMITADORES
Limitadores e load shedders em conjunto
O Stripe opera quatro tipos de limitadores em produção. O limitador de taxa de requisições é, de longe, o mais importante e o ponto de partida recomendado.
O limitador de taxa de requisições restringe cada usuário a um número máximo de requisições por segundo. O Stripe permite estourar o teto por pouco tempo, para picos súbitos em eventos em tempo real, e mantém o mesmo comportamento de limitação nos modos de teste e produção.
O limitador de concorrência fala em quantas requisições podem estar em andamento ao mesmo tempo, em vez de quantas por segundo. Alguns endpoints consomem muito mais recursos, e usuários frustrados com a espera tentam de novo, somando demanda a um recurso já sobrecarregado. Antes de adotá-lo, o Stripe lidava com frequência com contenção nos endpoints mais caros; segundo o post, ele resolveu o problema por completo.
O load shedder de uso da frota separa o tráfego em métodos críticos, como criar cobranças, e não críticos, como listar cobranças. Um cluster Redis conta as requisições de cada tipo e uma fração da infraestrutura fica sempre reservada às críticas, de modo que as não críticas acima da sua parte são rejeitadas.
O load shedder de utilização de workers é a última linha de defesa. Se uma máquina está ocupada demais, passa a descartar requisições menos críticas, começando pelo tráfego de teste, e escala para mais tráfego se isso não bastar. Descartar e devolver tráfego precisa ser lento, senão o sistema oscila entre os dois estados. Segundo o post, ele limita o impacto de incidentes que já estão acontecendo, enquanto os três primeiros são preventivos.
| Critério | Requisições por segundo | Concorrência | Uso da frota | Utilização de workers |
|---|---|---|---|---|
| O que controla | Requisições de cada usuário por segundo | Requisições em andamento ao mesmo tempo | Fração da frota reservada às requisições críticas | Workers com capacidade livre |
| Frequência de disparo | Constantemente | Bem menos que o limitador de taxa | Fração muito pequena das requisições | Muito raramente, só em grandes incidentes |
| Papel | Prevenir abuso | Controlar os endpoints que consomem muita CPU | Garantir parte da frota para o que é mais importante | Controle de danos em incidentes em curso |
A requisição do cliente chega à camada de limitadores, que decide se ela segue adiante.
A camada consulta o balde de tokens do usuário no Redis e retira um token a cada requisição.
Com o balde vazio, a requisição é rejeitada: é o limitador de taxa agindo sobre aquele usuário.
Um cluster Redis também conta as requisições de cada tipo; as não críticas acima da parte que lhes cabe são rejeitadas para sobrar capacidade às críticas.
Nos workers, se a fila aperta, a última linha de defesa passa a descartar tráfego menos crítico, a começar pelo modo de teste.
03 · IMPLEMENTAÇÃO
Token bucket em Redis
O Stripe usa o algoritmo token bucket, com um host central de baldes: a cada requisição retira-se um token, e novos tokens pingam aos poucos no balde. Com o balde vazio, a requisição é rejeitada. Cada usuário tem o seu balde, e a implementação usa Redis, que pode ser operado por conta própria ou, na AWS, ser um serviço gerenciado como o ElastiCache.
Ao rejeitar, é preciso decidir entre HTTP 429 e HTTP 503 conforme a situação, e a mensagem devolvida deve ser acionável para quem chama.
04 · LANÇAMENTO SEGURO
Introduzir limitadores sem quebrar usuários
Um limitador novo pode bloquear quem não deveria. O Stripe recomenda kill switches para desligá-lo se atuar por engano, com feature flags como válvula de escape humana, além de alertas e métricas para saber com que frequência ele dispara.
Também recomenda o dark launch de cada limitador, para observar o tráfego que ele bloquearia. A ideia é achar limiares que mantenham a API no ar sem afetar os padrões de requisição existentes dos usuários, o que pode envolver trabalhar com alguns deles para mudar o código.
No caminho normal, o middleware consulta o Redis antes de decidir o destino da requisição.
Imagine que o Redis dos limitadores caia ou que haja um bug no código de limitação.
O middleware captura a exceção e falha aberto: a requisição segue ao serviço e a API continua funcional.
Para o caso de os limitadores atuarem por engano, kill switches por feature flag os desligam, e alertas e métricas mostram a frequência de disparo.
05 · LIÇÕES
Por onde começar
Segundo o post, as estratégias não são todas necessárias no primeiro dia. Comece pelo limitador de taxa de requisições e introduza os outros três ao longo do tempo, para prevenir classes diferentes de problemas, à medida que a necessidade aparecer.
Perguntas frequentes
O que é Stripe: escalando a API com rate limiters?
Arquitetura real em produção. Pontos centrais: algoritmos de rate limiting e controle de sobrecarga.
O que o design de Stripe: escalando a API com rate limiters cobre?
Ele está organizado nestas seções: Por que limitar uma API em produção, Limitadores e load shedders em conjunto, Token bucket em Redis, Introduzir limitadores sem quebrar usuários e Por onde começar.
Quanto tempo leva Stripe: escalando a API com rate limiters e qual é o nível?
Leva cerca de 15 minutos para ler e tem nível Pleno.
Agora projete você mesmo
Rode este caso como uma entrevista na escola de System Design: você toma as decisões, o tutor as questiona e você vê a nota do seu desenho.