수 초 만에 100만 개의 동시 샌드박스로 확장하기

@modal
영어1일 전 · 2026년 7월 16일
128K
415
41
14
515

TL;DR

Modal이 중앙 집중식 아키텍처에서 탈중앙화된 워커 중심 모델로 전환하여 수 초 만에 100만 개의 샌드박스를 실행할 수 있게 된 과정을 설명합니다.

이 글은 Colin Weld와 Connor Adams가 작성했습니다. 여기에서 읽거나 블로그에서 확인하세요.

Modal에서는 여러 기능 중에서도 샌드박스를 구축합니다. 에이전트는 샌드박스 내에서 실행되며, 에이전트가 소프트웨어를 집어삼키고 있습니다. 현재 Modal은 하루에 수백만 개의 샌드박스를 실행하며, 고객당 최대 5만 개의 동시 샌드박스를 지원하고, 강화 학습부터 백그라운드 에이전트에 이르기까지 다양한 대규모 사용 사례를 지원합니다.

점점 더 많은 사용자가 더욱 빠른 속도로 더 많은 샌드박스를 필요로 하고 있습니다. 강화 학습은 수백만 개의 샌드박스를 동시에 실행해야 할 수 있으며, 롤아웃 시작 시 수십만 개의 샌드박스를 한 번에 생성해야 합니다. 마찬가지로, 에이전트는 트래픽 급증을 처리하기 위해 점점 더 대규모 확장과 높은 동시 생성 속도를 요구합니다.

현재의 샌드박스 플랫폼은 매우 훌륭하지만, 이러한 규모를 염두에 두고 설계되지는 않았습니다. 다른 기존 솔루션도 마찬가지입니다. 우리는 확장성과 성능에 집착하며, 인프라가 에이전트의 성장을 가속화하고 마찰을 줄이길 원합니다. 그래서 우리는 처음부터 다시 설계했습니다.

지난 몇 달 동안, 우리는 확장성과 안정성 모두를 위해 핵심 샌드박스 플랫폼을 완전히 재구축했습니다. 새로운 시스템에서 사용자는 수백만 개의 샌드박스를 동시에 실행하고 초당 수만 개의 샌드박스를 생성할 수 있습니다. 컨트롤 플레인에서 모든 중앙 병목 현상을 제거하여 실질적인 확장 한계가 없도록 했으며, 컨테이너 스케줄링 및 시작의 모든 부분을 최적화하고, 스케줄링 경로를 워커 팜에 직접 컨테이너를 생성하는 로드 밸런서 계층으로 단순화했습니다.

플랫폼의 성능을 입증하기 위해, 우리는 100만 개의 샌드박스를 동시에 실행했으며, 100만 개 모두를 1분 이내에 생성했습니다.

Modal - inline image

많은 샌드박스를 실행할 수 있다는 증거.

대부분의 솔루션이 확장되지 않는 이유

100만 개의 샌드박스를 실행하는 것은 단순히 컨테이너의 수가 많기 때문만이 아니라, 이렇게 많은 샌드박스를 실행하려면 수만 대의 컴퓨트 노드가 필요하기 때문에 모든 컨테이너 플랫폼의 한계를 시험합니다. O(컨테이너), O(노드) 또는 둘 다에 해당하는 많은 작업이 있을 것이며, 이는 기존 컨테이너 플랫폼이 확장 한계에 부딪히게 만듭니다.

예를 들어 Kubernetes의 경우:

  • 스케줄링 알고리즘은 최악의 경우 n개의 노드와 p개의 파드에 대해 O(n x p)이며, 스케줄링은 기본적으로 직렬화됩니다.
  • 각 파드는 수명 주기 동안 etcd(중앙 Kubernetes 내구성 저장소)에 여러 번 쓰기 작업을 발생시켜, 높은 파드 생성 속도나 높은 파드 교체율에서 심각한 문제를 일으킬 수 있으며, etcd는 키스페이스 내에서 기본적으로 샤딩이 불가능합니다.
  • 각 노드는 하트비트 간격마다 최소 한 번씩 etcd에 쓰기 작업을 수행하여 활성 상태를 알려야 하므로, 기본 etcd 쓰기 부하는 파드 생성과 완전히 독립적으로 O(노드)입니다.
Modal - inline image

Kubernetes 스케줄링 흐름의 근사치. 새 파드는 API 서버에 의해 etcd(강력한 일관성을 가진 내구성 저장소)에 기록됩니다. Kubernetes 스케줄러는 할당되지 않은 새 파드를 감시하고, API 서버 호출을 통해 노드에 할당하며, 이는 다시 etcd에 기록됩니다. 이 쓰기가 완료된 후에야 노드가 파드를 시작할 수 있습니다.

