Passer à 1 million de bacs à sable simultanés en quelques secondes

@modal
ANGLAISil y a 1 jour · 16 juil. 2026
128K
415
41
14
515

TL;DR

Modal explique sa transition d'une architecture centralisée vers un modèle décentralisé axé sur les travailleurs, permettant de lancer 1 million de bacs à sable en quelques secondes.

Cet article a été rédigé par Colin Weld et Connor Adams. Lisez-le ici ou sur notre blog.

Chez Modal, nous construisons des sandboxes, entre autres. Les agents s'exécutent dans des sandboxes, et les agents sont en train de dévorer le logiciel. Aujourd'hui, Modal exécute des millions de sandboxes par jour, prend en charge jusqu'à cinquante mille sandboxes simultanées par client, et supporte une variété de cas d'utilisation à grande échelle, de l'apprentissage par renforcement aux agents en arrière-plan.

De plus en plus, nos utilisateurs ont besoin de plus en plus de sandboxes, créées à des taux de plus en plus élevés. L'apprentissage par renforcement peut nécessiter l'exécution simultanée de millions de sandboxes, et la création de rafales de centaines de milliers de sandboxes au début des déploiements. De même, les agents nécessitent de plus en plus une échelle massive et des taux de création simultanée élevés pour faire face aux pics de trafic.

Notre plateforme de sandbox existante est vraiment bonne, mais elle n'a pas été conçue pour ces échelles ; et aucune autre solution existante ne l'est non plus. Nous sommes obsédés par l'échelle et la performance, et nous voulons que notre infrastructure accélère la croissance des agents, sans ajouter de friction. Nous sommes donc retournés à la planche à dessin.

Au cours des derniers mois, nous avons reconstruit notre plateforme de sandbox centrale de fond en comble pour l'échelle et la fiabilité. Sur notre nouveau système, les utilisateurs peuvent exécuter des millions de sandboxes simultanément et créer des dizaines de milliers de sandboxes par seconde. Nous avons supprimé tous les goulots d'étranglement centraux de notre plan de contrôle afin qu'il n'y ait pas de limites d'échelle pratiques, et nous avons optimisé chaque partie de l'ordonnancement et du démarrage des conteneurs, simplifiant le chemin d'ordonnancement à une couche de répartiteurs de charge qui créent des conteneurs directement sur notre flotte de workers.

Pour démontrer les capacités de notre plateforme, nous avons exécuté un million de sandboxes simultanément, créant le million en moins d'une minute.

Modal - inline image

Preuve que nous pouvons exécuter beaucoup de sandboxes.

Pourquoi la plupart des solutions ne passent pas à l'échelle

Exécuter 1 million de sandboxes repousse les limites de toute plateforme de conteneurs, à la fois en raison du nombre pur de conteneurs, mais aussi parce que l'exécution d'autant de sandboxes nécessite des dizaines de milliers de nœuds de calcul. Il y aura de nombreuses opérations qui sont soit O(conteneurs), soit O(nœuds), soit les deux, ce qui fera que les plateformes de conteneurs traditionnelles atteindront des limites de passage à l'échelle.

Pour Kubernetes, par exemple :

  • l'algorithme d'ordonnancement est O(n x p) pour n nœuds et p pods dans le pire des cas, et l'ordonnancement est sérialisé par défaut.
  • chaque pod provoque plusieurs écritures dans etcd (le magasin durable central de Kubernetes) au cours de sa vie, ce qui peut créer de sérieux problèmes sous des taux élevés de création de pods ou un fort turnover de pods, et etcd n'est pas nativement partitionnable au sein d'un espace de clés
  • chaque nœud doit écrire dans etcd au moins une fois par intervalle de battement de cœur pour signaler qu'il est vivant, donc la charge d'écriture de base d'etcd est O(nœuds) complètement indépendante de la création de pods
Modal - inline image

Approximation du flux d'ordonnancement de Kubernetes. Les nouveaux pods sont écrits dans etcd (un magasin durable fortement cohérent) par le serveur API. Le planificateur Kubernetes surveille les nouveaux pods non assignés et les affecte aux nœuds via un appel au serveur API, qui écrit à nouveau dans etcd ; après que cette écriture est effectuée, un nœud peut démarrer le pod.

