Scalare a 1 milione di sandbox simultanee in pochi secondi

@modal
INGLESE1 giorno fa · 16 lug 2026
128K
415
41
14
515

TL;DR

Modal spiega la transizione da un'architettura centralizzata a un modello decentralizzato incentrato sui worker, che consente di avviare 1 milione di sandbox in pochi secondi.

Questo articolo è stato scritto da Colin Weld e Connor Adams. Leggetelo qui o sul nostro blog.

In Modal, costruiamo sandbox, tra le altre cose. Gli agenti vengono eseguiti in sandbox e gli agenti stanno mangiando il software. Oggi Modal esegue milioni di sandbox al giorno, supporta fino a cinquantamila sandbox concorrenti per cliente e supporta una varietà di casi d'uso su larga scala, dal reinforcement learning agli agenti in background.

Sempre più spesso, i nostri utenti richiedono un numero sempre maggiore di sandbox, create a tassi sempre più elevati. Il reinforcement learning può richiedere l'esecuzione di milioni di sandbox in contemporanea e la creazione di picchi di centinaia di migliaia di sandbox all'inizio dei rollout. Allo stesso modo, gli agenti richiedono sempre più una scala massiccia e tassi di creazione concorrenti elevati per gestire i picchi di traffico.

La nostra attuale piattaforma sandbox è molto buona, ma non è stata progettata per queste scale; né lo è nessun'altra soluzione esistente. Siamo ossessionati dalla scala e dalle prestazioni, e vogliamo che la nostra infrastruttura acceleri la crescita degli agenti, non aggiunga attriti. Quindi siamo tornati al tavolo da disegno.

Negli ultimi mesi, abbiamo ricostruito da zero la nostra piattaforma sandbox core per scala e affidabilità. Sul nostro nuovo sistema, gli utenti possono eseguire milioni di sandbox in contemporanea e creare decine di migliaia di sandbox al secondo. Abbiamo rimosso tutti i colli di bottiglia centrali dal nostro control plane, così non ci sono limiti pratici di scalabilità, e abbiamo ottimizzato ogni parte della programmazione e dell'avvio dei container, semplificando il percorso di scheduling a un layer di load balancer che creano i container direttamente sul nostro fleet di worker.

Come dimostrazione di ciò di cui la nostra piattaforma è capace, abbiamo eseguito un milione di sandbox in contemporanea, creando tutto il milione in meno di un minuto.

Modal - inline image

Prova che possiamo eseguire molte sandbox.

Perché la maggior parte delle soluzioni non scala

Eseguire 1 milione di sandbox spinge al limite qualsiasi piattaforma di container, sia per il numero puro di container, ma anche perché eseguire così tante sandbox richiede molte decine di migliaia di nodi di calcolo. Ci saranno molte operazioni che sono O(container), O(nodi) o entrambe, il che farà sì che le piattaforme container tradizionali raggiungano i limiti di scalabilità.

Per Kubernetes, ad esempio:

  • l'algoritmo di scheduling è O(n x p) per n nodi e p pod nel caso peggiore, e lo scheduling è serializzato per impostazione predefinita.
  • ogni pod causa più scritture su etcd (il datastore durevole centrale di Kubernetes) durante la sua vita, il che può creare seri problemi con tassi elevati di creazione di pod o alto churn di pod, e etcd non è nativamente shardabile all'interno di un keyspace
  • ogni nodo deve scrivere su etcd almeno una volta per intervallo di heartbeat per segnalare liveness, quindi il carico di scrittura di base di etcd è O(nodi) completamente indipendente dalla creazione di pod
Modal - inline image

Approssimazione del flusso di scheduling di Kubernetes. I nuovi pod vengono scritti su etcd (un datastore durevole fortemente consistente) dal server API. Lo scheduler di Kubernetes cerca nuovi pod non assegnati e li assegna ai nodi tramite una chiamata al server API, che scrive di nuovo su etcd; dopo che questa scrittura viene completata, un nodo può avviare il pod.

