CubeSandbox JuiceFS 多节点性能基准测试报告
一、前言
本文测试 CubeSandbox 使用 JuiceFS 共享存储的生命周期性能,覆盖模板启动、快照、暂停与恢复,以及跨节点快照启动和暂停恢复。
重要说明:性能结果与硬件、网络、模板内容、JuiceFS 缓存、对象存储、Redis 延迟和沙箱负载高度相关。 本文数据用于描述本次部署的测试结果,不应直接视为其他环境的性能承诺。
二、测试环境
2.1 三节点硬件
三台节点均为腾讯云 PVM 云服务器,CPU 和数据盘规格一致;系统盘容量存在差异。
| 节点 | 角色 | CPU | 内存 | 系统盘 | 数据盘 |
|---|---|---|---|---|---|
| c1 | 控制节点 + 计算节点 + 存储服务 | 16 vCPU,AMD EPYC 9754 | 32 GiB(系统显示约 30 GiB) | 500 GiB XFS | 1 TiB XFS,挂载到 /data |
| c2 | 计算节点,测试源节点 | 16 vCPU,AMD EPYC 9754 | 32 GiB(系统显示约 30 GiB) | 500 GiB XFS | 1 TiB XFS,挂载到 /data |
| c3 | 计算节点,跨节点目标 | 16 vCPU,AMD EPYC 9754 | 32 GiB(系统显示约 30 GiB) | 100 GiB XFS | 1 TiB XFS,挂载到 /data |
三台节点的软件环境一致:
| 项目 | 配置 |
|---|---|
| OS | TencentOS Server 4.4 |
| 内核 | 6.6.69-opencloudos9.cubesandbox.pvm.host-g0de43d6b3bcd |
| CPU 拓扑 | 1 Socket × 16 Core × 1 Thread,1 个 NUMA 节点 |
| CubeSandbox 组件版本 | v0.7.3 安装包,使用本次测试分支构建的核心组件 |
| 测试日期 | 2026-10-28 |
2.2 部署拓扑
c1 同时运行 CubeSandbox 控制面和一个 Cubelet;c2、c3 作为计算节点连接 c1。本机测试和跨节点测试均从 c1 发起,通过 c1 的 CubeAPI 发出请求。
测试中的本机操作固定在 c2,跨节点操作固定为 c2 → c3。脚本通过 CubeAPI 的 distribution_scope 请求将沙箱调度到指定节点;控制面查询与节点隔离命令均直接在 c1 执行。
2.3 JuiceFS、Redis 与 MinIO
三台节点挂载同一个名为 cube 的 JuiceFS volume:
具体配置步骤见 JuiceFS 服务配置。
| 项目 | 配置 |
|---|---|
| JuiceFS 客户端 | juicedata/mount:ce-v1.4.1 |
| 挂载点 | /data/cubelet/jfs |
| 元数据引擎 | c1 上的 Redis 7,redis://c1:6380/0 |
| 对象存储 | c1 上的 MinIO,http://c1:9000/cube-jfs |
| 本地缓存目录 | /data/cubelet/jfs-cache |
| 单节点缓存上限 | 102400 MiB(100 GiB) |
| JuiceFS 回收站 | 1 天 |
三台节点使用相同挂载参数:
--no-usage-report
--cache-dir /data/cubelet/jfs-cache
--cache-size 102400
--prefetch 16
--max-fuse-io 1M
--cache-large-write
--writeback--writeback 允许脏数据先写入本地 staging,再异步上传 MinIO。测试因此分别记录 API 返回耗时和数据进入 remote_status=ready 的等待耗时。
2.4 沙箱与模板
| 项目 | 配置 |
|---|---|
| 后端 | JFS |
| 镜像 | cube-sandbox-cn.tencentcloudcr.com/cube-sandbox/sandbox-code:latest |
| 沙箱规格 | 2 vCPU / 2000 MiB |
| 可写层 | 1 GiB |
| 暴露端口 | 49999、49983 |
| 健康检查 | HTTP 49999 |
模板制作命令:
cubemastercli tpl create-from-image \
--image cube-sandbox-cn.tencentcloudcr.com/cube-sandbox/sandbox-code:latest \
--writable-layer-size 1G \
--expose-port 49999 \
--expose-port 49983 \
--probe 49999 \
--backend jfs记录模板 ID 用于后续测试
三、测试脚本与执行方法
3.1 测试脚本
本次使用仓库中的 tests/perf/cubebench_jfs_local.py 和 tests/perf/cubebench_jfs_cross_node.py。两者均直接在 c1 执行;后者通过 CubeAPI 请求跨节点调度,数据库查询和可选节点隔离均使用 c1 本机的 Docker/MySQL 与 cubeopscli。公共逻辑位于 tests/perf/jfs_bench_common.py。
3.2 SDK 与环境变量
在仓库根目录安装本地 Python SDK:
python3 -m venv /tmp/cube-perf-venv
source /tmp/cube-perf-venv/bin/activate
pip install -e ./sdk/python设置集群地址:
export CUBE_API_URL=http://<cubeapi-host>:3000
export CUBE_PROXY_NODE_IP=<cubeproxy-ip>
export CUBE_CONTROL_NODE=c1
export CUBE_NODES="c1=<c1-ip>,c2=<c2-ip>,c3=<c3-ip>"本机与跨节点测试均不要求 SSH:在 CUBE_CONTROL_NODE 上运行即可。CUBE_CONTROL_NODE 不能省略,因为脚本通过它标识本机 Docker/MySQL 和 cubeopscli 所在的控制节点。CUBE_NODES 不应包含已退出集群的节点,否则跨节点恢复在隔离或恢复节点调度状态时会失败。
3.3 完整测试命令
本机与跨节点结果分别写入独立 JSON。先在 c1 执行 c2 本机测试:
python3 tests/perf/cubebench_jfs_local.py \
<tpl-id> \
--section local \
--origin c2 \
--samples 10 \
--concurrency 1 5 10 \
--warmups 1 \
--round-gap 10 \
--label "$(date +%F), c2 local, bundled MinIO" \
--out /tmp/jfs-local-perf.json再在 c1 执行 c2 → c3 的跨节点测试:
python3 tests/perf/cubebench_jfs_cross_node.py \
<tpl-id> \
--backend jfs \
--section all \
--origin c2 \
--target c3 \
--samples 10 \
--concurrency 1 5 10 \
--warmups 1 \
--round-gap 10 \
--allow-node-isolation \
--label "$(date +%F), c2-to-c3, bundled MinIO" \
--out /tmp/jfs-cross-node-perf.json两个 JSON 可直接生成第 4.1–4.4 节的 Markdown 表格:
python3 tests/perf/cubebench_jfs_report.py \
/tmp/jfs-local-perf.json \
/tmp/jfs-cross-node-perf.json \
--out /tmp/jfs-perf-tables.md3.4 场景与测量口径
| 场景 | 测量方式 |
|---|---|
| 模板启动 | 从指定模板在 c2 创建沙箱,到 SDK 创建调用返回 |
| 快照制作 | 在 c2 创建沙箱,调用 create_snapshot 到 API 返回 |
| 快照就绪 | 快照 API 返回后,到 CubeMaster 数据库记录 remote_status=ready |
| 本机快照启动 | 复用一个已就绪快照,在 c2 创建沙箱 |
| 暂停 | 在 c2 调用 pause,到沙箱进入 paused |
| 暂停就绪 | pause 返回后,到暂停包 remote_status=ready |
| 本机恢复 | 在 c2 对 paused sandbox 调用 connect,到恢复完成 |
| 跨机首次快照启动 | 每个样本创建唯一新快照,再在 c3 第一次启动 |
| 跨机预热快照启动 | 复用同一个快照,多次在 c3 启动 |
| 跨机恢复 | 在 c2 暂停,临时隔离除 c3 外的节点,再恢复到 c3 |
每个场景分别测试 1、5、10 并发,每格保留 10 个有效样本。--warmups 1 表示正式采样前执行一个并发批次;fromsnap-cold 为保证每次使用唯一快照,脚本不执行 warmup。每个正式批次结束后等待 10 秒。
脚本测量每个 worker 自己的 API 调用和立即就绪等待时间;资源清理不计入指标。报告中的结果取每组 10 个有效样本的平均耗时。
四、测试结果
表格仅展示平均耗时(Avg),所有数值均以 ms 为单位。
4.1 模板启动与快照
| 指标 | 1 并发 | 5 并发 | 10 并发 |
|---|---|---|---|
| 从模板启动 | 157.7 ms | 231.0 ms | 352.4 ms |
| 快照制作 | 606.6 ms | 1210.0 ms | 1817.9 ms |
| 快照数据就绪 | 240.2 ms | 508.9 ms | 2635.4 ms |
| 快照制作到数据就绪总耗时 | 846.9 ms | 1718.9 ms | 4453.3 ms |
模板启动随并发度平滑增长。快照 API 在 10 并发下平均约 1.82 秒;等待 writeback 数据可安全跨节点读取还需要平均约 2.64 秒。
4.2 本机快照启动、暂停与恢复
| 指标 | 1 并发 | 5 并发 | 10 并发 |
|---|---|---|---|
| 本机从快照启动 | 162.3 ms | 381.8 ms | 350.7 ms |
| 暂停 | 623.3 ms | 1048.8 ms | 1602.8 ms |
| 暂停包数据就绪 | 239.4 ms | 808.6 ms | 2846.2 ms |
| 暂停到数据就绪总耗时 | 862.8 ms | 1857.5 ms | 4449.0 ms |
| 本机恢复 | 380.0 ms | 953.6 ms | 1473.5 ms |
暂停 API 返回只要求数据进入本地 staging;“暂停包数据就绪”继续等待相关 staging 块上传完成。高并发时,本机恢复和后台上传都会受到共享 FUSE、磁盘和对象存储队列影响。
4.3 跨节点快照启动
| 指标 | 1 并发 | 5 并发 | 10 并发 |
|---|---|---|---|
| c2→c3 首次启动 | 743.8 ms | 1073.6 ms | 1543.2 ms |
| c2→c3 预热启动 | 213.7 ms | 339.8 ms | 512.8 ms |
首次启动需要在 c3 读取此前未由该快照触发读取的数据;预热场景复用相同快照和缓存,因此明显更快。由于本轮未主动丢弃 c3 系统缓存,首次启动数据不等同于严格冷缓存结果。
4.4 跨节点暂停恢复
| 指标 | 1 并发 | 5 并发 | 10 并发 |
|---|---|---|---|
| c2 暂停 | 631.0 ms | 1077.2 ms | 1769.8 ms |
| 暂停包数据就绪 | 242.4 ms | 808.8 ms | 2804.7 ms |
| 暂停到数据就绪总耗时 | 873.3 ms | 1886.0 ms | 4574.4 ms |
| c3 恢复 | 907.7 ms | 1427.1 ms | 2416.7 ms |
10 个样本均以 c3 为调度目标完成恢复。跨节点恢复包含在 c3 建立目标节点私有对象、启动 VMM 和等待 guest 健康检查,不包含测试脚本执行节点隔离与恢复调度状态的时间。
五、结论与注意事项
- 模板启动具有良好的并发扩展性。 1/5/10 并发平均延迟分别为 158、231、352 ms。
- 快照和暂停分为 API 阶段与异步数据就绪阶段。 使用 writeback 时,API 返回不代表其他节点已经可以安全读取全部数据;跨节点消费前必须等待
remote_status=ready。 - 跨节点能力验证通过。 从 c2 制作的快照可以在 c3 启动,c2 暂停的沙箱也能在 c3 恢复,所有正式样本均成功落到目标节点。
- 缓存对跨节点启动影响明显。 10 并发首次启动平均约 1.54 秒,预热后约 0.51 秒;报告结果必须同时说明缓存口径。
- 高并发恢复存在进一步优化空间。 本机恢复 10 并发平均约 1.47 秒,跨节点恢复约 2.42 秒。建议继续拆分存储克隆、VMM restore 和 guest probe 的阶段耗时。
复现前请阅读 tests/perf/README.md 中的安全说明、参数限制和跨节点隔离行为。