【论文阅读】DeepSeek Elastic Compute (DSec)! A Sandbox Infrastructure for Effective Agentic Training at Scale
团队:DeepSeek X 清华大学
背景
大模型的RL训练与评估依赖于隔离的、有状态的Sandbox执行环境,在这些环境中agent可以执行代码、调用命令、与外界服务交互等。这类工作负载的特点是创建突发、环境异构、多隔离需求、执行稀疏、有状态且长生命周期、镜像多样但复用有限、agent执行不可信、agent执行可中断。为满足其要求,DeepSeek构建了一个DSec即弹性计算平台,其统一通过SDK暴露了Function call、container、microVM、full VM这4种沙箱后端。
Sandbox 工作负载特点
Sandbox创建突发,单作业最高可请求32k sandbox
Sandbox环境多样
Sandbox执行稀疏,大部分就使用5%申请的资源,需要高密部署
Sandbox镜像制品海量但复用度低
Sandbox内的agent执行不可信,可能会通过读取日志、联网搜索等方式获取答案,也可能自行操作导致Sandbox崩溃
GPU被抢占时,Sandbox内的agent执行需要可中断
DSec 解决方案
系统核心组件可横向拓展,引入云服务缓解突发请求
基础镜像 X 代码仓库 X harness工具组合叠加的方式
Sandbox做延迟敏感和尽力而为类型划分来指导CPU隔离,内存依赖带 DAX 的 virtio-pmem 减少重复缓存页、再通过FPR进行主动空闲内存上报
镜像使用3FS存储管理,并依赖EROFS进行按需拉取
使用 AppArmor 建立对进程的对象级访问控制,并支持细粒度的网络访问控制。此外加强可观测性
GPU被抢占时RL框架通过主动调用pause接口来暂停Sandbox,并支持透明恢复
DSec单个集群规模约160个节点,一天服务300w个sandbox,并发可达到38万个sandbox,并可持续达到每秒超过 5000 次sandbox创建。
160 个节点组成的单个集群约为 30k 核、250 TB 内存。在 38 万个 Sandbox 并发的情况下,平均每个 Sandbox 实际分摊约 0.079 核 CPU 和 0.66 GB 内存。假设每个 Sandbox 原始资源规格为 2C16G,则 CPU 和内存的超卖比例分别约为 25.3 倍和 24.3 倍,整体可近似认为达到 25 倍资源超卖。
设计与实现
用户视角使用
用户使用时需要自行指定沙箱后端,并传递所需要的镜像、资源、ttl、网络、初始用户等信息,如下是一个简单的container sandbox创建与使用示例。
1 | |
用户在选择不同后端的时候主要考虑如下的内容,对于容器和microVM,对每个任务用户往往需要传递基础镜像+代码仓库及依赖+工具(如DeepSeek Harness),对于VM往往是快照或者镜像,对于FnCall,其需要包含任务类型、依赖文件以及待运行代码或脚本的任务说明。整体来看是容器和microVM占资源消耗大头,FnCall 以一小部分常驻环境服务大量轻量调用,VM服务特殊负载如安卓、GUI操作系统等。

其中GPU FnCall 通过 MIG 提供性能隔离,通过 CPU/GPU 执行解耦把编译移出 GPU 路径,再通过预热 Python 进程消除运行时初始化开销,从而最大化 GPU 用于实际算子执行的时间;对单纯验证正确性性能不敏感任务则进一步提供共享 GPU模式,以换取更高并发。
平台架构
整体架构如下:

整体流程为:
训练作业使用sdk发起创建请求,请求被发送给IAM
IAM做身份认证与资源额度管理(这里使用的也是父子项目的quota管理),校验通过后发给Placement Engine
Placement Engine依赖Watcher的视图经过过滤与有限排序( power-of-k-choices )调度到合适的负载较低的节点,这里应该将调度的节点信息补充到了Sandbox id上,Placement Engine与Watcher不使用持久化数据库,而是通过重新遍历节点来获取到集群全局的状态
API Server依据sandbox id信息将请求转发给对应节点的Edge组件,也不持有持久化数据
Edge组件会检查本地容量来做准入判断,主要是兜底处理状态陈旧导致的调度偏差,通过后启动sandbox,在启动过程中,相关的数据会从3FS中按需拉取,并且Edge会负责管理Sandbox的生命周期、协调磁盘与内存快照
容器、microVM 和完整虚拟机Sandbox都对应一个运行时代理aether,对于容器通过Unix socket,虚拟机通过vsock与外部的Edge通信,若通信中断,则可认为 sandbox 被销毁。一个shell请求对应一个 chronus实例,同时可以有多个shell,chronus用于命令执行、文件系统访问和其他运行时操作。这类沙箱运行起来之后,其操作经由 apiserver、edge、aether和 chronus路由。而FnCall 既不使用 aether也不使用 chronus,并走单独的请求路径:提交的任务直接在预先创建的容器中执行,随后尽力清理任务状态。
此外为了应对突发的调度当本地利用率超过 80% 时,placement engine将一部分符合条件的入站沙箱创建请求卸载到云虚拟机。不过云上没有用对象存储,EROFS 镜像被存放在云上托管的分布式文件系统中,并由云虚拟机挂载。并且生产环境的文件访问轨迹表明,一套合计 30 TB、经过去重的紧凑 EROFS 镜像集,覆盖了 70% 容器任务所访问的镜像文件。在生产中,一个规模单元内的 200 台云虚拟机吸收了 ∼30% 的峰值溢出,从而在不过度配置本地集群的情况下提高容量。
Sandbox负载挑战与平台机制
本节只报告 Container 与 microVM 的测量结果,二者合计占生产中大部分沙箱实例和资源消耗。
生命周期与突发需求
大部分任务请求的sandbox数量可达上千,最高可到32k。并且这些请求都是短时间内到达
现在有可能会更大