Kubernetes peut être mis à l'échelle, mais cela nécessite un travail sérieux. Pour exécuter un grand nombre de nœuds, etcd doit généralement être réécrit ou remplacé. Prendre en charge un débit d'ordonnancement élevé nécessite de construire un système scatter-gather complexe pour paralléliser l'algorithme d'ordonnancement tout en maintenant une source unique de vérité pour l'état des pods. Le partitionnement et la parallélisation ne sont pas faciles par défaut, car Kubernetes repose sur une forte cohérence comme base de sa conception.

L'architecture originale des sandboxes de Modal présente des problèmes similaires. Comme Kubernetes, nous nous appuyons sur une forte cohérence dans tout notre backend, donc la création et l'ordonnancement des sandboxes nécessitent une coordination globale, et O(sandboxes) écritures dans Postgres, que nous ne pouvons pas partitionner trivialement.

Modal - inline image

L'architecture du plan de contrôle original des sandboxes de Modal. Lorsque les sandboxes sont créées, elles sont placées dans une file d'attente et écrites dans Postgres. L'ordonnancement est optimiste et exécuté en parallèle, avec une coordination centrale nécessaire pour éviter les conflits. L'affectation d'une sandbox à un worker (nœud de calcul) nécessite une écriture supplémentaire dans Postgres.

Parce que nous ne construisons pas sur Kubernetes, nous avons pu mettre à l'échelle horizontalement de nombreuses parties de ce système. Par exemple, l'ordonnancement est parallélisé par défaut, ce qui nous permet d'atteindre des taux de création de sandboxes en rafale très élevés. Mais à mesure que nous passions à des nombres toujours plus grands de nœuds et de sandboxes, nous rencontrions continuellement de nouveaux goulots d'étranglement provenant d'opérations qui étaient soit O(sandboxes) soit O(nœuds) mais qui n'étaient pas faciles à passer à l'échelle horizontalement.

Par exemple, nous exécutons un workflow durable pour chaque sandbox qui se termine, donc des taux élevés de turnover de sandboxes créeraient d'énormes arriérés d'événements. Nous rencontrions à plusieurs reprises des RPC appelés à un taux de O(sandboxes) qui causaient des problèmes de charge inattendus dans tout notre système. Et le nombre pur de nœuds nécessaires pour exécuter un grand nombre de sandboxes causait de multiples problèmes en aval dans la gestion des nœuds et l'auto-scaling. Enfin, même si nous pouvions contourner le problème, laisser une instance Postgres non partitionnée dans le chemin critique de toute création et ordonnancement de sandbox s'était avéré être une mauvaise idée.

Débloquer une échelle infinie

Nous avons rapidement réalisé qu'atteindre l'échelle que nous voulions nécessitait de repenser notre architecture de fond en comble. Nous voulons exécuter des millions de sandboxes et créer des dizaines de milliers de sandboxes par seconde, ce qui nécessite des propriétés de passage à l'échelle bien meilleures que tout ce qui existe. Plutôt que d'essayer de faire évoluer ce que nous avions, nous avons cru que le chemin le plus rapide et le plus propre était de repartir de zéro.

