aws.crafter.run

Escala

Cold start

También llamado Cold start / function init latency

Entender qué tarda de verdad cuando Lambda arranca un entorno nuevo, cuánto de eso puedes acortar tú, y decidir con criterio si merece la pena pagar por evitarlo.

IntermedioVerificado el

El problema

Tu API responde en 80 ms. Casi siempre. Y de vez en cuando, sin patrón aparente, alguien espera dos segundos y medio.

No es la red, no es la base de datos, y no sale en los logs de tu función porque el tiempo se fue antes de que tu handler existiera. Lambda tuvo que construir un entorno de ejecución desde cero, y eso tiene un coste que se factura y que el cliente nota.

En fríoLo paga menos del 1 % de las invocacionescódigoentornotu código de inithandlerEn calienteEl entorno ya existe. Es el caso normal en producción.handlerSnapStartJava, Python y .NET. En Node.js no existe.restaurarhandlerAprovisionadaInicializada antes de que llegue la petición. Se paga esté ociosa o no.handlertiempo →
Solo uno de los cuatro tramos es tuyo. Descargar el código y levantar el entorno los hace AWS y no los controlas. El tramo naranja —tu código de init— es el único que puedes acortar escribiendo código, y suele ser el más largo.

Lo primero que hay que interiorizar, porque cambia todas las decisiones que vienen después, es cuánto de esa barra es tuyo.

La fase Init que ejecuta Lambda tiene tres tareas: arrancar las extensiones, arrancar el runtime y ejecutar tu código estático — todo lo que está fuera del handler. Las dos primeras las hace AWS y no las controlas. La tercera es tuya, y en la mayoría de las funciones lentas es, con diferencia, la más larga: importar medio SDK, levantar un framework, leer configuración, abrir conexiones.

Cuánto pasa de verdad

Aquí conviene un baño de realismo, porque el cold start es probablemente el tema sobre el que más se ha escrito y menos se ha medido. La documentación de AWS es directa:

Los arranques en frío ocurren típicamente en menos del 1 % de las invocaciones, y su duración va desde menos de 100 ms hasta más de un segundo.

Y añade un dato que cambia la conversación: son más frecuentes en funciones de desarrollo y de test que en producción, precisamente porque se invocan menos.

Eso explica por qué tanta gente lo percibe como un problema enorme: lo sufre a diario en su entorno de desarrollo, donde invoca la función una vez cada media hora. En producción, con tráfico sostenido, el mismo código casi nunca lo toca.

Mide antes de pagar. El campo Init Duration aparece en la línea REPORT de CloudWatch Logs. Si no sabes qué porcentaje de tus invocaciones son frías ni cuánto duran, no tienes un problema de cold start: tienes una intuición.

La solución

Tres palancas, en orden de lo que deberías intentar primero:

1. Adelgazar el init (gratis)

Es lo que más devuelve por unidad de esfuerzo y lo único que no cuesta dinero.

2. SnapStart (barato, pero no para todos)

Lambda inicializa la función al publicar la versión, hace un snapshot cifrado de la memoria y el disco, y al invocar restaura desde ahí en vez de arrancar de cero. AWS habla de bajar la latencia de varios segundos a menos de un segundo.

El detalle que decide si te sirve: solo funciona en Java 11+, Python 3.12+ y .NET 8+. Node.js y Ruby no están soportados, y los runtimes OS-only tampoco. Si tu backend es TypeScript, SnapStart no es una opción para ti.

Además solo se activa en versiones publicadas y alias, nunca en $LATEST, y es incompatible con concurrencia aprovisionada, EFS y almacenamiento efímero por encima de 512 MB.

3. Concurrencia aprovisionada (funciona siempre, y se paga siempre)

Lambda mantiene N entornos ya inicializados y esperando. Es la única opción que elimina el arranque en frío del todo y la única que funciona con cualquier runtime. También es la única que se factura por tenerla, haya tráfico o no: un coste fijo dentro de un servicio que compraste por ser variable.

Cuándo usarlo

Cuándo NO usarlo

Cómo implementarlo

  1. Mide. Filtra Init Duration en CloudWatch Logs Insights y saca dos números: qué porcentaje de invocaciones son frías y cuánto dura el init.
  2. Si el init es largo, adelgázalo antes de tocar nada más. Suele ser la diferencia entre 1,5 s y 300 ms.
  3. Si sigue doliendo y el runtime lo permite, activa SnapStart en la versión publicada y mide otra vez.
  4. Si el SLA es duro o el runtime no soporta SnapStart, pon concurrencia aprovisionada sobre un alias, dimensionada al percentil de concurrencia real —no al pico absoluto—, y deja que el resto desborde a bajo demanda.
  5. Vuelve a medir. Es el paso que casi nadie hace.

El código

// ── Fuera del handler: se ejecuta una vez por entorno ──────────────
// Importar el cliente concreto y no el SDK entero es la recomendacion
// explicita de AWS, y en runtimes interpretados se nota.
import { DynamoDBClient } from '@aws-sdk/client-dynamodb';
import { DynamoDBDocumentClient } from '@aws-sdk/lib-dynamodb';

const ddb = DynamoDBDocumentClient.from(new DynamoDBClient({}));

// Carga en diferido: la libreria pesada solo se paga en el camino que
// de verdad la usa, no en cada arranque en frio.
let pdf: typeof import('./pdf') | undefined;
const cargarPdf = async () => (pdf ??= await import('./pdf'));

export const handler = async (evento: Evento) => {
  const pedido = await ddb.send(leer(evento.id));

  if (evento.formato === 'pdf') {
    const { generar } = await cargarPdf();
    return generar(pedido);
  }

  return pedido;
};
-- CloudWatch Logs Insights: cuánto y cuántas veces --
filter @type = "REPORT"
| stats count(*) as invocaciones,
        count(@initDuration) as frias,
        count(@initDuration) * 100 / count(*) as pct_frias,
        avg(@initDuration) as init_medio,
        pct(@initDuration, 99) as init_p99

Te va a morder

Coste

Palanca Coste
Adelgazar el init gratis, y además baja la factura de duración
SnapStart en Java sin coste adicional
SnapStart en Python y .NET caché del snapshot (mínimo 3 horas) + cargo por restauración
Concurrencia aprovisionada por entorno y hora, haya tráfico o no

La fase de init se factura como duración, así que acortarla no solo mejora la latencia: baja la factura de todas las invocaciones frías. Es la única de las tres palancas que ahorra dinero en vez de gastarlo.

Detalle de SnapStart que sorprende: en los runtimes gestionados de Java no tiene coste adicional. En Python y .NET sí pagas por mantener el snapshot en caché —con un mínimo de 3 horas por versión publicada— y por cada restauración. Las versiones antiguas que nadie borra siguen facturando.

Fuentes

Fases Init, Invoke, Restore y Shutdown, el límite de 10 segundos del init y su excepción, los suppressed inits, la persistencia de /tmp, los procesos en segundo plano, la terminación periódica de entornos y las cifras de frecuencia y duración de los arranques en frío: Understanding the Lambda execution environment lifecycle. Runtimes soportados, incompatibilidades, problema de unicidad y precios: Improving startup performance with Lambda SnapStart. Cuotas de memoria, paquete de despliegue y concurrencia: Lambda quotas.

Patrones relacionados

Un enlace sin la relación nombrada es un "ver también". Aquí cada uno dice qué relación tiene y por qué.