Capítulo 13 — Autoscaling e Mitigação de Cold Start
Décimo terceiro post do passeio capítulo a capítulo pelo LLM Primer VI: Escalando Sistemas de IA. O capítulo que explica por que o autoscaler padrão do Kubernetes provoca quedas sob tráfego de LLM, e como KEDA, Knative e CRIU se combinam para resolver o problema.
Por que este capítulo existe
Um assistente de chat oscila 30× do pico ao vale ao longo do dia. Uma ferramenta de desenvolvedor vai a zero nos fins de semana. Um produto de consumo cavalga uma onda que atravessa o Pacífico e chega à Europa. Provisionar para o pico desperdiça dinheiro no vale; provisionar para o vale derruba requisições no pico. O autoscaling mantém o deployment em passo com o tráfego; a mitigação de cold start torna o autoscaling — e em particular o scale-to-zero — rápido o suficiente para que o usuário não perceba. O Capítulo 13 explica por que o HPA padrão do Kubernetes é o scaler errado para LLMs, quais sinais o KEDA usa como alternativa, como o Knative expressa scale-to-zero, e o que é preciso para comprimir uma partida a frio de 60 a 180 segundos em poucos segundos de um dígito.
13.1 O HPA falha com tráfego de LLM de quatro formas específicas
O HPA padrão escala por utilização de CPU ou GPU. Ele falha com LLMs de quatro maneiras. Primeiro, a utilização da GPU é o sinal errado — nvidia-smi reporta a fração de tempo em que algum kernel está rodando, não se o batch está bem empacotado ou se as requisições estão progredindo. Um servidor a 95 por cento de utilização com oito prefills longos enfileirados atrás de um decode está sobrecarregado; um servidor a 60 por cento com um continuous batching saudável está bem. Segundo, a duração de uma requisição de LLM (segundos a dezenas de segundos) é longa comparada ao loop de controle do HPA (15 segundos), então o scaling atrasa em relação à carga por um ciclo completo de requisição. Terceiro, a unidade de capacidade não é um pod; um deployment desagregado escala em cliques, e o HPA não entende cliques. Quarto, o cold start: um novo pod fica pronto 60 a 180 segundos depois, muito tempo depois do pico que o disparou — que a essa altura já sobrecarregou a frota ou se dissipou em timeouts. O modo de falha típico é uma queda de dois minutos durante uma duplicação de tráfego, seguida de um scale-down que deixa o deployment subprovisionado para o próximo pico.
13.2 O KEDA escala por profundidade de fila, TTFT e ocupação de KV
O KEDA estende o HPA com um CRD ScaledObject que liga uma workload-alvo a um ou mais scalers, cada um convertendo uma métrica externa em um número desejado de réplicas. Três sinais importam para servir LLMs. A profundidade de fila é o mais direto: a contagem de requisições em espera do engine é o excedente de trabalho chegando sobre a capacidade de servir; a vLLM exporta esse número como vllm:num_requests_waiting. O time-to-first-token — especificamente o p95 ou p99 sobre uma janela deslizante — captura a degradação visível ao usuário e pega sobrecargas assimétricas que a profundidade de fila não pega (prefill saturado com decode saudável, ou o inverso). A ocupação do cache KV é preditiva; quando cruza 80 por cento, novas réplicas devem subir antes que as existentes comecem a preemptar ou rejeitar. Um ScaledObject de produção normalmente compõe os três, e o mais agressivo dentre eles vence. O Knative Serving se sobrepõe para prover scale-to-zero: abaixo de um pequeno limiar de ativação, todos os pods são removidos; requisições que chegam são seguradas por um activator que sobe um pod sob demanda — o que só é economicamente sustentável se o cold start for rápido.
13.3 O CRIU comprime uma partida a frio de 90 segundos em 3 a 6 segundos
Um cold start de 70B decompõe em: pull de imagem (10 a 60 s), init do Python (2 a 5 s), carga dos pesos (60 a 120 s), init do contexto CUDA (5 a 15 s), captura de CUDA graphs (10 a 30 s), warmup do KV (2 a 10 s) — total de 90 a 250 s. O CRIU (Checkpoint/Restore In Userspace) tira um snapshot de um processo totalmente aquecido — pesos carregados, contexto CUDA de pé, grafos capturados, pool de KV alocado, health check passado — e o restaura depois a partir do disco em poucos segundos. O utilitário cuda-checkpoint da NVIDIA (2024) estende o CRIU para lidar com estado de GPU: pools de memória de dispositivo, contexto CUDA, PTX em cache, grafos capturados. Um snapshot aquecido do vLLM restaura em 3 a 6 segundos a partir de NVMe local. Um DaemonSet pré-posiciona o checkpoint no NVMe de cada nó para que o Knative restaure a partir de arquivo local em vez de buscar na rede. Combinado com image streaming (começar a puxar antes de o pull terminar) e carregamento lazy dos pesos, cold starts abaixo de 5 segundos são alcançáveis em produção — que é o número abaixo do qual scale-to-zero passa a ser economicamente defensável para aplicações voltadas ao usuário.
O que o Capítulo 13 prepara
Os Capítulos 1 a 13 percorreram a pilha física do serving de LLMs — hardware, engines, plataformas, desagregação, escala. O restante do livro vira para o dinheiro. O Capítulo 14 explica por que o token é a unidade de cobrança, por que o output é precificado de duas a cinco vezes acima do input, e como tokens invisíveis de reasoning acabam na fatura. O Capítulo 15 percorre a matemática do ponto de equilíbrio entre self-hosting e provedores de API, mais o item de engenharia de plataforma que a maioria dos times subestima. O Capítulo 16 é o catálogo dos movimentos de corte de custo que se compõem.
Próximo — Capítulo 14: Economia de Tokens e Precificação de APIs. Por que a fatura tem a cara que tem, e como o medidor roda quando ninguém está olhando.