Pour optimiser l'échelle, nous avons décidé que tout ce qui prend une charge O(sandboxes) ou O(nœuds) doit être scalable horizontalement par défaut, le chemin de création de sandbox doit être aussi simple que possible, et tout le reste doit être secondaire. La solution à laquelle nous sommes arrivés est notablement différente des systèmes existants. Nous avons complètement abandonné toute forme de coordination centrale, et échangé la cohérence globale contre la scalabilité et la performance partout sur le chemin critique pour l'exécution et la création de sandboxes. Voici comment cela fonctionne :

  • Plutôt qu'un seul planificateur sérialisé, nous exécutons une flotte de serveurs d'ordonnancement qui traitent les demandes de création de sandbox en concurrence. Pour traiter une demande de création, un serveur d'ordonnancement exécute un algorithme d'ordonnancement rapide sur des données mises en cache en mémoire. Le résultat est que l'ordonnancement passe à l'échelle horizontalement et ressemble plus à de l'équilibrage de charge qu'à de l'ordonnancement de conteneurs traditionnel.
  • Plutôt qu'un magasin de données central et durable servant de source de vérité pour l'état des sandboxes et des workers, ce qui est le fonctionnement de la plupart des plateformes de conteneurs, chaque worker de notre nouveau système est sa propre source de vérité. Les workers publient périodiquement leur état dans un flux Redis. Les serveurs d'ordonnancement consomment cet état de manière asynchrone et l'utilisent pour prendre des décisions d'ordonnancement. Une fois qu'un serveur d'ordonnancement décide sur quel worker créer une sandbox, il contacte le worker directement via RPC pour demander la création d'une sandbox. Les workers acceptent la demande d'ordonnancement s'ils ont des ressources libres, ou la rejettent sinon.
  • Nous n'avons aucun magasin de données dans le chemin critique de la création de sandbox, ce qui améliore la scalabilité et la fiabilité. Bien que nous ayons besoin d'écrire les métadonnées et les résultats des sandboxes dans un stockage durable, nous le faisons en grande partie de manière asynchrone.
  • En dehors des créations de sandbox, nous n'avons pas de RPC qui soient O(sandboxes). Les workers regroupent les messages de contrôle pour plusieurs sandboxes dans des RPC uniques, dans l'esprit des idées de la conception orientée données.
Modal - inline image

Notre conception finale, la première fois que nous l'avons schématisée au tableau.

Modal - inline image

Chemin de création de sandbox dans l'architecture de sandbox v2 de Modal. Les demandes de création de sandbox sont traitées par des serveurs d'ordonnancement mis à l'échelle horizontalement, qui sélectionnent ensuite un worker avec un algorithme d'équilibrage de charge rapide en mémoire, et contactent le worker (nœud de calcul) directement pour créer une sandbox. Les objets sandbox sont stockés dans Redis, mais pas dans le chemin critique.

Le résultat est que le chemin de création de sandbox ne nécessite que deux sauts réseau et une opération CPU peu coûteuse. Il n'y a pas de goulots d'étranglement centraux ni de coûts de coordination, pas de points de défaillance uniques, et par conséquent pas de plafond pratique pour l'échelle agrégée des sandboxes ou le débit de création de sandboxes. Nous pouvons ajouter plus de planificateurs ou de workers selon les besoins. Le goulot d'étranglement le plus imminent est que tous les workers publient leur état dans un seul flux Redis, mais les tests de charge ont suggéré que cela reste viable jusqu'à bien plus de 100 000 workers ; et nous ne dépendons pas de l'ordre sur le flux de toute façon, donc il serait facile d'ajouter simplement plus de flux. Par conception, nous évitons les problèmes qui empêchent les solutions existantes de passer à l'échelle.

Construire cette solution n'a pas été facile ! Tout le processus de développement a pris des mois de travail, couvrant la plupart des grands systèmes de notre backend. Nous avons passé des heures devant des tableaux blancs. Quatre d'entre nous se sont retirés dans une maison de location à Miami Beach pour construire un prototype du nouveau système que nous voulions, sans distractions. Nous avons passé huit jours à écrire du code jusqu'à ne plus en pouvoir physiquement, jouant aux échecs rapides pour récupérer, sautant dans l'océan, puis retournant directement au code, luttant pour rendre notre nouveau système propre et fonctionnel.

Modal - inline image

Notre meilleur ingénieur se relaxant à Miami Beach.

Une fois que nous avons fait fonctionner les pièces principales (et que nous sommes revenus à New York), nous avons également dû réimplémenter chaque fonctionnalité de Sandbox et toute l'observabilité des Sandboxes sur notre nouveau système. Ce projet a également nécessité des changements dans notre pile de gestion des workers, ainsi que dans notre runtime de conteneurs. Par exemple, un problème intéressant que nous avons rencontré est que nos nouveaux planificateurs de sandbox pouvaient pousser les conteneurs vers les workers si rapidement que de nombreux conteneurs démarrant en même temps se disputeraient le verrou rtnl dans le noyau Linux lors de la configuration des règles de réseau de conteneurs et mettraient des dizaines de secondes à démarrer, nous avons donc dû modifier notre configuration réseau de conteneurs pour les sandboxes juste pour que nos workers n'explosent pas lorsqu'ils sont inondés de créations de sandbox.

