Capítulo 13 — Autoscaling y mitigación de cold start
Decimotercera entrega del recorrido capítulo por capítulo de LLM Primer VI: Scaling AI Systems. El capítulo que explica por qué el autoscaler estándar de Kubernetes produce outages bajo tráfico LLM, y cómo KEDA, Knative y CRIU componen la solución.
Por qué existe este capítulo
Un asistente de chat oscila 30× de pico a valle en un día. Una herramienta de desarrollador va a cero los fines de semana. Un producto de consumo cabalga una ola de Pacífico a Europa. Provisionar para el pico desperdicia dinero en el valle; provisionar para el valle tira peticiones en el pico. El autoscaling mantiene el despliegue en paso con el tráfico; la mitigación del cold start hace que el autoscaling — y en particular la escala-a-cero — sea lo bastante rápido para que los usuarios no lo noten. El Capítulo 13 explica por qué el HPA estándar de Kubernetes es el scaler equivocado para LLMs, qué señales KEDA escala en su lugar, cómo Knative expresa la escala-a-cero, y qué hace falta para comprimir un cold start de 60–180 segundos hasta segundos de un solo dígito.
13.1 HPA falla al tráfico LLM de cuatro maneras específicas
El HPA por defecto escala sobre utilización de CPU o de GPU. Falla con LLMs de cuatro maneras. Primero, la utilización de GPU es la señal equivocada — nvidia-smi reporta la fracción de tiempo durante la cual algún kernel está corriendo, no si el batch está bien empaquetado o si las peticiones están progresando. Un servidor al 95 por ciento de utilización con ocho prefills largos encolados detrás de un decode está sobrecargado; uno al 60 por ciento con un batch continuo sano está bien. Segundo, la duración de las peticiones LLM (segundos a decenas de segundos) es larga comparada con el bucle de control del HPA (15 segundos), así que el escalado va con retraso de una vida completa de petición respecto a la carga. Tercero, la unidad de capacidad no es un pod; un despliegue desagregado escala en cliques y el HPA no entiende cliques. Cuarto, cold start: un pod nuevo entra online 60–180 segundos después, mucho después de que el pico que lo disparó haya sobrecargado la flota o se haya desprendido como timeouts. El modo de fallo típico es un outage de dos minutos durante una duplicación de tráfico, seguido de un escalado a la baja que deja el despliegue infra-provisionado para el siguiente pico.
13.2 KEDA escala sobre profundidad de cola, TTFT y ocupación de KV
KEDA extiende el HPA con un CRD ScaledObject que ata una carga objetivo a uno o más scalers que convierten una métrica externa en el conteo de réplicas deseado. Tres señales importan para el serving de LLMs. La profundidad de cola es la más directa: el conteo de peticiones en espera del motor es el excedente del trabajo que llega sobre la capacidad de servir; vLLM lo exporta como vllm:num_requests_waiting. El time-to-first-token — específicamente el p95 o p99 sobre una ventana deslizante — captura la degradación visible por el usuario y atrapa la sobrecarga asimétrica que la profundidad de cola no ve (prefill saturado pero decode bien, o viceversa). La ocupación de la caché KV mira hacia adelante; cuando la ocupación cruza el 80 por ciento, deberían entrar réplicas nuevas antes de que las existentes empiecen a preemptar o rechazar peticiones. Un ScaledObject de producción compone típicamente las tres, ganando la más agresiva de ellas. Knative Serving se apila encima para escala-a-cero: por debajo de un pequeño umbral de activación se eliminan todos los pods; las peticiones entrantes las retiene un activator que arranca un pod bajo demanda, lo cual solo es económico si el cold start es rápido.
13.3 CRIU comprime un cold start de 90 segundos hasta 3–6 segundos
Un cold start de 70B se descompone en pull de imagen (10–60 s), init de Python (2–5 s), carga de pesos (60–120 s), init de contexto CUDA (5–15 s), captura de CUDA graphs (10–30 s), warmup de KV (2–10 s) — total 90–250 s. CRIU (Checkpoint/Restore In Userspace) hace snapshot de un proceso completamente caliente — pesos cargados, contexto CUDA arriba, graphs capturados, pool de KV asignado, health check pasado — y lo restaura después desde disco en segundos. La utilidad cuda-checkpoint de NVIDIA (2024) extiende CRIU para manejar el estado GPU: pools de memoria de dispositivo, contexto CUDA, PTX cacheado, graphs capturados. Un snapshot caliente de vLLM se restaura en 3–6 segundos desde NVMe local. Un DaemonSet pre-etapa el checkpoint sobre el NVMe de cada nodo para que Knative pueda restaurar desde archivo local en vez de traerlo por la red. Combinado con image streaming (empieza a hacer pull antes de que el pull termine) y carga perezosa de pesos, cold starts de menos de 5 segundos son alcanzables en producción — que es el número por debajo del cual la escala-a-cero se vuelve económicamente defendible para aplicaciones de cara al usuario.
Lo que prepara el Capítulo 13
Los Capítulos 1 al 13 han recorrido el stack físico del serving de LLMs — hardware, motores, plataformas, desagregación, escalado. El resto del libro pasa al dinero. El Capítulo 14 explica por qué el token es la unidad de facturación, por qué la salida se cobra dos a cinco veces por encima de la entrada, y cómo los tokens invisibles de razonamiento acaban en la factura. El Capítulo 15 recorre la aritmética del punto de equilibrio entre autohost y proveedores de API, más el renglón de ingeniería de plataforma que la mayoría de los equipos subestima. El Capítulo 16 es el catálogo de jugadas de reducción de coste que se acumulan.
Próximamente — Capítulo 14: Economía del token y precios de API. Por qué la factura tiene la forma que tiene, y cómo corre el contador cuando nadie está mirando.