Sandbox的负载特征如下,前期环境准备,而后周期性地等待与工具调用,后期验证可能会进一步抬高负载。整体看来CPU是突发的,而内存是长期占用的。

环境多样性与准备压力
沙箱内容可以分解为三部分:提供操作系统级依赖的base image(例如 Ubuntu、Python 3.10 或 Java 8 环境),携带任务代码仓库及其特定依赖的workspace,以及一个或多个频繁更新的toolkits(例如 DeepSeek Harness)。
由于变更迅速,所以以组合粒度来打镜像会产生海量镜像,故而其平台做法是采用分开管理并独立进行版本演化,在实际创建时通过挂载来组合,而这在容器运行时dockerd方面是通过overlayfs栈来解决的,对于microVM是以块设备叠加根文件系统使用overlayfs层来解决的。

稀疏利用与高密度执行
大部分Container Sandbox都只使用到了不到5%的资源,而microVM大部分也都只使用了不到40%的请求资源,其天然适合高密部署

就内存而言,microVM 有两类浪费。
经由虚拟块设备读取的镜像数据可能被宿主机缓存一次,又被每个客户机再缓存一次,使同一数据在客户机与宿主机两侧被冗余缓存。
若没有显式上报,客户机内部的空闲页不会归还给宿主机。由于请求的内存容量往往超过实际需求,客户机几乎没有内部压力去回收不活跃的页。这些沙箱也是长生命周期的:容器的中位生命周期为 17.4 分钟,microVM 为 15.5 分钟,两种后端的 p99 均超过三小时。漫长的生命周期放大了滞留内存的代价。这些效应共同制约了 microVM 的内存超额分配,在沙箱密度很高时尤其如此。

高密部署在内存方面:
为了解决内存中的页重复问题,其只读层用 DAX + virtio-pmem 把文件访问直接映射到宿主机支持的页、而不把它们复制进客户机 RAM,使同驻的 microVM 可以共享同一份宿主机页缓存。
为了解决内存长期驻留问题,其在可写层用DAMON 识别长期未访问的冷文件页,并主动回收。被释放的 4 KiB 页进入 buddy allocator 后逐步合并成较大块。virtio-balloon 再通过 free page reporting 将这些空闲区域通知宿主机,由宿主机
MADV_DONTNEED真正释放物理内存。
高密部署在CPU方面:
DSec将Sandbox分为延迟敏感(LS)和尽力而为(BE)两类。
在逻辑核隔离方面,通过将BE Sandbox设置为
SCHED_IDLE来让出CPU的时间片给LS Sandbox在物理核隔离方面,因为现代CPU架构往往是1个物理核对应2个逻辑核,同一个物理核的两个逻辑核会相互干扰,所以其采用了Core Scheduling策略,当某个物理核的一个逻辑核正在运行 LS 任务时,避免让不兼容的 BE 任务同时运行在它的 sibling 逻辑核上,从而减少 SMT 资源争用。
最终做到了单节点峰值可达到 1048 个容器和 524 个 microVM。在整个生产环境中观察到单节点至少 3200 个容器或 800 个 microVM 的稳定运行。

庞大的镜像工作集与低复用
一个周内活跃的制品合计占用超过 130 TB,远超单个节点所能存储的容量。
容器镜像的复用中位数为 3、p90 为 28
microVM 镜像的复用中位数为 1、p90 为 3。
这种低复用率导致本地镜像缓存利用率很差,当一批沙箱创建请求突发到达时,拉取镜像变得不可避免,并给镜像分发基础设施带来很大压力。

由于高密部署导致集群接近饱和,直接拉取并解压镜像会消耗节点的CPU与I/O资源。而如下所示,不同编程语言的镜像访问的数据是不一样的,但是都很少,完全不需要全量拉取。

