Un cold start è un costo di latenza che si paga quando una piattaforma serverless deve creare e inizializzare un nuovo ambiente prima di eseguire il codice. Non è un bug, è una fattura: lo scale-to-zero fa sì che gli ambienti inattivi vengano recuperati perché l’inattività non costi nulla – e la prima richiesta dopo il recupero paga il setup. Capire le fasi, i numeri reali e la scala di mitigazione trasforma i cold start da paura vaga in una decisione di ingegneria con un prezzo.
Punti chiave
| Domanda | Risposta |
|---|---|
| La causa | Scale-to-zero: nessun costo a riposo ⇒ qualcuno inizializza su richiesta |
| Le fasi | Allocare → scaricare il codice → avviare il runtime → eseguire l’init → rispondere |
| I numeri | ~100 ms–1 s+ tipico; meno dell’1 % del traffico regolare, quasi tutto quello sporadico |
| L’innesco dimenticato | Lo scale-out della concorrenza – i warmer non ci possono nulla |
| La scala | Prima i rimedi gratuiti nel codice; per ultima la capacità sempre calda a pagamento |
Le cinque fasi, con il cronometro in mano
COLD START costo tipico
1 Allocare una sandbox (micro-VM / container) ~50–100 ms
2 Scaricare il pacchetto di deployment 50–500 ms ← dipende dal bundle
3 Avviare il runtime del linguaggio 50–1.000 ms ← interprete veloce, VM lenta
4 Eseguire il PROPRIO init (import, SDK, conn. DB) 0 ms–secondi ← la leva più grande in mano
5 Invocare l'handler il lavoro vero
WARM START = solo il passaggio 5 (+ ~1–10 ms di scongelamento). L'ambiente è
stato congelato, non distrutto – connessioni e cache fuori dall'handler
sopravvivono, ed è per questo che la disciplina sull'init rende a ogni richiesta.
Il confronto che vale la pena misurare in proprio – una funzione su un backend sempre in esecuzione, dove la corsa non parte mai:
// JavaScript / Node.js — Back4app JS SDK
// Cloud Code runs on an always-on backend — no scale-from-zero cold start
const t0 = Date.now();
const avg = await Parse.Cloud.run('averageStars', { movie: 'Arrival' });
console.log(`Round trip: ${Date.now() - t0} ms`); // consistent p50 ≈ p99
// The FaaS mitigations (warmers, provisioned capacity, bundle diets)
// don't apply here: the process serving this call was already running. // Flutter / Dart — Back4app Flutter SDK
// Cloud Code runs on an always-on backend — no scale-from-zero cold start
final t0 = DateTime.now();
final response = await ParseCloudFunction('averageStars')
.execute(parameters: {'movie': 'Arrival'});
print('Round trip: ${DateTime.now().difference(t0).inMilliseconds} ms');
// Consistent p50 ≈ p99: the process serving this call was already running. // iOS / Swift — Back4app Swift SDK
// Cloud Code runs on an always-on backend — no scale-from-zero cold start
let t0 = Date()
let avg: Double = try await Cloud.run(name: "averageStars",
parameters: ["movie": "Arrival"])
print("Round trip: \(Int(Date().timeIntervalSince(t0) * 1000)) ms")
// Consistent p50 ≈ p99: the process serving this call was already running. // Android / Kotlin — Back4app Android SDK
// Cloud Code runs on an always-on backend — no scale-from-zero cold start
val t0 = System.currentTimeMillis()
val avg = ParseCloud.callFunction<Double>(
"averageStars", mapOf("movie" to "Arrival"))
println("Round trip: ${System.currentTimeMillis() - t0} ms")
// Consistent p50 ≈ p99: the process serving this call was already running. Cold start vs. warm start
| Cold start | Warm start | |
|---|---|---|
| Ambiente | Creato e inizializzato ora | Riusato, scongelato |
| Latenza aggiunta | Da ~100 ms a secondi | Meno di 10 ms |
| Quando | Prima chiamata, post-deployment, post-inattività, scale-out | Traffico regolare entro il pool caldo |
| Codice di init | Viene eseguito | Saltato – i suoi risultati persistono |
| Nota di fatturazione | Sulle grandi piattaforme la fase di init è ormai fatturata come l’esecuzione | Solo il tempo dell’handler |
Quanto dura, e quanto spesso – onestamente
La durata dipende soprattutto da runtime e bundle: i runtime interpretati (JavaScript, Python) tipicamente 200–400 ms; i compilati (Go, Rust) sotto i ~100–300 ms; quelli basati su VM (JVM, .NET) da 500 ms a diversi secondi, con lo snapshot-restore che abbatte in modo netto il numero della JVM; i p99 valgono 2–3× la mediana, e alberi di dipendenze obesi moltiplicano il tempo di inizializzazione più volte, qualunque sia il linguaggio, mentre i benchmark hello world mostrano la linea di base di ogni runtime. La frequenza è il punto dove la maggior parte delle spiegazioni racconta solo metà della storia. Il traffico di produzione regolare vede cold start su meno dell’uno per cento delle invocazioni – rassicurante, e vero. Ma il conto si ribalta con il traffico sporadico: l’aritmetica di Mike Roberts – una funzione invocata una volta all’ora fa un cold start praticamente ogni volta, e gli ambienti di sviluppo registrano tassi di freddo del 30–90 %. E l’innesco che tutti dimenticano: lo scale-out della concorrenza – quando arrivano dieci richieste e tre ambienti sono caldi, sette fanno un cold start simultaneo, in pieno picco di traffico, cioè esattamente quando fa male.
La scala di mitigazione, con i prezzi
In ordine di costo, dal più economico. Gratis, nel codice: ridurre il bundle di deployment e potare le dipendenze – la leva più grande che la maggior parte dei team non ha ancora tirato; importare solo i sottomoduli dell’SDK effettivamente usati; caricare in modo lazy i moduli pesanti dei percorsi rari; aprire le connessioni al database nello scope di init, così i warm start le riusano. Economico, nella configurazione: alzare la memoria (la CPU sale con essa, in modo sensibile sui runtime a VM); attivare lo snapshot-restore dove la piattaforma lo offre. Fragile, rimedio della nonna: i ping di keep-warm – una richiesta pianificata ogni pochi minuti tiene caldo un solo ambiente e non fa nulla per lo scale-out; stato onesto: espediente storico. A pagamento, definitivo: la capacità pre-allocata (“provisioned concurrency”, “istanze minime”) – N ambienti sempre inizializzati, cold start eliminati fino a N, a un prezzo sempre attivo che annulla in parte il pagamento a consumo. L’ironia merita la sua frase: il rimedio al problema simbolo del serverless consiste nel ricomprare il server che era stato promesso come assente.
Gli isolate: come i runtime edge aggirano il problema
Le piattaforme edge dichiarano cold start quasi nulli cambiando l’architettura invece di scaldarla: anziché avviare un container o una micro-VM per tenant, eseguono migliaia di isolate V8 – sandbox in stile scheda del browser – dentro un unico processo di lunga durata. Creare un contesto di isolate costa pochi millisecondi e pochi megabyte, non centinaia di millisecondi più l’avvio di un runtime. Il trade-off è l’ambiente: un sottoinsieme delle API standard del web, tetti stretti sulla CPU, nessun filesystem – uno strumento diverso, non un upgrade gratuito, trattato onestamente nella voce sull’edge.
Casi d’uso tipici in cui i cold start contano
- API interattive – un essere umano guarda lo spinner; il p99 include la coda fredda.
- Pagamenti e checkout – sensibili alla latenza e pagati in conversioni.
- Accesso ed emissione di sessione – il percorso della prima impressione, spesso dopo periodi di inattività.
- Endpoint a traffico sporadico – strumenti di amministrazione e API interne dove quasi ogni chiamata è fredda.
- Dove invece non contano: job in coda, webhook, lavoro pianificato – l’asincrono assorbe la coda in modo invisibile.
Conviene ottimizzare i cold start? Matrice decisionale
| Situazione | Che fare |
|---|---|
| Carichi asincroni, in coda o pianificati | Niente – qui i cold start sono invisibili |
| Traffico alto e regolare, interattivo | Rimedi nel codice; misurare prima di pagare |
| Traffico sporadico, rivolto all’utente | Istanze minime su quel percorso – o un backend sempre attivo |
| Runtime a VM (JVM/.NET), sensibile alla latenza | Prima snapshot-restore e memoria |
| Traffico a picchi con p99 stretto | Capacità pre-allocata dimensionata sul picco |
| Logica in stile gateway, utenti globali | Runtime edge basati su isolate |
| Gran parte dei backend applicativi su un BaaS | Già risolto – nessuno scale-from-zero esiste |
Limiti e trade-off
- Le mitigazioni scambiano denaro per latenza. La capacità pre-riscaldata è una fattura permanente; la decisione si prende per endpoint, non per tutta la piattaforma.
- I warmer mentono alle dashboard. Una funzione pingata sembra sana mentre ogni vero picco di traffico continua a fare cold start nello scale-out.
- L’austerità sull’init ha un limite. Un lazy-loading aggressivo sposta la latenza dai cold start ai percorsi di primo uso – va misurato dove è stata spostata.
- I benchmark invecchiano in fretta. Le classifiche dei runtime e i numeri delle piattaforme cambiano ogni anno; cifre scadute (e penalità di rete corrette da tempo) circolano ancora – conviene datare i dati.
- La metrica che conta è la propria. Le statistiche sulla percentuale di freddo descrivono il traffico di qualcun altro; solo il p99 misurato sotto un carico simile alla produzione giustifica una spesa.
I cold start su Back4app
Back4app è una piattaforma open-source di Backend as a Service (BaaS) che combina database gestito, API REST e GraphQL generate automaticamente, autenticazione, archiviazione di file e funzioni serverless con Cloud Code. Qui la storia dei cold start è un’assenza architetturale: Cloud Code gira dentro un backend sempre in esecuzione, quindi non esiste il momento dello scale-from-zero – nessuna corsa contro l’init, nessun pool caldo da gestire, nessuna voce di capacità pre-allocata in fattura – e la misura nelle schede di codice mostra che cosa si compra: p50 e p99 a portata di voce l’uno dall’altro, alla prima richiesta della giornata come alla milionesima. Il trade-off è quello indicato in BaaS vs. serverless: si rinuncia alla granularità della fatturazione per invocazione in cambio di una latenza costante e di un database già attaccato – che, per i backend applicativi rivolti all’utente, è di solito il versante del compromesso che gli utenti percepiscono.
Domande frequenti
Che cos'è un cold start?
La latenza aggiuntiva che compare quando una piattaforma serverless deve costruire un ambiente di esecuzione nuovo prima di lanciare la funzione: allocare un'istanza, scaricare il codice, avviare il runtime, eseguire il codice di inizializzazione – e solo allora gestire la richiesta. Un warm start salta direttamente all'ultimo passaggio.
Quanto dura un cold start?
Di solito da un centinaio di millisecondi a oltre un secondo. I runtime interpretati (JavaScript, Python) si aggirano sui 200–400 ms; quelli compilati (Go, Rust) possono scendere sotto i 100 ms; i runtime basati su VM (JVM, .NET) vanno da 500 ms a diversi secondi, e le configurazioni cariche di framework sono le peggiori. Le latenze di coda valgono due o tre volte la mediana.
Qual è la differenza tra un cold start e un warm start?
Un warm start riusa un ambiente congelato ma già inizializzato: la piattaforma lo scongela e chiama l'handler, aggiungendo meno di 10 ms. Tutto ciò che vive fuori dall'handler – connessioni, cache, moduli caricati – sopravvive, ed è per questo che la disciplina sull'inizializzazione rende a ogni invocazione calda successiva.
Con quale frequenza si verificano i cold start?
Entrambe le risposte sono vere: meno dell'uno per cento delle invocazioni con traffico di produzione regolare – e la larghissima maggioranza con traffico sporadico, perché una funzione chiamata una volta all'ora fa un cold start quasi ogni volta. Le raffiche ne aggiungono altri: ogni richiesta concorrente oltre il pool caldo innesca il proprio cold start.
Come si riducono i cold start?
Conviene salire la scala dal gratuito al pagato: ridurre il bundle di deployment e potare le dipendenze (il guadagno gratuito più grande), caricare in modo lazy gli import usati raramente, scegliere un runtime più veloce, alzare la memoria (la CPU scala con essa), usare lo snapshot-restore dove la piattaforma lo offre – e solo allora pagare per capacità pre-riscaldata.
Che cos'è la provisioned concurrency?
È la soluzione a pagamento, venduta anche come istanze minime: la piattaforma tiene N ambienti inizializzati in anticipo sulla domanda, eliminando i cold start per il traffico fino a N. L'ironia è compresa nel prezzo – si reintroduce un costo sempre attivo in un modello a consumo – e per questo ha senso solo sui percorsi critici per la latenza.
I ping di keep-warm funzionano?
In parte, e in modo fragile: un ping pianificato tiene caldo un solo ambiente, ma non fa nulla quando la concorrenza scala in orizzontale – la decima richiesta simultanea fa un cold start, per quanto caldo sia il primo ambiente. I warmer sono l'espediente storico; le istanze minime sono la risposta supportata.
I cold start contano davvero in ogni app?
Solo dove un essere umano sta aspettando: i percorsi sincroni rivolti all'utente, come le API interattive e i pagamenti. Code, webhook, job pianificati e il resto del lavoro asincrono assorbono i cold start in modo invisibile. Prima di spendere soldi sul problema va misurata la latenza di coda sotto un traffico simile a quello di produzione.