Come abbiamo creato lo Scale to Zero di Laravel Cloud | Laravel - The clean stack for Artisans and agents
Di recente abbiamo annunciato che il tuo stack Laravel Cloud ora scala a zero e si riattiva 20 volte più velocemente. In questo post spieghiamo come lo abbiamo costruito.
L'implementazione originale dello scale to zero su Cloud aveva un tempo di riattivazione di 10 secondi, abbastanza lungo da farsi notare dagli utenti. Aggiungere anche l'avvio di database e cache avrebbe peggiorato la situazione, quindi la maggior parte delle app li manteneva attivi 24 ore su 24.
Il nuovo Flex compute con scale-to-zero utilizza checkpoint/restore. Così, invece di un avvio a freddo a ogni richiesta, il runtime salva l'intero stato in memoria su disco e lo ripristina istantaneamente. Il tempo di riattivazione scende sotto i 500 millisecondi. Ora l'intero stack, database e cache inclusi, può dormire e risvegliarsi come un'unica unità.
Per scoprire come ci siamo riusciti, continua a leggere, oppure consulta la documentazione di Laravel Cloud se preferisci iniziare subito.
Perché il vecchio scale to zero era così lento
Nella nostra architettura originale di scale-to-zero, dormire significava rimozione. Quando la tua app andava in idle, veniva completamente rimossa dal cluster di compute. La richiesta successiva in arrivo colpiva un proxy, che poi doveva pianificare un workload su un nodo di compute, scaricare l'immagine dell'app e avviare tutti i processi da zero.
Quel processo richiedeva circa 10 secondi, il che significava che qualsiasi app con traffico reale non poteva sfruttare appieno i vantaggi dello scale to zero. Il compute dormiva, ma tutto il resto continuava a essere fatturato.
Checkpoint/Restore: perché i tempi di riattivazione si sono ridotti di 20 volte
Per risolvere i lenti tempi di riattivazione, abbiamo progettato una nuova implementazione che mantiene l'immagine dell'app e lo stato in memoria sul disco di un nodo di compute. Quando una richiesta HTTP o l'esecuzione di un comando attiva un wake, il container runtime ripristina i processi dell'app da quello snapshot in memoria.
"Su richiesta, il container runtime ripristina i processi dell'app dallo stato in memoria ed è in grado di rispondere alla richiesta in arrivo entro centinaia di millisecondi", ha spiegato Cyrill Troxler, Senior Software Engineer of Infrastructure di Laravel.
La tecnologia è il container checkpoint/restore, un'evoluzione di CRIU (Checkpoint/Restore In Userspace). Quando la tua app dorme, il runtime scrive su disco, sul nodo di compute, uno snapshot completo dello stato dei suoi processi, incluse le pagine di memoria e i file descriptor aperti. Il ripristino da quello snapshot evita la pianificazione, il download dell'immagine e l'inizializzazione dei processi richiesti da un percorso di avvio a freddo.
Quando è in sleep, l'unica cosa in esecuzione è il runtime personalizzato in grado di ripristinare su richiesta l'intero container dell'app.
Il problema ingegneristico più difficile
Far funzionare checkpoint/restore su una singola app non è difficile. Farlo funzionare in modo affidabile su una vasta flotta di app con runtime, configurazioni e dipendenze diverse è un problema completamente diverso.
"Far funzionare checkpoint/restore in modo affidabile su una flotta enorme di app con vari runtime e configurazioni diverse [è stata la parte più difficile]. In più, il lavoro di integrazione che abbiamo dovuto fare a livello di OS con uno stack molto restrittivo", ha detto Cyrill.
L'infrastruttura gira su Bottlerocket, la distribuzione Linux di Amazon incentrata sui container, con SELinux che applica policy di sicurezza severe. Installare un nuovo container runtime su quello stack ha richiesto un lavoro di integrazione a livello di pacchetto che la build upstream di Bottlerocket non supporta out of the box.
"Inizialmente pensavamo di dover creare e mantenere una nostra variante di Bottlerocket per poter installare il nuovo runtime. Siamo riusciti a farla compilare ed eseguire, ma solo tenere il passo con le release e distribuire le immagini a livello globale sarebbe stato molto lavoro. Alla fine abbiamo trovato un modo per installarlo sulla versione upstream ufficiale, il che ci ha fatto risparmiare moltissimo tempo e fatica", ha detto Cyrill.
L'altro vincolo era lo storage. Le app in sleep scrivono il loro stato in memoria su disco sul nodo di compute. Quello storage deve essere abbastanza veloce da ripristinare in centinaia di millisecondi, ma abbastanza economico da essere sostenibile su una flotta globale. Trovare il giusto equilibrio tra operazioni di input/output al secondo e dimensione dello storage ha richiesto diverse iterazioni.
Come compute, database e cache si risvegliano come un'unica unità
I tre componenti del tuo stack Laravel Cloud non si risvegliano tramite un orchestratore centrale: si segnalano a vicenda.
Il compute si risveglia su una connessione HTTP in ingresso o sull'esecuzione di un comando. Una volta che il container dell'app è ripristinato e in esecuzione, apre connessioni a MySQL e Laravel Valkey usando i normali driver client. Sono quelle connessioni Transmission Control Protocol a risvegliare database e cache.
"L'app si risveglia tramite connessioni HTTP o esecuzione di comandi, mentre cache e database su connessione TCP (normale connessione client Valkey/MySQL)", ha spiegato Cyrill.
Questo design mantiene leggero il coordinamento del wake. La tua app non deve sapere che il database stava dormendo. Apre una connessione e il database si risveglia. Questo elimina uno strato di orchestrazione e rimuove un ulteriore punto di fallimento.
Per Valkey, i vantaggi vanno oltre. Poiché il nuovo runtime ripristina l'intero stato in memoria, la cache appare esattamente come prima dello sleep. Quando la tua app si risveglia e si connette, la cache è calda. L'unico overhead è il piccolo ritardo iniziale della connessione TCP.
Evitare un thundering herd e i task schedulati durante lo sleep
Quando arrivano più richieste mentre un'app dorme, la prima attiva un wake. Le altre vengono messe in coda e inoltrate contemporaneamente una volta che l'app è pronta, senza perdere nessuna richiesta.
Per i task schedulati, uno scheduler centrale in esecuzione al di fuori del workload del cliente gestisce il risveglio delle singole app e l'esecuzione di schedule:run. Quello scheduler è sempre attivo: la tua app non deve essere in esecuzione perché lo scheduler sappia che ha del lavoro da fare.
I queue worker usano lo stesso meccanismo, con l'utente che specifica la pianificazione del wake. Per le applicazioni che necessitano di elaborazione immediata delle code senza un intervallo pianificato, le managed queues sono la scelta giusta. Quei worker girano su un'infrastruttura che resta calda ed elaborano i job man mano che arrivano.
Modalità di errore
Se il wake con checkpoint/restore fallisce, il sistema ripiega su un avvio a freddo. L'app si avvia da zero, il che richiede più tempo, ma nessuna richiesta restituisce un errore.
"C'è un meccanismo di fallback quando un wake fallisce, che semplicemente avvia il container dell'app da zero. Questo comporta un leggero ritardo, ma garantisce comunque che non ci sia alcun errore di richiesta lato utente", ha detto Cyrill. "Monitoriamo questi fallimenti e miglioriamo continuamente il sistema per cercare di ridurli al minimo."
Monitorare un'app che dorme presenta una sfida ovvia: non c'è nulla in esecuzione da controllare. Il sistema monitora il runtime personalizzato stesso. Verifica continuamente se il runtime è raggiungibile. Se quel controllo non supera una soglia, il runtime si riavvia automaticamente.
Pubblica su Laravel Cloud oggi stesso
Questa architettura è attiva su ogni nuova applicazione Flex su Laravel Cloud. Le nuove app ottengono automaticamente il Flex compute con scale-to-zero.
Se sei già su Cloud e vuoi i tempi di riattivazione migliorati, seleziona una delle nuove dimensioni Flex compute (512 MB, 1 GB o 2 GB) e ridispiega. Se sei nuovo a Laravel Cloud, il primo mese del piano Starter è gratuito.
Altri articoli recenti
Laravel AI 1.1 e 1.2: Agent Skills, Cohere e structured output più solidi
Le release 1.1.0 e 1.2.0 di laravel/ai portano gli Agent Skills, l'approvazione obbligatoria per i tool built-in e nuovi provider come Cohere e Laya self-hosted. Sul fronte qualità arrivano i fix allo structured output per Bedrock e il supporto alle provider options. Aggiornati anche i modelli di default, con Claude 4.7+ che ignora i sampling params.
Laravel 13.35.0: scheduler più controllabile, code più flessibili e response Markdown
Laravel 13.35.0 porta Schedule::alwaysOnOneServer(), il supporto a schedule:interrupt per i comandi di lunga durata, --memory in percentuale per queue:work e il nuovo metodo markdown() sulla response factory. Tante piccole migliorie anche a test, view compilate in parallelo e dischi local.
BashBox: un interprete Bash in sandbox per agenti AI in PHP
BashBox è un interprete bash scritto in puro PHP che permette di eseguire gli script generati dagli agenti AI senza mai ricorrere a proc_open, exec o shell_exec. Ogni comando è una classe PHP che lavora su un filesystem virtuale, con limiti di esecuzione, quote disco e accesso di rete configurabili. Ideale per chi sviluppa agenti con il Laravel AI SDK o altre librerie simili.