---
title: DSec 深潜:从 create() 到沙盒跑起来
subtitle: 四条路径 · 事实核查 · 实现细节
source: arXiv 2609.22978v1 精读
theme: auto
template: sheet
---
这一页把论文第 3、5、6、7 节串成四条路径:控制、数据、内存、抢占。每条路径都标了出处,并把论文事实与解读推断分开。
## 事实核查:转述 vs 论文
逐条对照 arXiv:2609.22978,多数说法准确,个别需要修正。
| 说法 | 判定 | 论文口径 |
| --- | --- | --- |
| 生产规模:约 160 节点、30K 核、250 TB、380K 并发、5K 每秒、3M 每天 | ok | §2.4;指每个规模单元,多个单元共享同一套 3FS |
| CPU 超卖超过 50 倍 | warn | 论文未给该数字;只给九成沙盒 ≤5% 与单节点密度 |
| 容器直接跑在宿主机 | warn | 容器与 FnCall 跑在 QEMU/libvirt 虚拟机内,多一层隔离 |
| 四种后端;FnCall 复用预建容器 | ok | §2.2;FnCall 不走 aether 与 chronus |
| EROFS 元数据本地、数据在 3FS、写留本地 | ok | §5.3;另有层折叠与 file-backed mount |
| OverlayBD 与 ublk 存储已开源 | ok | §7;Rust 版在 AgentENV 仓库 |
| Rollout 解耦与 pause/resume | ok | §6.2、§6.3 |
| 评测未验证模型能力提升 | ok | §8 只评四个基础设施机制 |
## 一次 create 请求的全景
信任侧与不可信侧只有一条通道:apiserver。
```flow LR
(libdsec) -> IAM: 鉴权与配额
IAM -> Placement: 批准后选节点
Placement -> Watcher: 拉取健康与负载快照
Placement -> apiserver: 返回目标节点
apiserver -> edge: 转发,沙盒 ID 含 owner edge
edge -> (容器 / 微虚拟机 / Full VM): 启动运行时
edge -> aether -> chronus: 会话与命令通道
- apiserver 不保存沙盒状态,任意实例可直接路由。
- placement 先按能力过滤,再在随机样本里选最闲节点。
- edge 做本地容量终审,拒绝时由上层改选。
- FnCall 走旁路,不经过 aether 与 chronus。
## Path A 控制路径
participants: libdsec, IAM, Placement, Watcher, apiserver, edge, aether, chronus
== 创建 ==
libdsec -> IAM: create 请求
IAM --> libdsec: 鉴权与配额通过
libdsec -> apiserver: 创建沙盒
apiserver -> Placement: 请求选节点
Placement -> Watcher: 集群快照
Placement --> apiserver: 目标 edge
apiserver -> edge: 转发创建请求
edge -> edge: 本地容量终审
edge -> aether: 启动代理
aether -> chronus: 建立 shell 会话
edge --> libdsec: sandbox ready
== 运行 ==
libdsec -> apiserver: run_shell
apiserver -> edge: 按 ID 直接路由
edge -> aether: Unix socket 或 vsock
aether -> chronus: 定位或新建会话
chronus --> aether: stdout 与退出码
aether 是每沙盒代理;chronus 是每会话 shell 抽象,可并发多个。
## Path B 数据路径
3FS 擅长大的顺序 I/O,弱于小的随机 I/O。读写分工由此决定。
group 容器路径: 容器运行时, OverlayFS 组合, 本地元数据
(容器运行时) -> OverlayFS 组合: lower 为 EROFS 只读层
OverlayFS 组合 -> 本地元数据: 启动前预取
OverlayFS 组合 -> [(3FS 数据)]: 按需批量读
group 微虚拟机路径: 微虚拟机运行时, ublk 块设备, 本地二级缓存
(微虚拟机运行时) -> ublk 块设备: OverlayBD 可写 ext4
ublk 块设备 -> [(3FS 数据)]: 256 KiB 块按需读
ublk 块设备 -> 本地二级缓存: 页缓存淘汰后兜底
| 原则 | 做法 |
| --- | --- |
| 写留本地 | 可写层放节点本地盘,避开 3FS 的小写惩罚 |
| 读按需且批量 | 只读数据按需读,内核预读合并成大请求 |
| 元数据留本地 | EROFS 多设备模式分离元数据与数据 |
- 相邻层合计不超过约 3 GB 时离线折叠成一对镜像,保留 whiteout 语义。
- 容器侧用 file-backed mount,去掉 loop 设备映射层。
- 微虚拟机侧:EROFS 只读层加 OverlayBD 可写盘,经 ublk 暴露给 guest。
## Path C 内存路径
微虚拟机有两类内存浪费:宿页缓存重复、guest 空闲页不归还。
(guest 读只读层) -> virtio-pmem 与 DAX: 直接映射宿主页
virtio-pmem 与 DAX -> 宿主页缓存: 多个微虚拟机共享一份
(guest 冷页) -> DAMON: 采样识别冷页
DAMON -> buddy 分配器: 走内核回收路径
buddy 分配器 -> balloon 空闲页报告: 报告中释放页
balloon 空闲页报告 -> 宿主: MADV_DONTNEED 释放内存
| 机制 | 效果 | 代价与边界 |
| --- | --- | --- |
| virtio-pmem + DAX | 峰值宿主内存下降 40.2% | 冷访问同步缺页;guest 元数据约为容量 1/64 |
| DAMON + balloon 空闲页报告 | 时间累计内存下降 21.2% | 单独使用峰值内存基本不变 |
| 两者组合 | 总体内存消耗最低 | 峰值 CPU 从 26.5% 升到 41.4% |
生产配置:只读 EROFS 层用 DAX,较大的可写盘用 DAMON 与空闲页报告。
## Path D 抢占路径
participants: RL 框架, DSec edge, 容器, 微虚拟机
== 抢占:暂停该任务全部沙盒 ==
RL 框架 -> DSec edge: pause 请求
DSec edge -> 容器: docker pause + 回收内存
DSec edge -> 微虚拟机: 保存快照并终止 Firecracker 进程
note DSec edge: 内存被回收,执行状态保留
== 恢复:下一次请求即透明恢复 ==
RL 框架 -> DSec edge: 新请求
DSec edge -> 容器: MADV_WILLNEED 预取 + unpause
DSec edge -> 微虚拟机: 新进程恢复快照
DSec edge --> RL 框架: 从断点继续,无需重放命令日志
- 状态真源是 worker container 与 agent sandbox,两者都在可抢占 GPU 池外。
- 旧方案要在恢复时重放命令日志,避免非幂等命令的重复副作用。
## 实现细节速览
* 放置策略: power-of-k + 本地在途视图 + edge 终审;用户隔离限制爆炸半径
* dockerd 改动: 动态插入 EROFS 下层,约 30 行 Go;相邻层可折叠
* 微虚拟机存储: Rust 版 OverlayBD 与 ublk 库,支持 3FS、OSS、registry
* 3FS 硬件: 每台存储服务器 20 × 15 TB SSD 与 2 × 400 Gbps RDMA
* GPU FnCall: MIG 分区 + CPU 编译转发 + 预热进程池
* 内核: 宿主 Linux 7.0、guest Linux 6.1,全部使用现有机制
## 下一站:你来选
下一站先拆哪条路径?
* 数据路径 | EROFS、3FS、OverlayBD 的完整读写分工
- 控制路径 | 从 create 到 ready 的每个 RPC 与进程
- 内存路径 | DAX、FPR、QoS 的调参与边界
- 抢占路径 | pause/resume 的状态一致性
`