Kubernetes può essere scalato, ma richiede un lavoro serio. Per eseguire un gran numero di nodi, etcd generalmente deve essere riscritto o sostituito. Supportare un throughput elevato di scheduling richiede la costruzione di un complesso sistema scatter-gather per parallelizzare l'algoritmo di scheduling mantenendo comunque un'unica fonte di verità per lo stato dei pod. Sharding e parallelizzazione non sono facili per impostazione predefinita, perché Kubernetes si basa sulla forte consistenza come spina dorsale del suo design.

L'architettura sandbox originale di Modal ha problemi simili. Come Kubernetes, ci affidiamo alla forte consistenza in tutto il nostro backend, quindi creare e schedulare sandbox richiede coordinamento globale e scritture O(sandbox) su Postgres, che non possiamo shardare banalmente.

Modal - inline image

Architettura del control plane sandbox originale di Modal. Quando vengono create le sandbox, vengono inserite in una coda e scritte su Postgres. Lo scheduling è ottimistico e viene eseguito in parallelo, con coordinamento centrale necessario per evitare conflitti. Assegnare una sandbox a un worker (nodo di calcolo) richiede una scrittura aggiuntiva su Postgres.

Poiché non ci basiamo su Kubernetes, siamo stati in grado di scalare orizzontalmente molte parti di questo sistema. Ad esempio, lo scheduling è parallelizzato per impostazione predefinita, il che ci consente di raggiungere tassi di creazione di sandbox a burst molto elevati. Ma man mano che scalavamo a numeri sempre più grandi di nodi e sandbox, incontravamo continuamente nuovi colli di bottiglia derivanti da operazioni che erano O(sandbox) o O(nodi) ma non facili da scalare orizzontalmente.

Ad esempio, eseguiamo un workflow durevole per ogni sandbox che termina, quindi tassi elevati di churn di sandbox creerebbero enormi arretrati di eventi. Ci imbattavamo ripetutamente in RPC chiamati a un tasso O(sandbox) che causavano problemi di carico imprevisti in tutto il sistema. E il numero puro di nodi necessari per eseguire un gran numero di sandbox causava molteplici problemi a valle nella gestione dei nodi e nell'autoscaling. Infine, anche se potevamo aggirarlo, lasciare un'istanza Postgres non shardata nel percorso critico di tutta la creazione e lo scheduling delle sandbox si era rivelato una cattiva idea.

Sbloccare la scala infinita

Abbiamo capito rapidamente che raggiungere la scala desiderata richiedeva di ripensare la nostra architettura da zero. Vogliamo eseguire milioni di sandbox e crearne decine di migliaia al secondo, il che richiede proprietà di scalabilità molto migliori di qualsiasi cosa esistente. Piuttosto che cercare di evolvere ciò che avevamo, abbiamo creduto che il percorso più veloce e pulito fosse ricominciare da capo.

