如何看懂 AgentENV 系统架构全景图:从 API 到 Firecracker 微虚拟机的完整数据流
【免费下载链接】AgentENVAgentENV (AENV) is a distributed platform for running agent environments at scale.项目地址: https://gitcode.com/gh_mirrors/age/AgentENV
AgentENV(AENV)是一个用于大规模运行 Agent 环境的分布式平台。本文带你从一张全景图出发,完整走通一个 HTTP 请求如何穿透 API 层、编排器,最终变成一台运行中的 Firecracker 微虚拟机(microVM),并解释快照、ublk 块设备与分布式控制平面在其中扮演的角色——这是理解 AgentENV 系统架构最快的路径。
一、30 秒看懂 AgentENV 系统架构全景
AgentENV 的核心目标只有一个:让 AI Agent 能跑在隔离、可快照、可秒级恢复的 Firecracker microVM 里,并且能在集群中水平扩展。
整个系统分两大平面:
| 平面 | 组成 | 职责 |
|---|---|---|
| 单节点平面(Rust 编写) | API Server + Orchestrator + Firecracker + 存储子系统 | 管理沙箱生命周期、块设备、网络、快照 |
| 分布式控制平面(Go 编写) | Gateway + Scheduler | 多节点间的路由与节点选择 |
官方架构文档对这一全景有权威定义:
AgentENV 在隔离的、支持快照的 Firecracker microVM 中运行 AI Agent。其核心是一个存储子系统,提供可挂载进虚拟机的分层块设备,以及基于 ublk 的内存快照恢复。每个节点还有一个编排器管理沙箱生命周期,以及一个分布式控制平面(Gateway + Scheduler)负责多节点路由。
完整原文见 architecture.md。
二、核心组件地图:7 个关键模块与源码位置
下面这张表把全景图上的每个方块映射到了源码目录,方便你边读边对照代码:
| 组件 | 源码位置 | 一句话职责 |
|---|---|---|
| API Server | src/api/ | 暴露 E2B 兼容的 HTTP API 与反向代理入口 |
| Orchestrator 编排器 | src/orchestrator/ | 沙箱生命周期状态机、持久化与自动清理 |
| Firecracker 运行时 | src/sandbox/firecracker/ | 创建并控制每个沙箱的 microVM |
| overlaybd 存储 | storage/overlaybd/ | 基于 LSMT 的分层镜像,根文件系统层栈 |
| ublk 块设备 | storage/ublk/ | 用户态块设备服务,把镜像暴露为/dev/ublkbN |
| 快照管理器 | src/snapshot/ | 提交、解析、删除持久化快照 |
| 模板构建器 | src/template/ | 构建用户模板并发布其提交后的快照 |
📌 一个值得注意的设计:存储 I/O 的"重活"被隔离在独立守护进程uvm-ublk-daemon(storage/ublk-daemon/)里,通过 Unix 域套接字 RPC 与节点主进程通信。这样 io_uring 控制与设备生命周期集中在一个进程,而节点服务器只负责编排状态,互不拖累。
三、完整数据流:一个创建沙箱请求的旅程
我们以POST /sandboxes(E2B 兼容接口)为例,追踪请求在节点内的完整路径。
第 1 站:API 层(Axum HTTP 服务器)
请求首先到达由 Axum 构建的 HTTP 服务器。在 server.rs 中可以看到路由装配顺序:先挂载生成的控制面 API 路由,再合并手写的/proxy/*反向代理入口、镜像构建路由与/metrics,最后叠加沙箱代理分类中间件和API Key 鉴权中间件。
鉴权在这里完成:所有控制面请求必须携带部署级
X-API-Key。数据面流量(进入沙箱内部的请求)则由沙箱自身的凭证校验,两条路径严格分离。
第 2 站:编排器(生命周期状态机)
API 层验证请求后,交给编排器驱动状态转换。沙箱状态机定义了 8 个状态,定义在 types.rs:
Creating → Running → Pausing → Paused → Resuming → Running ↓ Killing编排器同时负责三件事:
- 持久化:沙箱元数据写入存储,节点重启后 Paused 沙箱依然可恢复
- 自动驱逐:超时的沙箱被自动清理,释放 CPU 与内存
- 增量指标:运行中沙箱数、已分配 CPU/内存等计数器随生命周期事件实时更新
第 3 站:Firecracker microVM 启动
编排器调用 Firecracker 后端(sandbox.rs)完成三件关键装配:
- 分配网络插槽:从网络插槽池取一个预热好的 network namespace(含 veth + TAP),避免冷启动时的命名空间创建开销
- 挂载块设备:通过 ublk 守护进程创建 overlaybd 块设备作为根文件系统
/dev/vda,额外数据盘挂为/dev/vdb - 启动 microVM:通过 Firecracker API socket 配置 CPU、内存、boot source 并触发启动
第 4 站:存储子系统——真正的性能核心 🔥
这是 AgentENV 架构中最精妙的部分。虚拟机看到的"磁盘"其实是一个分层镜像栈:
/dev/vda ← /dev/ublkbN(用户态 ublk 块设备) ↓ overlaybd 层栈 ├── upper(可读写层,最新写入) ├── layer N … layer 2(只读压缩层) └── layer 0(基础镜像层)读路径:ImageFile 从顶层向下查找段索引,第一个包含该块映射的层提供服务数据;写路径:所有写入只追加到顶部可写层,底层只读层永远不被修改。
块设备怎么来的?Linux 内核 ublk 驱动 + 用户态服务(storage/ublk/src/ctrl.rs):
- 用户态通过 io_uring 向
/dev/ublk-control发送ADD命令 - 内核分配设备 ID,创建
/dev/ublkcN(控制)与/dev/ublkbN(块设备) - 每个队列一个 worker 线程,异步处理内核分发的 I/O
- 虚拟机把它当作普通磁盘读写,零额外系统调用开销
分层镜像的三大好处:
- 🚀按需加载:OCI 镜像层可从 registry/OSS 远程拉取,本地磁盘只作有界缓存,集群镜像总量可超出本地磁盘容量数个数量级
- ⚡写时复制:同一模板启动的多个沙箱共享全部只读层,只有 upper 层独立
- 📦快照即分层:暂停时上层被"封存"为新的只读层(
create_snapshot_and_restack),再开一个全新 upper,整个过程不拷贝数据
四、快照数据流:为什么暂停 <100ms、恢复 <50ms
暂停(Pause)的完整数据流
aenv pause <id> → API: POST /sandboxes/{id}/pause → Orchestrator: Running → Pausing → Firecracker 创建 state-only diff 快照 → 查询脏内存区间,用 process_vm_readv 读取选中内存 → 直接生成 overlaybd 内存层(叠加在历史快照层之上) → 封存文件系统 upper 层 → SnapshotManager 提交到仓库(S3 兼容对象存储 / 分布式文件系统) → Orchestrator: Paused(元数据持久化)内存与文件系统都走增量 diff:只记录自上次快照以来变化的部分,因此即使磁盘被大量修改,暂停也能在 100ms 内完成。核心提交逻辑见 manager.rs。
恢复(Resume)的完整数据流
恢复路径是快照架构的精华所在:
- 从快照仓库解析出层栈(固定产物会先尝试 P2P向同集群其他节点要,命中不了才回源对象存储)
- 从分层内存镜像创建一个只读 ublk 块设备,作为 Firecracker 的
BackendType::File内存后端 - Firecracker 对块设备做 mmap,首次写入时 COW(写时复制)到匿名内存——底层设备永不被修改
- 同一快照恢复的多个沙箱引用计数共享同一个内存 ublk 设备,Linux 页缓存在它们之间复用,并发冷启动 I/O 大幅下降
💡 传统 userfaultfd 缺页填充方案被 ublk 方案取代:块设备 + 页缓存天然享受内核缓存,无需用户态缺页处理线程。旧实现仍保留在 storage/uffd-core/ 供参考。
五、网络数据流:每个沙箱一个隔离命名空间
每个运行中的沙箱拥有专用 Linux 网络命名空间,Firecracker 通过 TAP 设备接入,命名空间通过 veth 对连到宿主机。拓扑与报文路径详见 networking.md。
关键机制一览:
- 地址规划:由插槽索引派生宿主机交互 IP、veth
/31链路地址、VM 固定链路地址,内部地址池在用户放行规则之前被整体拒绝,沙箱之间完全隔离 - 透明出口代理:需要域名策略时,命名空间内 TCP 80/443 被 REDIRECT 到本地代理(egress_proxy.rs),代理解析 SNI/Host 后查可信 DNS,策略失败即关闭(fail-closed)
- 策略热替换:
iptables-restore批处理原子替换命名空间规则链,存量连接不受影响 - 网络预热池:
(network slot, Firecracker 进程)对可以预先创建,恢复路径直接"移交",跳过 spawn 与 socket 等待
六、分布式控制平面:Gateway 与 Scheduler 如何协作
多节点部署时,客户端只面对一个 Gateway。数据流如下:
Client ──HTTP──> Gateway(:8080) ├─ 新沙箱 → gRPC Schedule() 选节点 ├─ 已有沙箱 → gRPC LookupNode() 查绑定 └─ 创建成功后 → RecordAssignment() 播种沙箱→节点绑定 ↓ 反向代理 HTTP Node A / Node B (:8000)- Gateway(services/gateway/):HTTP 反向代理。从路由头(
x-agentenv-sandbox-id/e2b-sandbox-id)或基于 Host 的代理域名({port}-{sandboxID}.{domain})提取数据面路由;控制面路由(如 pause)按 URL 路径中的沙箱 ID 路由。它还聚合GET /sandboxes、GET /nodes等跨节点列表请求 - Scheduler(services/scheduler/):gRPC 服务,维护内存中的沙箱→节点绑定表。RPC 包括
Schedule、LookupNode、RecordAssignment、Heartbeat等,契约见 scheduler.proto。调度策略支持round_robin(默认)与random - 绑定生命周期:运行时节点心跳携带完整沙箱 ID 清单,调度器将其视为事实来源,心跳中缺失的绑定会被清除;节点下线时
UnregisterNode主动清理其名下绑定 - 节点发现:支持
static(配置显式列表)与kubernetes(watch EndpointSlice,取就绪 DaemonSet Pod IP)两种模式
⚠️ 一个诚实的设计取舍:所有绑定都在内存中,Scheduler 重启后绑定丢失,但会通过"新沙箱创建 + 各节点下一次心跳清单"自动重建。
可选加速层——P2P 制品传输(src/p2p/):快照提交成功后,固定 Firecracker 产物与 overlaybd 层会经 P2P 层尽力广播;解析时先问 P2P 再问对象存储,让制品在集群内自然扩散。调度器只存/返透明的 peer 端点,真正的目录查询与字节传输全部走节点直连。
七、架构全景速查:源码目录对照表
| 目录 | 内容 |
|---|---|
| src/api/ | HTTP API 层(E2B 兼容端点 + 反向代理) |
| src/orchestrator/ | 沙箱生命周期状态机与持久化 |
| src/sandbox/ | Firecracker 管理、网络命名空间、ublk 集成 |
| src/snapshot/ | 快照仓库后端、运行时解析、P2P 发布 |
| src/template/ | 用户模板构建器 |
| storage/overlaybd/ | LSMT 分层镜像核心(本地/registry/tar 后端) |
| storage/ublk/ + storage/ublk-daemon/ | 用户态块设备与守护进程 |
| services/gateway/ + services/scheduler/ | 分布式控制平面(Go) |
📖 延伸阅读(仓库内官方文档):
- 架构总览:docs/src/internals/architecture.md
- 沙箱网络:docs/src/internals/networking.md
- 反向代理设计:docs/src/internals/proxy-design.md
- P2P 设计:docs/src/internals/p2p-design.md
- 控制平面服务:docs/src/internals/services.md
八、总结:AgentENV 架构设计的三个关键洞察
- 存储即架构:AgentENV 的性能故事完全由存储子系统书写——overlaybd 分层镜像让"镜像仓库"变成集群级无限缓存,ublk 让块 I/O 停留在用户态却享受内核级效率
- 快照 = 分层 + 写时复制:文件系统快照是"封存上层",内存快照是"只读块设备 + COW",两者都不做全量拷贝,这才有了暂停 <100ms、恢复 <50ms 的硬指标
- 平面分离、进程隔离:API 编排、块 I/O、分布式路由分属不同进程(乃至不同语言栈),每个平面只对自己的延迟敏感路径负责,互不拖累
理解了这个"API → Orchestrator → Firecracker → ublk → overlaybd"的数据流主链,你就掌握了 AgentENV 系统架构的骨架——无论是排查一次慢启动,还是评估如何扩展集群,都能从这张全景图快速定位到正确的模块。
【免费下载链接】AgentENVAgentENV (AENV) is a distributed platform for running agent environments at scale.项目地址: https://gitcode.com/gh_mirrors/age/AgentENV
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考