Kubernetes는 확장 가능하지만, 상당한 작업이 필요합니다. 많은 수의 노드를 실행하려면 일반적으로 etcd를 재작성하거나 교체해야 합니다. 높은 스케줄링 처리량을 지원하려면 파드 상태에 대한 단일 진실 공급원을 유지하면서 스케줄링 알고리즘을 병렬화하는 복잡한 scatter-gather 시스템을 구축해야 합니다. Kubernetes는 설계의 근간으로 강력한 일관성에 의존하기 때문에 샤딩과 병렬화는 기본적으로 쉽지 않습니다.

Modal의 원래 샌드박스 아키텍처도 비슷한 문제가 있습니다. Kubernetes와 마찬가지로, 우리는 백엔드 전체에서 강력한 일관성에 의존하므로 샌드박스를 생성하고 스케줄링하려면 전역 조정이 필요하며, Postgres에 O(샌드박스) 쓰기 작업이 필요하며, 이는 쉽게 샤딩할 수 없습니다.

Modal - inline image

Modal의 원래 샌드박스 컨트롤 플레인 아키텍처. 샌드박스가 생성되면 큐에 배치되고 Postgres에 기록됩니다. 스케줄링은 낙관적이며 병렬로 실행되지만, 충돌을 피하기 위해 중앙 조정이 필요합니다. 샌드박스를 워커(컴퓨트 노드)에 할당하려면 Postgres에 추가 쓰기가 필요합니다.

우리는 Kubernetes 위에 구축하지 않기 때문에 이 시스템의 많은 부분을 확장할 수 있었습니다. 예를 들어, 스케줄링은 기본적으로 병렬화되어 있어 매우 높은 버스트 샌드박스 생성 속도를 달성할 수 있습니다. 그러나 노드와 샌드박스의 수가 점점 더 많아짐에 따라, O(샌드박스) 또는 O(노드)에 해당하지만 쉽게 확장할 수 없는 작업에서 새로운 병목 현상이 계속 발생했습니다.

예를 들어, 완료되는 각 샌드박스에 대해 내구성 있는 워크플로를 실행하므로, 높은 샌드박스 교체율은 엄청난 이벤트 백로그를 생성합니다. O(샌드박스) 속도로 호출되는 RPC가 시스템 전체에 예상치 못한 부하 문제를 일으키는 경우가 반복적으로 발생했습니다. 또한 많은 수의 샌드박스를 실행하는 데 필요한 노드 수 자체가 노드 관리 및 오토스케일링에서 여러 다운스트림 문제를 일으켰습니다. 마지막으로, 우회할 수는 있었지만, 모든 샌드박스 생성 및 스케줄링의 중요한 경로에 샤딩되지 않은 Postgres 인스턴스를 두는 것은 좋지 않은 생각임이 입증되었습니다.

무한한 확장성 확보

우리는 원하는 규모를 달성하려면 아키텍처를 근본부터 다시 생각해야 한다는 것을 빠르게 깨달았습니다. 우리는 수백만 개의 샌드박스를 실행하고 초당 수만 개의 샌드박스를 생성하기를 원하며, 이는 기존의 어떤 것보다 훨씬 더 나은 확장 속성을 필요로 합니다. 기존 시스템을 발전시키려고 노력하기보다는, 가장 빠르고 깔끔한 길은 새로 시작하는 것이라고 믿었습니다.