DSec为了复用基础设施选择将镜像服务托管在3FS上,但是3FS对大块顺序读写能维持高吞吐,但在小块随机 I/O 上表现很差,所以其做了一些针对性优化,
写入直接留本地,避免小写入惩罚
读取按需从3FS获取并且 I/O 以成批方式执行
元数据尽量留在本地文件系统。元数据常常通过小块读取访问。当镜像格式允许时,我们把元数据与数据分离,并把元数据预取到本地节点。
对容器而言,EROFS 有助于实现这些设计原则,因为EROFS本地就是严格只读+支持按需加载+多设备支持元数据与文件数据分离。并且进一步的其还离线地把大小处于阈值之内(例如 3 GB)的连续层折叠成一对分别存放元数据和数据的 EROFS 镜像,从而减少挂载次数减少开销。
而microVM 则利用 EROFS + OverlayBD + ublk 提供兼容 ext4 的可写块设备和增量快照,从而避免完整镜像拉取,并把 3FS 的访问模式尽量转换成其擅长的大块 I/O。注意采用这个方案的一个原因是Firecracker不支持virtio-fs。
与RL框架的协同优化
运行智能体自己通过磁盘快照的方式制作一个新Sandbox来出题。并且还构建了一个出题规则以及出题环境检查标准。
将agent rollout与rl框架解耦,agent直接放到sandbox中做,并配备一个worker容器来管理该sandbox,并且都放在GPU池外。
当训练任务被抢占时,RL框架主动向相关sandbox发送pause请求来回收资源,对容器和 microVM,随后发往已暂停沙箱的任何请求,都会在执行所请求的操作之前透明地恢复它。对于容器类型edge会发出 docker pause,冻结容器的进程树然后启用内存回收,对于microVM,其会进行全量快照,然后终止正在运行的 Firecracker 进程以释放该 microVM 的运行时内存。
agent还有可能经由非预期渠道获取答案,例如通过 socket 发送RPC伪造用户请求,检查 chronus日志以寻找泄漏的答案,试图覆盖 /bin/bash,利用 Go 模块代理获取托管在 GitHub 上的代码等。
其使用 AppArmor 建立对象级访问控制,即使进程在 Sandbox 内以 root 身份运行,也只能访问策略允许的文件和 Unix domain socket,从而阻止其读取 chronus 日志中的敏感残留信息,或通过内部 IPC 接口伪造用户请求。
其还进行了细粒度网络控制,训练框架按域名或镜像服务组织、指定特定于任务的网络权限。例如,允许访问 PyPI,同时拒绝访问 NPM。DSec 通过按沙箱部署的 eBPF 程序强制执行相应的允许列表,按 IP 地址、端口和协议过滤流量,拒绝允许列表之外的流量。当任务在连通性要求不同的阶段之间移动时,这些策略可以动态更新。
agent在执行过程中可能会导致sandbox崩溃,在一个案例中,智能体从根目录递归运行 grep,遍历 /proc,并读取 /proc/kpagecgroup,触发了一个使内核崩溃的内核缺陷。目前还没有单一机制能够防止全部智能体不当行为和系统故障。因此我们加强可观测性以识别新出现的问题,并随着模型演化持续加固 DSec。
实验
实验在10个节点组成的集群上进行(裸金属规格是2 sockets × 96 cores × 2 SMT threads,虚拟机规格是1 socket × 96 cores × 2 SMT )
镜像实验
将EROFS 镜像按需拉取与全量拉取Docker(cold)、全量本地缓存Docker(cached)对比。
EROFS 镜像按需拉取基本打平Docker(cached)的拉取速度,比全量拉取快1.71倍,在磁盘读写方面因为按需拉取比Docker(cold)少接近一半。

此外还对比了通过tar解压仓库和工具、只读镜像挂载这两种方式,明显只读镜像挂载的表现更好。

高密部署
在内存方面,其在测试集群上运行真实的智能体 RL 负载,并比较四种 Firecracker 配置:未优化的基线、仅带 DAX 的 virtio-pmem、仅经由 virtio-balloon 设备的基于 DAMON 的空闲页上报(FPR),以及两种机制的组合。结果如下:
- 带 DAX 的 virtio-pmem 把每个客户机冗余的页缓存折叠为单一共享的宿主机映射,与基线相比将峰值宿主机内存用量降低 40.2%。单独的 DAMON + balloon FPR 基本不改变峰值用量,但把按时间积分的宿主机内存消耗降低 21.2%。两种机制结合产生最低的总体内存消耗。

在CPU方面,其将来自真实评估负载的延迟敏感(LS)任务(国际象棋应用),与占节点容量 10% 到 50% 的同驻尽力而为(BE)负载一起运行,其比较无保护基线、单独的 SCHED_IDLE,以及 SCHED_IDLE与核心调度的组合。结果如下:
50% 的 BE 负载下,若没有 QoS 控制,其每步延迟相对无同驻基线增加 45.2%。单独的
SCHED_IDLE最多只将延迟改善 3.4%,因为 LS 线程仍可能与跑在其 SMT 兄弟线程上的 BE 工作争用。加入核心调度后,低负载下延迟接近无同驻基线,在 50% 负载下把膨胀限制在 17.3%。改善幅度随 BE 争用增加而增大。剩余的性能下降主要来自高多核负载下 CPU 睿频降低,以及核心调度并不处理的内存带宽和共享末级缓存(LLC)争用。
