Modal Notebooks 内部实现:如何做到秒级启动的云端 GPU notebook
Inside Modal Notebooks: How we built a cloud GPU notebook that boots in seconds
Modal 发布云端 Jupyter notebook 产品 Modal Notebooks,可在数秒内启动 GPU 和自定义镜像,并支持实时协作。内核运行在 Modal Sandboxes 中,通过 modal-kernelshim 把 Jupyter 协议消息转为 HTTP 调用;容器镜像采用懒加载文件系统,按需拉取文件内容。
原文拆解了云端 GPU notebook 从沙箱、懒加载镜像到协作编辑的实现路径,可供做交互式算力产品的团队参考。
👋 你好,我是 Eric。我在 Modal 从事系统和产品方面的工作。
我们最近推出了 Modal Notebooks,这是一个全新的云端 Jupyter notebook,可以在几秒内启动 GPU 和任意自定义镜像,并且支持实时协作。
我想分享一些让这种体验成为可能的工程实践。这篇文章不是关于功能的,而是关于在云端运行交互式、高性能 GPU 工作负载的同时仍能保持即时响应背后的系统工作。
Notebooks 最初只是一个小实验:我们能否在不牺牲本地速度的前提下,构建一个托管的、可协作的 notebook? 如今大多数超级计算工作流都涉及在一台必须保持热启动的大型、昂贵的 devbox 上转发 Jupyter 服务器(再加上用于批处理运行的 Slurm)。我们想要更好的东西——一个现代编辑器,将协作与 Modal 的原语(如持久化存储、自定义镜像和即时访问 GPU)结合起来。
“
Modal Notebooks 在 Suno 内部共享 ML 研究方面表现出色。工程师和设计师可以在训练运行完成后几分钟内就开始把玩最前沿的模型。
”
— Victor Tao, ML 研究工程师
在这篇文章中,我将介绍我们是如何做到的,从运行时(沙箱、镜像加载、内核协议)到协作层,最后到编辑器界面。
用于有状态后端的 Modal Sandboxes
一切都始于内核。
每个 Jupyter notebook 的核心都是内核协议,这是你与 IPython 内核进程“对话”以运行代码的语言。乍一看可能很复杂,但思路很简单:发送一个代码单元进去,拿回结果,外加 stdout、stderr 和富输出的流。
在标准设置中,Jupyter 运行在单台后端机器上,与 Web 编辑器一对一连接。要在协作式、多租户的云 GPU 环境中可靠地运行它,我们需要重新思考这一模型。
从计算层开始,内核运行在 Modal Sandboxes 中:这是我们用于安全、隔离进程的抽象,拥有自己的文件系统、资源和生命周期。它们是一个低层 API,可以在几秒内在世界各地启动容器。
与其他沙箱系统(Cloudflare、Vercel、e2b)相比,Modal Sandboxes 略有不同:它们旨在支持高性能工作负载,拥有数百个 CPU、顶级 Nvidia GPU、数 GB 磁盘,以及一个惰性加载的、内容寻址的 FUSE 文件系统。这意味着 Modal Sandboxes 可以运行 AI 工作负载。
(Modal Sandboxes 不只是给我们自己用的;它们是我们希望其他人也能使用的原语。例如,Lovable 就是用它来运行 AI 开发者环境的。Marimo 也在 Sandboxes 之上构建了他们的 Molab 云产品,这是一种与 Modal 自家产品非常不同的 notebook 体验,这表明 Sandboxes 可以支撑多种交互式计算。)
为了弥合内核与外部世界之间的鸿沟,我们编写了一个名为 modal-kernelshim 的守护进程,它驻留在每个 Sandbox 内部。它将基于 ZeroMQ 的 Jupyter 协议消息转换为通过我们控制平面隧道的 HTTP 调用。这让我们能够以看起来像本地 Jupyter 内核、但大大简化的方式处理代码单元执行、中断和关闭。
从用户的角度来看,只要代码一运行,流式输出就会立即出现在浏览器中。而在幕后,这些输出通过 TLS 从 Sandbox 经由服务器组件发送回前端。
这种架构(shim → 服务器 → 前端)正是我们实现即时、远程访问内核的方式,同时提供可供多用户连接的现代界面。
即时、分布式的容器基础设施
过去 4 年,我们一直在默默构建大量分布式系统和核心基础设施,为我们的容器运行时提供支撑。我想在这里分享其中一些工作,因为归根结底,正是这些底层系统让 Notebooks 得以运转。
延迟加载容器镜像
启动容器时最大的延迟来源之一是解包镜像。在 Docker 或 Kubernetes 中,启动一个 8 GB 的 Python/ML 镜像意味着必须先下载并解压各层,然后才能运行任何东西——通常接近一分钟。
对于长期运行的服务来说这没问题,但它会扼杀交互式笔记本中的反馈循环。
我们的解决方案是构建一个延迟加载的容器文件系统。我们不会预先拉取每个文件,而是只加载一个轻量级元数据索引,并通过 Rust FUSE 服务器挂载它。实际文件内容会在你的进程访问它们的瞬间按需获取。
这些读取会流经一个内容寻址的分层缓存:内存页缓存、本地 SSD、区域缓存服务器、区域 CDN,最后是 blob 存储。大多数访问都会命中其中某个快速层级;当没有命中时,我们只流式传输你实际需要的文件,速度通常足以跑满硬件。
这个文件系统及其相关的容器运行时,实际上是我作为创始工程师加入 Modal 时构建的第一批东西:公司里最早的一批 Rust 代码。它最初只是一个用于改进基准测试的实验,如今已成为实现快速容器启动的基础,从笔记本到生产级 AI 推理都依赖它。
调度与容量
高效运行笔记本不仅仅关乎快速启动容器——还关乎这些容器如何被放置。在 Modal,笔记本与我们的函数共享同一个资源池,背后是数千个 CPU 和 GPU。调度器会在这个池中平衡工作负载,因此无论你是从 0.125 个 CPU 起步,还是扩展到多个 H100 或 B200,只要有容量,你的容器仍会被即时放置。
我们之前写过我们如何自动扩展我们的机群以匹配需求,横跨多个云并针对价格进行优化。
笔记本还带来了另一个问题:内核经常处于空闲状态。让一个巨大的 GPU 实例空转是烧钱的快方式。我们的解决方案是自动暂停它们;当你回来时,它们会在几秒内重新启动。你能获得持久机器的体验,却无需承担维持其存活的额外开销。
卷
现代 AI 工作负载围绕数据运转。训练是数据输入、权重输出。推理流水线通过一连串步骤移动检查点、嵌入和输出。没有持久化存储,这一切都无法运作——而在一个容量会跨区域和硬件变化的无服务器世界中,持久化正是保持工作负载一致性的关键。为了让 Notebooks 可行,我们需要一个全局、可变且快速的存储系统。
这正是 VolumeFS 所提供的,它是 Modal Volumes 的骨干。它是一个为全局访问而设计的 FUSE 文件系统,构建在存储数 PB 数据的分布式网络之上。
老实说,要在这篇博客文章中描述 VolumeFS,涉及的组件太多了。但可以说,它是 Modal 的核心基础设施之一,让整个平台得以整合在一起。简要总结就是:文件树存放在 Spanner 中,操作被设计为最终一致,并且我们复用了分布式的内容寻址 CDN。我们期待之后讨论 Modal Volumes 的内部机制。
像任何优秀的系统一样,用户永远不必考虑这些!结果是文件感觉像是本地的,但行为却是全局的。你可以在世界任何地方启动计算,同时仍然拥有你的数据。
实时协作
Notebook 天生具有社交属性。它们不仅用于运行代码,还用于共同探索想法并留下可读的记录。因此我们需要实时协作编辑。
为此,我们借助了 Rushlight,这是几年前我在 CodeMirror 6 中试验操作转换时开源的一个小型库。当时,我想要一个更简单、可自托管的协作层。轻量且健壮,在你自己的数据库中实现实时存储和自动压缩。
每一次编辑都流经 Redis Streams,并在那里广播给其他客户端。OT 层确保变更收敛,即使有多人同时输入。在前端,CodeMirror 处理在线状态和多个光标。
我们将编辑状态与执行状态分离。当你运行一个单元格时,输出会实时内联流式返回,但之后重新连接的任何人都可以随时从后端重新获取当前状态。更大的结果——图表、视频、模型输出——会被推送到 S3 Express One Zone,这样编辑流就能保持快速,同时输出仍然持久且可检索。
一些团队要求与 Modal 组织外部的利益相关者共享 notebook,因此我们添加了基于链接的共享,并允许嵌入 Jupyter Widgets 以增加交互性。这样,notebook 就不仅仅是一个草稿本——它还可以兼作轻量级的演示界面。我们在 Modal Notebooks 上实现了 widget 协议。据我们所知,这是 widget 在实时协作编辑环境中的首个可用实现!
编辑器功能:LSP 和 AI 补全
在 2025 年,编辑器需要足够智能。Jupyter 在开发者体验方面历来落后——补全、内联文档和语义高亮从来都不能开箱即用。对于 Modal Notebooks,我们希望这些能力是原生的。
我们从实现 Language Server Protocol 的核心部分(textDocument/completions、textDocument/hover、textDocument/semanticTokens/full)开始,并将它们接入 Pyright。这为你带来了补全、文档和语义高亮。我们将其中一些实现开源了。
我们还集成了 Ruff 的自动格式化,直接在前端运行其前沿的 WebAssembly 构建。
在 AI 方面,我们尝试了编辑预测。目前我们使用 Claude 4 来提供下一步编辑建议。我们还尝试更进一步,将推理直接托管在 Modal 上。那个版本在 H100 GPU 上运行 Zed 的 Zeta 模型,直接从我们自己的云基础设施提供补全服务。不过,在将其设为默认之前,还需要做一些 UI 调整。
我认为我们确实打造出了真正称得上一流开发环境的东西,既有现代编辑器功能,又有 GPU 支持的执行能力。
结论
多年来,我们一直在 Modal 思考基础基础设施,始终以系统目标为核心:速度、性能、效率和易用性。每一层都建立在前一层之上。Modal Notebooks 是文件系统、操作系统、分布式系统、调度、安全、沙箱、隔离等诸多方面大量工作的结晶。
诚然,尽管我们在 Web 界面和可观测性上有所投入,Modal 从来都不是Web 优先的。我们的起点始终是 SDK,因为我们押注于程序员。但 SDK 并非适用于所有工作,而这个产品是我们首次涉足客户端库之外的领域,是我们独立于其他部分的首个“新产品”。
这项工作最初只是一个单人原型,后来发展成了一个小团队的努力。贡献者包括:
- 工程: Eric Zhang、Howard Halim、Amit Prasad
- 产品设计: Sona Dolasia
- 产品反馈: Charles Frye、Michael Waskom、Luis Capelo、Thomas Fan
- 发布: Kenny Ning、Rebecka Storm、Ben Shababo、Margaret Shen
特别感谢我们在 Suno 等世界级公司的设计合作伙伴,他们从一开始就在使用 Notebooks。
来源:Modal Blog · modal.com