← All posts

O scale-to-zero não sabe contar até um

Authagonal·July 6, 2026
authinfrastructurekubernetesaksserverlessazurearchitecture

O conselho era sempre o mesmo. Seu tráfego de autenticação vem em picos. Seu cluster Kubernetes fica em grande parte silencioso. Azure Container Apps dimensiona para zero e cobra apenas pelo que você usa. Você está pagando continuamente por um cluster que passa a maior parte do tempo esperando.

Levamos isso a sério o suficiente para calcular corretamente o custo da migração. Então, abandonamos a ideia. Não por causa do preço da mudança, nem por causa dos cold starts, embora os cold starts sozinhos já devessem ter sido suficientes. Abandonamos a ideia porque falta um número ao vocabulário da plataforma, e é o único número com que o nosso núcleo de autenticação realmente se importa.

Serverless conta até zero e até N

Runtimes de scale-to-zero conhecem dois números. Zero, quando ninguém está chamando. N, quando estão, com N flutuando sob demanda. Para tratamento de solicitações sem estado, esse vocabulário é perfeito, por isso o conselho parece tão correto. A maioria dos backends web realmente tem essa forma: cada solicitação independente, cada instância descartável, tráfego zero merecendo uma conta zero.

A face pública de um sistema de autenticação também se parece com isso. Endpoints de token, páginas de login, JWKS. Sem estado, com picos, amigável ao cache.

Por baixo disso, há uma camada que não é nada disso.

O número é um

Abaixo dos endpoints, nosso backplane executa uma camada de coordenação. A qualquer momento, exatamente uma réplica detém o arrendamento de liderança do cluster (um arrendamento de blob hoje em dia, não mais gossip, que é uma história para outro post) e executa os trabalhos singleton: a varredura de retenção, a passagem de entrega de webhooks, o trabalho onde dois executores simultâneos significam efeitos colaterais disparados em dobro e zero executores significa que as coisas, silenciosamente, nunca acontecem.

O número de que essa camada precisa é um. Não zero quando está tudo quieto. Não N sob carga. Um, mantido continuamente, com uma transferência verificável quando o detentor morrer. O scale-to-zero não tem como dizer "um, sempre". Ele pode dizer "pelo menos um enquanto houver tráfego", que é uma promessa diferente, e a diferença entre essas duas promessas é exatamente o modo de falha que a eleição de líder existe justamente para prevenir.

É por isso que o gráfico de utilização estava mentindo para nós. Um cluster de autenticação silencioso não está sem fazer nada. Ele está mantendo um arrendamento, mantendo as chaves de assinatura aquecidas e pronto para responder à próxima validação de token em milissegundos de um dígito. Silencioso e ocioso são estados diferentes, e os painéis de cobrança mostram apenas um deles.

Você pode fingir, e isso é pior

Você pode forçar "exatamente um" em um runtime serverless. Fixe o número mínimo de réplicas em um e você comprou um servidor sempre ativo em uma plataforma cujo instinto inteiro é tirar de você as instâncias silenciosas. Cada evento de escala, cada reinicialização iniciada pela plataforma, cada troca de revisão se torna uma questão de liderança cujo momento você não controla. Estaríamos lutando contra o comportamento central do runtime para preservar o nosso, para sempre, e pagando pelo privilégio.

E a falha recai sobre a pior pessoa possível. A solicitação que paga um cold start é um humano tentando fazer login. "Seu login foi lento porque nosso serviço de autenticação estava dormindo" não é uma frase que ninguém deveria colocar em produção.

A conta teve uma correção chata

E o dinheiro que começou tudo isso? Bastaram um agendador e uma SKU. O cluster de desenvolvimento agora é desalocado quando ninguém está usando, e o pool de nós mudou para uma SKU mais barata. Um parágrafo é tudo o que isso merece, e esse é o ponto: "parar de pagar por ociosidade" é um objetivo, não uma arquitetura, e a maior parte do objetivo podia ser alcançada com uma mudança de configuração em vez de uma troca de plataforma.

O teste de forma

A regra que mantivemos: combine o runtime com a forma real da carga de trabalho, não com o seu gráfico de tráfego. Serverless recompensa o que é sem estado e em rajadas. Ele pune qualquer coisa que precise manter um papel contínuo e exclusivo, e um núcleo de autenticação que protege chaves de assinatura e elege quem executa os trabalhos destrutivos é o exemplo mais puro desse segundo tipo que conhecemos.

Não somos contra serverless. Grande parte da nossa superfície sem estado viveria feliz nele. Mas a camada que tem que contar até exatamente um vai continuar em uma infraestrutura chata, sempre ativa e inspecionável.

Essa camada também é precisamente o que você deixa de operar quando executa autenticação no Authagonal em vez de executar a backplane você mesmo.