Estávamos a Limitar a Taxa dos Nossos Próprios Serviços
A API do Mythex permite 300 pedidos por minuto a partir de um endereço de rede. Esse limite existe para nos proteger de uma pessoa ou de um script que martele a API. Em produção, começou a recusar os nossos próprios serviços — a parte da nossa borda que serve as apps publicadas e o serviço que corre o agente de IA — porque cada um deles contacta a API a partir de apenas alguns endereços. Os pedidos que levam a nossa credencial interna estão agora isentos, e todos os outros continuam limitados exatamente como antes.
O sintoma
A API começou a responder a algumas das nossas próprias chamadas internas com 429 Too Many Requests. Foram atingidos três tipos de chamada, e cada um deles importa para quem usa o Mythex:
- Procurar que app vive num domínio personalizado. Quando um visitante abre uma app publicada no seu próprio domínio, a nossa borda pergunta à API onde está esse site. Um 429 aí é um visitante que não consegue chegar a um site.
- Guardar um turno ativo do agente. Enquanto o agente trabalha, o seu progresso é guardado à medida que avança, para que uma resposta sobreviva a um refresh ou a uma ligação interrompida. Um 429 aí é progresso que não foi guardado.
- Verificar o acesso a uma pré-visualização. A pré-visualização de uma app que estás a construir está protegida, e essa proteção pergunta à API. Um 429 aí é uma pré-visualização que não abre.
Nenhuma destas chamadas era de uma pessoa a usar a API. Eram todas de nós.
Porque aconteceu
Um limite de taxa por endereço assume uma coisa: um endereço é, aproximadamente, um chamador. Para as pessoas, isso é suficientemente próximo. Para a nossa própria infraestrutura, está muito errado.
- O serviço de borda que serve as apps publicadas e as pré-visualizações contacta a API a partir de alguns endereços de saída partilhados. Cada visitante de cada app publicada, e cada verificação de pré-visualização, chega parecendo ter vindo de um desses poucos.
- O orquestrador — o serviço que corre os turnos do agente — contacta a API a partir de um único endereço de contentor. Cada turno a correr, para cada utilizador, partilha esse endereço.
Assim, o orçamento pensado para uma pessoa estava a ser dividido por todo o tráfego de um serviço inteiro. Esses serviços esgotavam-no entre si, e o limitador fez o que lhe foi pedido: recusou-os.
A correção
Os nossos próprios serviços já provam quem são. Cada chamada interna leva um token interno, e cada rota da secção interna da API verifica esse token antes de fazer seja o que for.
O limitador de taxa usa agora essa mesma verificação. Um pedido cujo token corresponde ao interno está numa lista de permissões e não conta para o orçamento por endereço. Tudo o resto é contado exatamente como antes: 300 pedidos por minuto por endereço.
Dois detalhes impediram que isto se tornasse um buraco:
- Um token errado não tem passe. A lista de permissões só corresponde ao token interno real. Um pedido com um token inventado é contado e limitado como qualquer outro, e as rotas internas continuam a rejeitá-lo com
401 Unauthorized. - O limite em si não mudou. Não aumentámos o número para abrir espaço. Aumentá-lo teria escondido o problema até o tráfego voltar a crescer, e enfraquecido a proteção para o caso para o qual o limite existe.
Movemos as definições do limitador para uma pequena função e escrevemos testes contra ela. Um envia 20 pedidos com o token interno para um limitador configurado para permitir 5, e espera que todos os 20 tenham sucesso. Outro envia pedidos simples a partir de um endereço e espera que os primeiros cinco tenham sucesso e os seguintes sejam recusados. Um terceiro envia pedidos com um token forjado e espera que sejam recusados da mesma forma.
O que tirámos disto
- Os limites carregam pressupostos. "Um endereço, um chamador" está embutido num limite por endereço. Deixa de ser verdade no momento em que os teus próprios serviços estão atrás de endereços partilhados — e muitos estão: balanceadores de carga, redes de borda, contentores, redes de escritórios.
- Distingue o teu próprio tráfego pela identidade, não pelo endereço. Os endereços são a forma como o tráfego chega, não quem o enviou. Já tínhamos uma credencial que prova que uma chamada é nossa; o limitador simplesmente não estava a olhar para ela.
- Não resolvas aumentando o número. Um limite maior teria feito desaparecer os 429 durante algum tempo, protegeria menos e voltaria a falhar mais tarde.
- Olha para quem está a ser limitado. Um 429 que cai no teu próprio serviço é um relatório de bug sobre os teus limites, não um sinal de que o limitador está a funcionar.
O que significa se construíres no Mythex
Nada a mudar do teu lado. As apps publicadas em domínios personalizados, os turnos do agente e as pré-visualizações deixam de depender de quão ocupado está o resto do Mythex. O tráfego da tua app é assunto da tua app: o limite descrito aqui é na nossa API, e não nas apps que publicas.
Se tens um backend próprio, a mesma armadilha aplica-se a qualquer limite de taxa que acrescentes. Os nossos guias sobre o que é uma API e a lista de verificação de segurança para apps criadas com IA são um bom ponto de partida. E para outro caso de a nossa própria infraestrutura se atrapalhar, vê como chegámos a zero erros 502 nos deploys.