확장성을 최적화하기 위해, O(샌드박스) 또는 O(노드) 부하를 발생시키는 모든 것은 기본적으로 수평 확장이 가능해야 하고, 샌드박스 생성 경로는 가능한 한 간단해야 하며, 다른 모든 것은 부차적이어야 한다고 결정했습니다. 우리가 내놓은 솔루션은 기존 시스템과 현저히 다릅니다. 우리는 모든 종류의 중앙 조정을 완전히 없애고, 샌드박스 실행 및 생성의 중요한 경로에서 전역 일관성을 확장성과 성능과 맞바꿨습니다. 작동 방식은 다음과 같습니다.

  • 단일 직렬화된 스케줄러 대신, 샌드박스 생성 요청을 동시에 처리하는 스케줄링 서버 플릿을 운영합니다. 스케줄링 서버는 생성 요청을 처리하기 위해 인메모리 캐시된 데이터에 대해 빠른 스케줄링 알고리즘을 실행합니다. 그 결과, 스케줄링은 수평으로 확장되며, 기존 컨테이너 스케줄링보다는 로드 밸런싱에 가깝습니다.
  • 대부분의 컨테이너 플랫폼이 작동하는 방식인 샌드박스 및 워커 상태의 진실 공급원 역할을 하는 중앙의 내구성 있는 데이터 저장소 대신, 새 시스템의 모든 워커는 자체 진실 공급원입니다. 워커는 주기적으로 자신의 상태를 Redis 스트림에 게시합니다. 스케줄링 서버는 이 상태를 비동기적으로 소비하여 스케줄링 결정을 내리는 데 사용합니다. 스케줄링 서버가 샌드박스를 생성할 워커를 결정하면, RPC를 통해 해당 워커에 직접 연락하여 샌드박스 생성을 요청합니다. 워커는 사용 가능한 리소스가 있으면 스케줄링 요청을 수락하고, 그렇지 않으면 거부합니다.
  • 샌드박스 생성의 중요한 경로에는 데이터 저장소가 전혀 없어 확장성과 안정성이 향상됩니다. 샌드박스 메타데이터와 결과를 내구성 있는 저장소에 기록해야 하지만, 대부분 비동기적으로 수행합니다.
  • 샌드박스 생성 외에는 O(샌드박스)인 RPC가 없습니다. 워커는 데이터 지향 설계의 아이디어에 따라 여러 샌드박스에 대한 제어 메시지를 단일 RPC로 일괄 처리합니다.
Modal - inline image

우리가 처음 화이트보드에 그렸던 최종 설계.

Modal - inline image

Modal v2 샌드박스 아키텍처의 샌드박스 생성 경로. 샌드박스 생성 요청은 수평 확장된 스케줄링 서버에서 처리되며, 빠른 인메모리 로드 밸런싱 알고리즘으로 워커를 선택한 후 워커(컴퓨트 노드)에 직접 연락하여 샌드박스를 생성합니다. 샌드박스 객체는 Redis에 저장되지만, 중요한 경로에는 있지 않습니다.

결과적으로 샌드박스 생성 경로는 단 두 번의 네트워크 홉과 한 번의 저렴한 CPU 작업만 필요합니다. 중앙 병목 현상이나 조정 비용, 단일 장애 지점이 없으며, 결과적으로 샌드박스 규모나 샌드박스 생성 처리량에 실질적인 상한선이 없습니다. 필요에 따라 더 많은 스케줄러나 워커를 추가할 수 있습니다. 가장 임박한 병목 현상은 모든 워커가 단일 Redis 스트림에 상태를 게시한다는 점이지만, 부하 테스트 결과 워커 수가 100,000대를 훨씬 넘을 때까지 이 방식이 유지됨을 보여줍니다. 또한 우리는 어차피 스트림의 순서에 의존하지 않으므로 스트림을 더 추가하는 것도 쉽습니다. 설계상, 우리는 기존 솔루션의 확장을 막는 문제들을 피했습니다.

이 솔루션을 구축하는 것은 쉽지 않았습니다! 전체 개발 과정은 백엔드의 주요 시스템 대부분을 포괄하며 수개월의 작업이 소요되었습니다. 우리는 화이트보드 앞에서 수시간을 보냈습니다. 네 명의 팀원은 방해받지 않고 우리가 원하는 새 시스템의 프로토타입을 구축하기 위해 마이애미 비치의 렌트 하우스로 자리를 옮겼습니다. 우리는 물리적으로 더 이상 버틸 수 없을 때까지 8일 동안 코드를 작성했고, 스피드 체스로 회복하며, 바다에 뛰어들었다가, 다시 바로 코드로 돌아와 새 시스템을 깔끔하고 기능적으로 만들기 위해 고군분투했습니다.

Modal - inline image

마이애미 비치에서 휴식을 취하는 우리 최고의 엔지니어.

핵심 부분이 작동하는 것을 확인하고(뉴욕으로 돌아온 후), 우리는 모든 샌드박스 기능과 샌드박스 관찰 가능성을 새 시스템 위에 다시 구현해야 했습니다. 이 프로젝트는 핵심 워커 관리 스택과 컨테이너 런타임의 변경도 필요로 했습니다. 예를 들어, 우리가 직면한 흥미로운 문제 중 하나는 새 샌드박스 스케줄러가 너무 빨리 워커에 컨테이너를 푸시할 수 있어서, 동시에 많은 컨테이너가 시작되면 컨테이너 네트워킹 규칙을 설정할 때 Linux 커널의 rtnl 잠금을 놓고 경쟁하여 시작하는 데 수십 초가 걸릴 수 있다는 점이었습니다. 그래서 샌드박스 생성 요청이 워커에 쇄도할 때 워커가 폭주하지 않도록 샌드박스의 컨테이너 네트워킹 설정을 변경해야 했습니다.

