☰
forkd 如何实现 56 毫秒 Live BRANCH:memfd + userfaultfd 写保护与写时复制原理深度剖析
2026/10/2 12:50:54 网站建设 项目流程

forkd 如何实现 56 毫秒 Live BRANCH:memfd + userfaultfd 写保护与写时复制原理深度剖析

【免费下载链接】forkd高性能Agent沙箱,预热虚拟机可以在约 100 毫秒内派生出 100 个独立实例;运行过程中约 150 毫秒“分叉”出一个新的运行环境。底层使用 KVM 隔离,并利用快照+写时复制降低资源开销。项目地址: https://gitcode.com/deeplethe/forkd

forkd 是一款高性能 Agent 沙箱工具,它用memfd 共享内存 + userfaultfd 写保护(UFFDIO_WRITEPROTECT)+ 写时复制(Copy-on-Write)三件套,把正在运行的虚拟机「分叉」出一个新分支的停机窗口压到了56 毫秒(p50),比传统 Diff 快照快 3.6 倍,比全量快照快 242 倍——而且这个数字与磁盘速度无关。本文带你从「为什么慢」讲起,拆解 forkd live BRANCH 的完整实现原理。

一、BRANCH 到底慢在哪:暂停窗口问题

对运行中的沙箱做快照分叉,最疼的不是「分叉出子实例要多久」,而是源虚拟机被暂停的时长(pause-window):暂停期间源沙箱的 TCP 连接、kvmclock 全部「卡住」,这是用户能直接感知的卡顿。

forkd 在 1.5 GiB 的 Python+numpy 源沙箱、机械硬盘(最差的存储条件)上测得四种模式:

模式暂停窗口 p50说明
full(全量写 memory.bin)13 550 ms被磁盘写速度锁死
diff(脏页快照)202 ms脏页写入仍发生在暂停窗口内
live(v0.4 写保护路径)56 ms内存拷贝移到恢复之后

完整数据与测试方法见 bench/live-fork-pause-window/RESULTS-v0.4.md,可用 bench-live-fork.py 复现。

关键洞察:full 和 diff 的耗时都绑死在磁盘上,而 live 模式的暂停窗口只由「vmstate 转储(约 30–50 ms)+ 写保护武装(约 0.4–0.6 ms)」决定,是与磁盘无关的 CPU 开销。存储越慢,live 的优势反而越大。

二、第一块拼图:memfd——把客户机内存变成共享内存对象

为什么不能直接对memory.bin文件做写保护?这里有一个内核层面的硬约束:

UFFDIO_WRITEPROTECT只支持匿名(anonymous)和共享内存(shmem)类型的 VMA,不支持任意文件映射。

所以 forkd 在创建源沙箱时(live_fork: true)就提前布局:用memfd_create(2)创建一个匿名文件,把快照的内存字节拷进去,再把/proc/<pid>/fd/<N>路径交给 Firecracker,让它以MAP_SHARED映射这个 memfd 作为客户机 RAM。这个设计的完整论证在 crates/forkd-vmm/src/memfd.rs 的模块注释里:

  • memfd 是 shmem inode,天然满足UFFD_WP 的 VMA 要求;
  • forkd-controller保留 memfd 句柄,就能 mmap同一批物理页——客户机写什么,控制器立刻看得见;
  • memfd 随 fd 关闭而消失,不需要清理磁盘残留文件。

memfd 创建与填充的核心逻辑见 create_and_populate,还支持 2 MiB 大页后端以缓解页表压力。MemoryBackend::MemfdShared枚举与Vm::request_wp_uffd握手接口定义在 crates/forkd-vmm/src/lib.rs;FC 侧需要mem_backend.shared = true,对应的上游提案见 FIRECRACKER-UPSTREAM-PROPOSAL.md。

三、第二块拼图:写保护 + 后台拷贝,把「抄家」挪出停机窗口

这是整个方案的灵魂。传统做法是「冻结 → 把整个内存写到磁盘 → 解冻」;live BRANCH 变成「短暂冻结 → 给内存上写保护锁 → 解冻 → 边跑边抄」。