Comment nos performances se comparent

Nous avons évalué notre système en lançant 1 million de sandboxes aussi vite que possible. À un niveau élevé, nous pouvons créer un million de sandboxes en moins d'une minute, où le principal goulot d'étranglement est le benchmark lui-même. Le temps individuel jusqu'à l'interactivité des sandboxes reste constamment bas, et nous ne voyons pas de dégradations réelles avec l'échelle.

Modal - inline image

Distribution et eCDF des demandes de création de sandbox. Une demande de création de sandbox renvoie une fois que nos serveurs d'ordonnancement ont assigné avec succès une sandbox à un worker, et que celle-ci a commencé à démarrer.

Nous pensons que c'est attendu, compte tenu de notre conception. Il n'y a pas de coordination dans le chemin d'ordonnancement, donc l'ordonnancement devrait rester très rapide indépendamment de la concurrence et de l'échelle. En ce qui nous concerne, nous n'avons pas de limites sérieuses à l'ordonnancement simultané de sandboxes ou à l'échelle en dehors de la capacité disponible, et gérer la capacité est quelque chose que nous faisons déjà bien.

Modal - inline image

Diagramme de dispersion des temps de démarrage de 10 000 sandboxes de notre test d'un million de sandboxes, sélectionnées aléatoirement parmi le million de sandboxes.

Les temps de démarrage des sandboxes sur notre nouveau système (la latence entre le moment où le client essaie pour la première fois de créer une sandbox et le moment où la sandbox peut exécuter du code utilisateur) sont inférieurs à une demi-seconde à la médiane, et restent solides à grande échelle. Ils sont également substantiellement plus rapides que notre ancien système, en grande partie parce que l'ordonnancement est beaucoup plus rapide — il ne prend que des dizaines de millisecondes maintenant. La queue de latence longue est un peu plus longue que nous le souhaiterions. Nous attribuons une grande partie de cette queue à la contention du noyau et du réseau (y compris la contention du verrou rtnl mentionnée précédemment) lorsque de nombreuses sandboxes démarrent simultanément sur le même worker, et nous travaillons à la réduire. De plus, la queue à grande échelle est réelle. Nous nous attendons à ce que cela s'améliore à mesure que nous optimisons le chemin de démarrage des conteneurs.

Dans l'ensemble, nous sommes très satisfaits de ces chiffres de performance. Alors que les agents conquièrent le monde, nous pouvons clairement passer à l'échelle avec eux.

Voyez par vous-même

Bientôt, ce nouveau système soutiendra tout l'ordonnancement de sandbox chez Modal, mais il est déjà disponible en bêta. Vous pouvez y adhérer avec un simple changement dans votre code. Si vous avez besoin d'exécuter beaucoup de sandboxes, essayez-le et parlez-nous !

Remerciements

Beaucoup de personnes ont contribué à ce projet avec sang, sueur et larmes. Notre POC de Miami a été construit par Colin Weld (moi), Daniel Shaar, Walter Tang et Gleb Posobin, puis mis en production par Walter, Colin, Connor Adams, Akshay Balwally, Tom Wildenhain, Scott Hao et Taylor Baldwin.

Enregistrer en un clic

Lire les articles viraux en profondeur avec l’IA de YouMind

Enregistrez la source, posez des questions ciblées, résumez l’argument et transformez un article viral en notes réutilisables dans un seul espace de travail IA.

Découvrir YouMind
Pour les créateurs

Transformez votre Markdown en un article 𝕏 impeccable

Quand vous publiez vos propres textes longs, la mise en forme 𝕏 des images, tableaux et blocs de code est pénible. YouMind transforme un brouillon Markdown complet en un article 𝕏 impeccable, prêt à publier.

Essayer Markdown vers 𝕏

D'autres patterns à décoder

Articles viraux récents

Explorer plus d'articles viraux