Per ottimizzare la scalabilità, abbiamo deciso che tutto ciò che comporta un carico O(sandbox) o O(nodi) deve essere orizzontalmente scalabile per impostazione predefinita, il percorso di creazione delle sandbox deve essere il più semplice possibile e tutto il resto deve essere secondario. La soluzione a cui siamo arrivati è notevolmente diversa dai sistemi esistenti. Abbiamo completamente eliminato qualsiasi tipo di coordinamento centrale e abbiamo scambiato la consistenza globale con scalabilità e prestazioni ovunque nel percorso critico per l'esecuzione e la creazione di sandbox. Ecco come funziona:

  • Invece di un singolo scheduler serializzato, eseguiamo una flotta di server di scheduling che gestiscono le richieste di creazione sandbox in contemporanea. Per gestire una richiesta di creazione, un server di scheduling esegue un algoritmo di scheduling veloce su dati cached in memoria. Il risultato è che lo scheduling scala orizzontalmente e assomiglia più a un load balancing che allo scheduling tradizionale di container.
  • Invece di un datastore durevole centrale che funge da fonte di verità per lo stato di sandbox e worker, che è come funzionano la maggior parte delle piattaforme container, ogni worker nel nostro nuovo sistema è la propria fonte di verità. I worker pubblicano periodicamente il loro stato in uno stream Redis. I server di scheduling consumano questo stato in modo asincrono e lo usano per prendere decisioni di scheduling. Una volta che un server di scheduling decide su quale worker creare una sandbox, contatta il worker direttamente tramite RPC per richiedere la creazione di una sandbox. I worker accettano la richiesta di scheduling se hanno risorse libere, altrimenti la rifiutano.
  • Non abbiamo datastore nel percorso critico della creazione di sandbox, il che migliora scalabilità e affidabilità. Mentre abbiamo bisogno di scrivere metadati e risultati delle sandbox in storage durevole, lo facciamo in gran parte in modo asincrono.
  • Oltre alle creazioni di sandbox, non abbiamo RPC che siano O(sandbox). I worker raggruppano messaggi di controllo per più sandbox insieme in singoli RPC, nello spirito delle idee del data-oriented design.
Modal - inline image

Il nostro design finale, la prima volta che lo abbiamo abbozzato su lavagna.

Modal - inline image

Percorso di creazione delle sandbox nell'architettura sandbox v2 di Modal. Le richieste di creazione sandbox vengono gestite da server di scheduling scalati orizzontalmente, che poi selezionano un worker con un algoritmo di load balancing veloce in memoria e contattano il worker (nodo di calcolo) direttamente per creare una sandbox. Gli oggetti sandbox sono memorizzati in Redis, ma non nel percorso critico.

Il risultato è che il percorso di creazione delle sandbox richiede solo due hop di rete e un'operazione CPU economica. Non ci sono colli di bottiglia centrali o costi di coordinamento, nessun singolo punto di fallimento e, di conseguenza, nessun tetto pratico alla scala aggregata delle sandbox o al throughput di creazione. Possiamo aggiungere più scheduler o worker secondo necessità. Il collo di bottiglia più imminente è che tutti i worker pubblicano lo stato su un singolo stream Redis, ma i test di carico hanno suggerito che questo rimane fattibile fino a ben oltre 100.000 worker; e non dipendiamo comunque dall'ordinamento sullo stream, quindi sarebbe facile aggiungere semplicemente più stream. Per design, evitiamo i problemi che impediscono alle soluzioni esistenti di scalare.

Costruire questa soluzione non è stato facile! L'intero processo di sviluppo ha richiesto mesi di lavoro, toccando la maggior parte dei sistemi principali del nostro backend. Abbiamo passato ore davanti alle lavagne. Quattro di noi si sono trasferiti in una casa in affitto a Miami Beach per costruire un prototipo del nuovo sistema che volevamo, senza distrazioni. Abbiamo passato otto giorni a scrivere codice fino a non poterne più fisicamente, giocando a scacchi veloci per recuperare, tuffandoci nell'oceano e poi tornando subito al codice, lottando per rendere il nostro nuovo sistema pulito e funzionale.

Modal - inline image

Il nostro miglior ingegnere che si rilassa a Miami Beach.

Una volta che abbiamo fatto funzionare i pezzi principali (e siamo tornati a New York), abbiamo anche dovuto reimplementare ogni singola funzionalità delle Sandbox e tutta l'osservabilità delle Sandbox sopra il nostro nuovo sistema. Questo progetto ha anche richiesto modifiche al nostro stack di gestione dei worker core, così come al nostro runtime container. Ad esempio, un problema interessante che abbiamo incontrato è che i nostri nuovi scheduler di sandbox potevano spingere i container ai worker così rapidamente che molti container che si avviavano contemporaneamente contendevano per il lock rtnl nel kernel Linux durante l'impostazione delle regole di rete dei container e impiegavano decine di secondi per avviarsi, quindi abbiamo dovuto cambiare la configurazione di rete dei container per le sandbox proprio per evitare che i nostri worker esplodessero quando inondati di creazioni di sandbox.