以 crates/forkd-uffd/src/wp_snapshot.rs 中WpBranch的注释为蓝图,一次 BRANCH 的时间线是:

  1. 暂停源 VM(Firecracker 负责 pause);
  2. 武装写保护:对源 VM 的 memfd 区域执行UFFDIO_WRITEPROTECT,这就是整个 BRANCH 的临界区,每 GiB 不到 1 毫秒,见 WpBranch::begin;
  3. 在内存「对客冻结」状态下转储 vCPU + 设备状态(vmstate);
  4. 立即恢复源 VM 运行——暂停窗口到此结束,共约 56 ms;
  5. 恢复后两路并发跑内存拷贝:
    • 批量通道:bulk_copy_clean逐页读走仍然干净的页,见 bulk_copy_clean;
    • 故障通道:源 VM 一旦写某个页,内核立刻向 userfaultfd 报写故障,处理线程把写前的原始内容抄进快照文件,再对该页解除写保护放行写入,见 run_handler。

这条路径有一条严格的一致性不变量:快照文件里的每一页,都持有「写保护武装那一刻」客户机能读到的值。也就是说,分叉出来的分支拿到的是一份精确的时间点视图,而源沙箱则继续向前演化,互不干扰。Phase 1–3 的 PoC(experiments/v0.4-uffd-wp-poc/ 等)在 64 MiB / 256 MiB / 1 GiB 区域、含 KVM 客户机经 EPT 的真实写入下验证了0 次不变量违例。

跨进程细节值得一提:UFFDIO_REGISTER是按进程计的,而 KVM 跑在 Firecracker 里,所以 uffd 由 FC 进程创建,再经 SCM_RIGHTS 把 fd「快递」给控制器武装写保护——对应 begin_with_external_uffd。

四、第三块拼图:写时复制——N 个子实例为什么几乎不占内存

分叉出的子实例从快照恢复时,走的是 forkd 的老本行:所有子 VM 对memory.bin做mmap(MAP_PRIVATE),干净页由内核页缓存天然共享,只有被写脏的页才按子实例 CoW 复制。

这里有个容易踩的坑:为什么不干脆让子实例也走 UFFD 按需取页?因为 UFFD 的UFFDIO_COPY是拷贝语义——N 个子实例各拿各的私有副本,内核 CoW 共享直接没了,等于把 forkd 最核心的密度优势换掉。这个权衡的完整推导见 docs/design/userfaultfd.md。

五、56 毫秒是怎么量出来的

  • 硬件:i7-12700 + 30 GiB 内存 +机械硬盘(故意用最差存储,见 RESULTS-v0.4.md 的 Setup 与 Caveats);
  • 源码:POST /v1/sandboxes/<id>/branch带mode: "live",CLI 为forkd snapshot --from-sandbox <id> --live,SDK 见 sdk/python/forkd/controller.py;
  • 还有个隐藏大招:wait=false时 HTTP 请求在源 VM 恢复后就返回(p5069 ms),内存拷贝在后台跑完,status字段从writing翻到ready时快照即可消费——调用方根本不用等那 13 秒的落盘。

运行前提:Linux 内核 ≥ 5.7(UFFD_WP)、vm.unprivileged_userfaultfd=1或 root /CAP_SYS_PTRACE、带 memfd 共享补丁的 Firecracker(forkd doctor会自动探测,见 crates/forkd-cli/src/doctor.rs)。

六、这 56 毫秒意味着什么 🚀

对 Agent 场景来说,56 ms 的停机意味着「分叉」从一项昂贵的操作变成廉价到可以随手做的操作:

  • 破坏性操作前自动分支——rm -rf/apt remove之前先分叉,后悔即丢弃;
  • 投机执行——同一状态并行尝试多种策略,挑赢家;
  • 对话检查点——每 N 轮自动存档,第 47 轮跑偏就回到第 45 轮。

相关设计文档:docs/design/branching.md(分支语义与暂停窗口行为)、docs/design/userfaultfd.md(架构演进全记录)、DESIGN-v0.4.md 与 DESIGN-v0.4-PHASE6.md(v0.4 实现细节)。从 v0.2 的 ~13.5 s,到 v0.3.4 diff 快照的 ~200 ms,再到 v0.4 live 的56 ms,forkd 用三个版本把「分叉」打磨成了一个几乎免费的动词。

【免费下载链接】forkd高性能Agent沙箱,预热虚拟机可以在约 100 毫秒内派生出 100 个独立实例;运行过程中约 150 毫秒“分叉”出一个新的运行环境。底层使用 KVM 隔离,并利用快照+写时复制降低资源开销。项目地址: https://gitcode.com/deeplethe/forkd

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询