성능 비교

우리는 가능한 한 빨리 100만 개의 샌드박스를 가동하여 시스템을 벤치마킹했습니다. 높은 수준에서, 우리는 1분 이내에 100만 개의 샌드박스를 생성할 수 있으며, 주요 병목 현상은 벤치마크 자체입니다. 개별 샌드박스의 상호 작용 가능 시간은 일관되게 낮게 유지되며, 규모에 따른 성능 저하가 거의 없습니다.

Modal - inline image

샌드박스 생성 요청의 분포 및 eCDF. 샌드박스 생성 요청은 스케줄링 서버가 샌드박스를 워커에 성공적으로 할당하고 시작하기 시작하면 반환됩니다.

우리는 이것이 우리의 설계를 고려할 때 예상된 결과라고 믿습니다. 스케줄링 경로에는 조정이 없으므로, 스케줄링은 동시성 및 규모와 관계없이 매우 빠르게 유지되어야 합니다. 우리가 보기에, 가용 용량 외에는 동시 샌드박스 스케줄링 또는 규모에 심각한 제한이 없으며, 용량 관리는 이미 우리가 잘하는 일입니다.

Modal - inline image

100만 개의 샌드박스 테스트에서 10,000개 샌드박스 시작 시간의 산점도, 100만 개의 샌드박스에서 무작위로 선택됨.

새 시스템의 샌드박스 시작 시간(클라이언트가 처음 샌드박스 생성을 시도한 시점부터 샌드박스가 사용자 코드를 실행할 수 있을 때까지의 지연 시간)은 중앙값 기준 0.5초 미만이며, 규모가 커져도 견고합니다. 또한 이전 시스템보다 훨씬 빠릅니다. 이는 주로 스케줄링이 훨씬 빨라졌기 때문이며, 이제는 수십 밀리초밖에 걸리지 않습니다. 지연 시간의 긴 꼬리는 우리가 원하는 것보다 다소 깁니다. 이 꼬리의 많은 부분은 동일한 워커에서 많은 샌드박스가 동시에 시작될 때 발생하는 커널 및 네트워크 경합(앞서 언급한 rtnl 잠금 경합 포함)에 기인하며, 이를 줄이기 위해 노력하고 있습니다. 또한, 규모에서의 꼬리 지연은 현실입니다. 컨테이너 시작 경로를 최적화함에 따라 이 부분이 개선될 것으로 예상합니다.

전반적으로, 우리는 이러한 성능 수치에 매우 만족합니다. 에이전트가 세상을 장악함에 따라, 우리는 분명히 그들과 함께 확장할 수 있습니다.

직접 확인해보세요

곧 이 새 시스템이 Modal의 모든 샌드박스 스케줄링을 지원하게 될 것이지만, 이미 베타 버전으로 사용할 수 있습니다. 코드를 한 줄만 변경하면 옵트인할 수 있습니다. 많은 샌드박스를 실행해야 한다면, 사용해보고 저희에게 문의하세요!

감사의 말

이 프로젝트에는 많은 사람들이 피와 땀과 눈물을 기울였습니다. 마이애미 POC는 Colin Weld(저), Daniel Shaar, Walter Tang, Gleb Posobin이 구축했으며, 이후 Walter, Colin, Connor Adams, Akshay Balwally, Tom Wildenhain, Scott Hao, Taylor Baldwin이 프로덕션 환경으로 전환했습니다.

원클릭 저장

YouMind로 바이럴 글을 AI 심층 읽기

소스를 저장하고, 핵심 질문을 던지고, 주장을 요약해 바이럴 글을 다시 활용할 수 있는 노트로 바꾸세요. 하나의 AI 워크스페이스에서 모두 할 수 있습니다.

YouMind 둘러보기
크리에이터를 위해

당신의 Markdown을 깔끔한 𝕏 글로

직접 쓴 장문을 올릴 때 이미지, 표, 코드 블록을 𝕏에 맞게 정리하는 일은 번거롭습니다. YouMind는 전체 Markdown 초안을 깔끔하고 바로 게시할 수 있는 𝕏 글로 바꿔 줍니다.

Markdown → 𝕏 사용해 보기

분석할 패턴 더 보기

최근 바이럴 아티클

더 많은 바이럴 아티클 보기