Come si comportano le nostre prestazioni

Abbiamo eseguito il benchmark del nostro sistema lanciando 1 milione di sandbox il più velocemente possibile. Ad alto livello, possiamo creare un milione di sandbox in meno di un minuto, dove il collo di bottiglia principale è il benchmark stesso. Il tempo di interattività delle singole sandbox rimane costantemente basso e non vediamo reali degradazioni con la scala.

Modal - inline image

Distribuzione ed eCDF delle richieste di creazione sandbox. Una richiesta di creazione sandbox restituisce quando i nostri server di scheduling hanno assegnato con successo una sandbox a un worker e questa ha iniziato ad avviarsi.

Crediamo che questo sia previsto, dato il nostro design. Non c'è coordinamento nel percorso di scheduling, quindi lo scheduling dovrebbe rimanere molto veloce indipendentemente dalla concorrenza e dalla scala. Per quanto ci riguarda, non abbiamo limiti seri allo scheduling concorrente di sandbox o alla scala al di fuori della capacità disponibile, e la gestione della capacità è già qualcosa che facciamo bene.

Modal - inline image

Scatterplot dei tempi di avvio di 10.000 sandbox dal nostro test di 1 milione di sandbox, selezionati casualmente tra le 1 milione di sandbox.

I tempi di avvio delle sandbox sul nostro nuovo sistema (la latenza dal momento in cui il client prova per la prima volta a creare una sandbox, a quando la sandbox può eseguire codice utente) sono inferiori a mezzo secondo in mediana e rimangono solidi a scala. Sono anche sostanzialmente più veloci del nostro vecchio sistema, in gran parte perché lo scheduling è molto più veloce — ora richiede solo decine di millisecondi. La coda lunga della latenza è un po' più lunga di quanto vorremmo. Attribuiamo gran parte di questa coda alla contesa del kernel e di rete (inclusa la contesa del lock rtnl menzionata in precedenza) quando molte sandbox si avviano simultaneamente sullo stesso worker, e stiamo lavorando per ridurla. Inoltre, la coda a scala è reale. Ci aspettiamo che questo migliori man mano che ottimizzeremo il percorso di avvio dei container.

Nel complesso, siamo molto contenti di questi numeri di prestazioni. Mentre gli agenti conquistano il mondo, chiaramente possiamo scalare con loro.

Vedi con i tuoi occhi

Presto questo nuovo sistema supporterà tutto lo scheduling delle sandbox in Modal, ma è già disponibile in Beta. Puoi aderire con un semplice cambiamento al tuo codice. Se hai bisogno di eseguire molte sandbox, provalo e parlaci!

Riconoscimenti

Molte persone hanno contribuito con sangue, sudore e lacrime a questo progetto. Il nostro POC di Miami è stato costruito da Colin Weld (io), Daniel Shaar, Walter Tang e Gleb Posobin, e poi portato in produzione da Walter, Colin, Connor Adams, Akshay Balwally, Tom Wildenhain, Scott Hao e Taylor Baldwin.

Salva con un clic

Leggi in profondità gli articoli virali con l’AI di YouMind

Salva la fonte, fai domande mirate, riassumi l’argomentazione e trasforma un articolo virale in note riutilizzabili in un unico spazio di lavoro AI.

Scopri YouMind
Per i creator

Trasforma il tuo Markdown in un articolo 𝕏 pulito

Quando pubblichi i tuoi testi lunghi, formattare immagini, tabelle e blocchi di codice per 𝕏 è una seccatura. YouMind trasforma un'intera bozza Markdown in un articolo 𝕏 pulito e pronto da pubblicare.

Prova Markdown verso 𝕏

Altri pattern da decodificare

Articoli virali recenti

Esplora altri articoli virali