Files
SerpMax/docs/01_CRIU_BROWSER_SNAPSHOT.md

484 lines
25 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# ProfileMax:基于 CRIU 的 Chromium 浏览器快照实现方案
- 文档类型:实现方案 / PoC 计划
- 状态:已验证(2026-10-20 本机 PoC + node 端到端集成测试通过,实测数据见第 12 节)
- 目标路径:`/home/bigcode/data/dev/bun/SerpMax/docs/01_CRIU_BROWSER_SNAPSHOT.md`
## 1. 目标与范围
ProfileMax 需要保存已启动的 Chromium 浏览器运行现场。示例:浏览器已经打开 Google 并完成搜索,创建快照后结束原浏览器;后续恢复时尽可能直接回到原搜索结果页面,避免再次启动浏览器、打开网站、重新执行页面初始化,从而降低重复作业的启动延迟和 CPU 峰值。
本方案采用 Linux + Chromium + CRIU,先验证技术可行性,再开发快照管理层。
### 1.1 必须实现
- 对 Chromium 完整相关进程树执行 checkpoint / restore。
- 恢复页面当前的内存状态,重点验证 DOM、JavaScript 堆、滚动位置和页面交互。
- 快照成功后可以结束原进程;恢复时不依赖原 Chromium 进程仍然存在。
- 保存快照元数据,校验浏览器版本、启动参数和运行环境。
- 记录创建耗时、恢复耗时、快照大小、内存占用和 CPU 峰值。
- 恢复失败时能报告具体阶段和错误,后续可回退到普通浏览器启动流程。
### 1.2 明确不作为目标
- **不要求保持原 TCP、HTTP/2、WebSocket 等网络连接。** 恢复后允许浏览器和页面重新建立连接。
- 不保证 Google 或其他网站的服务端会话永远有效。
- 第一阶段不做跨主机迁移、不做快照分叉克隆、不开发通用虚拟机快照系统。
- 不自行实现进程内存快照引擎;使用 CRIU 完成底层检查点与恢复。
- 不修改 Chromium 源码,除非 PoC 证明现有接口无法满足必要条件。
> 网络连接不需要延续,不代表可以直接忽略进程持有的 socket。CRIU 在 dump 时仍必须能处理进程文件描述符及其内核资源。必须通过 PoC 验证连接相关资源的实际处理方式,不能假设不传输 TCP 就一定可以成功 dump。
## 2. 总体架构
```text
ProfileMax API / Job Manager
|
v
Browser Snapshot Manager
|
+-- Browser Runtime Manager
| +-- Chromium 启动与进程树识别
| +-- 固定 Profile / 启动参数 / 显示环境
|
+-- Checkpoint Adapter
| +-- CRIU pre-dump / dump / restore 能力探测
| +-- 命令执行、超时、日志和错误归一化
|
+-- Snapshot Store
| +-- CRIU image 目录
| +-- 元数据与环境指纹
| +-- 完整性检查
|
+-- Restore Validator
+-- 进程存活检查
+-- 浏览器 DevTools / 页面状态检查
+-- 页面交互与网络重连检查
```
建议管理层使用项目现有的 Bun/TypeScript 技术栈实现;CRIU 通过受控子进程调用。若当前项目已有统一任务执行或进程管理模块,应复用,不要另建重复框架。所有 CRIU 命令必须由服务端生成参数数组执行,禁止拼接用户输入到 shell 命令。
## 3. 关键技术约束
### 3.1 Chromium 是多进程程序
不能只对 Browser 主进程执行快照。需要识别并纳入同一检查点的相关进程,例如:
- Browser 主进程
- Renderer 进程
- GPU 进程
- Network Service / Utility 等子进程
- 与浏览器运行现场相关的其他子进程
PoC 需验证 CRIU 采用正确的进程树入口和权限设置,且恢复后进程关系及 IPC 可用。禁止仅凭一个 PID dump 就认为整个浏览器已被完整保存。
### 3.2 固定运行环境
第一阶段固定以下条件,减少变量:
- 同一台 Linux 主机、同一内核版本与 CRIU 版本。
- 同一 Chromium 二进制版本及启动参数。
- 同一用户、UID/GID、工作目录、环境变量和 Profile 路径。
- 相同的挂载点、字体、共享库、临时目录和必要设备。
- 固定显示模式;优先从无头 Chromium 或固定 Xvfb 环境中选定一种进行 PoC,不要在首轮同时测试多种模式。
- 固定代理配置。代理本身可以在恢复后重新连接,但其配置应保持一致。
快照元数据必须记录上述环境。若恢复环境与快照不兼容,应拒绝恢复并给出明确原因。
### 3.3 Chromium 沙箱与 GPU
Chromium sandbox、namespace、seccomp、GPU 设备、共享内存及文件描述符可能影响 CRIU 兼容性。
- 首轮先使用正常安全配置验证。
- 如果为了定位问题,需要临时关闭 GPU 或在隔离测试环境中调整沙箱,必须作为单独实验变量记录。
- 不得把 `--no-sandbox` 当作生产默认参数,也不得为了通过 PoC 而默默降低生产安全边界。
- 生产部署前必须明确支持矩阵,写明哪些 Chromium 参数和运行模式经过实测。
### 3.4 网络与 socket 处理
ProfileMax 不需要恢复原 TCP/WS 连接,但进程内仍可能保存 socket 文件描述符、epoll 状态及异步网络请求状态。
实施原则:
1. 不将网络连接连续性纳入快照成功标准。
2. PoC 分别测试 CRIU 默认行为,以及在 CRIU 支持和环境允许时对已建立 TCP 连接的处理行为。
3. 若 dump 因网络文件描述符失败,记录 CRIU 原始错误和对应 FD 类型,再选择可验证的处理方案;不要直接忽略错误。
4. 恢复后,允许应用层重建连接;对已经失效的请求和 WebSocket,页面自身必须能恢复或重新加载相关数据。
5. 如需在恢复后关闭陈旧连接,应采用可验证的浏览器/页面层策略;不要从外部任意关闭 Chromium 的 FD,这可能破坏进程内部状态。
### 3.5 页面状态边界
进程内存快照的目标是保留运行现场,但不能保证每个网站页面都能无缝续跑:
- 页面已渲染的 DOM 和 JavaScript 堆是重点验证项。
- 页面计时器、Promise、Service Worker、后台标签页、扩展进程和浏览器内部任务需要单独测试。
- 恢复后页面可能检测到网络断开、请求失败或登录状态失效。
- 页面现场恢复与网站业务状态恢复是两回事。服务端数据可能已经改变。
## 4. 快照目录与元数据
建议每个快照使用独立目录,CRIU image 文件和元数据分离管理:
```text
data/snapshots/
<snapshot-id>/
criu/
# CRIU 生成的 checkpoint image 文件
manifest.json
checkpoint.log
restore.log
```
`manifest.json` 建议字段:
```json
{
"schemaVersion": 1,
"snapshotId": "uuid",
"createdAt": "ISO-8601",
"status": "ready",
"browser": {
"name": "chromium",
"version": "exact-version",
"executable": "/usr/bin/chromium",
"rootPid": 1234,
"launchArgsHash": "sha256"
},
"runtime": {
"kernelRelease": "exact-release",
"criuVersion": "exact-version",
"uid": 1000,
"gid": 1000,
"profilePath": "/data/profiles/example",
"displayMode": "xvfb-or-headless",
"networkContinuityRequired": false
},
"metrics": {
"checkpointDurationMs": null,
"restoreDurationMs": null,
"snapshotBytes": null
},
"validation": {
"processTreeRestored": false,
"pageStateVerified": false,
"interactive": false
}
}
```
上例仅为结构示意。实际实现必须从运行环境采集真实值,不能硬编码 PID、版本或路径。敏感代理凭据、Cookie 和页面数据不得写入普通日志或 manifest。
## 5. 生命周期与状态机
建议快照状态:
- `creating`:正在执行 checkpoint。
- `ready`:checkpoint 完成,元数据和文件校验通过。
- `restoring`:正在恢复。
- `restored`:进程恢复成功且基础检查通过。
- `failed`:创建或恢复失败。
- `deleting`:正在清理。
创建流程(浏览器关闭前自动快照):
1. ProfileMax 统一管理浏览器关闭入口。任务完成、任务管理器要求关闭或用户主动关闭时,先进入 `closing` 流程;不要等 Chromium 已经开始退出后才监听 `close` 事件。
2. 检查目标浏览器实例和所有权,并确认任务已结束、没有正在执行的关键操作。
3. 记录 Chromium 版本、进程树、启动参数、运行环境及当前作业 URL。
4. 创建临时快照目录并执行 CRIU checkpoint/dump。
5. 收集退出码、stdout/stderr、CRIU 日志和耗时;校验检查点文件完整并写入 manifest。
6. 校验通过后,原子地将快照标记为 `ready`,并将其关联到对应浏览器实例/任务。
7. 只有快照已可靠落盘并标记为 `ready` 后,才完成浏览器关闭流程。注意:常规 CRIU dump 通常会让被 dump 的进程停止/退出,因此应由 CRIU 的实际 dump 语义完成进程收尾,不能再无条件调用 Chromium 的正常关闭。
8. 如果快照失败,记录错误并按配置执行普通关闭;不要把不完整快照标记为 `ready`。若产品要求必须先保留一个仍运行的 Chromium 再正常关闭,需要单独验证 leave-running 模式与 Profile 文件一致性,不能直接把它当作安全默认方案。
关闭事件的实现要求:使用 ProfileMax 自己的统一关闭方法/生命周期钩子作为触发点;浏览器进程已经退出后的 `close`/`exit` 通知只用于清理和记录结果,不用于启动快照。
恢复流程:
1. 校验 manifest、快照文件、版本和运行环境。
2. 确保没有冲突的同一实例正在运行;首版不支持从同一快照并发恢复多个实例。
3. 准备恢复所需的用户、目录、挂载、网络命名空间和显示环境。
4. 执行 CRIU restore,保存日志和耗时。
5. 验证恢复后的进程树、浏览器调试接口(如果启用)、原页面状态及用户交互。
6. 对网络重连进行观察,但不要求旧连接继续存在。
7. 只有验证通过才标记为 `restored`;失败时保留诊断材料,避免自动覆盖原快照。
注意:CRIU 的具体命令行参数、权限要求和网络选项必须以部署机器上安装版本的 `criu --help`、官方文档和 PoC 结果为准。本文不预设某一组命令在所有内核/CRIU 版本上通用。
## 6. 模块接口建议
管理层可先实现以下内部接口,具体参数根据现有 ProfileMax 代码规范调整:
```ts
type SnapshotStatus =
| "creating"
| "ready"
| "restoring"
| "restored"
| "failed"
| "deleting";
interface SnapshotManifest {
schemaVersion: number;
snapshotId: string;
createdAt: string;
status: SnapshotStatus;
browser: {
name: "chromium";
version: string;
executable: string;
rootPid: number;
launchArgsHash: string;
};
runtime: {
kernelRelease: string;
criuVersion: string;
uid: number;
gid: number;
profilePath: string;
displayMode: string;
networkContinuityRequired: false;
};
}
interface CheckpointResult {
snapshotId: string;
durationMs: number;
snapshotBytes: number;
logPath: string;
}
interface RestoreResult {
snapshotId: string;
durationMs: number;
restoredPids: number[];
validationPassed: boolean;
}
interface CheckpointAdapter {
checkCapabilities(): Promise<{
available: boolean;
criuVersion?: string;
reasons: string[];
}>;
checkpoint(browserRootPid: number, snapshotDir: string): Promise<CheckpointResult>;
restore(snapshotDir: string): Promise<RestoreResult>;
}
```
这些接口是设计草案,不代表项目中已经存在对应模块。需要先查看 ProfileMax 当前目录结构和现有进程管理实现,再决定最终落点。
## 7. PoC 实施计划
### P0:环境检查
- 确认 Linux 发行版、内核版本、CRIU 版本及所需权限。
- 运行 CRIU 自检,并保存完整输出。
- 检查 Chromium 的实际进程树、命名空间、打开的 FD、共享内存和设备依赖。
- 记录当前 Chromium 版本、启动参数和运行模式。
交付物:环境报告、CRIU capability 报告、浏览器进程树样本。
### P1:最小 checkpoint / restore
- 启动 Chromium 并打开固定测试页面。
- 在页面内创建可验证的 JavaScript 状态标记,例如计数器、随机 token、滚动位置和 DOM 文本。
- 执行 checkpoint,确认原实例已按预期停止或退出。
- restore 后读取页面标记,验证其与 checkpoint 前一致。
- 检查页面是否可点击、输入和滚动。
交付物:可重复执行的测试脚本、CRIU 日志、成功/失败原因。
### P2:真实搜索页面
- 打开 Google 并执行固定关键词搜索,按正常流程完成测试任务。
- 任务完成、浏览器准备关闭时,由 ProfileMax 关闭流程触发快照;不使用定时快照,也不需要单独监听页面稳定事件。
- 快照完成并可靠落盘后,按 CRIU dump 的实际语义结束原进程,再执行恢复测试。
- 验证 URL、DOM、滚动位置和页面交互。
- 观察网络重连后的页面行为;不把旧 TCP/WS 保持连接作为成功条件。
交付物:真实网站验证记录。若网站行为不稳定,使用本地测试页面作为可重复基线,并将网站测试作为补充。
### P3:基准测试
至少重复 20 次,分别测量普通冷启动和快照恢复:
| 指标 | 冷启动 | CRIU 恢复 |
|---|---:|---:|
| 总耗时 P50 / P95 | 测量 | 测量 |
| CPU 峰值 | 测量 | 测量 |
| 恢复后可交互耗时 | 测量 | 测量 |
| 快照体积 | 不适用 | 测量 |
| 失败率 | 测量 | 测量 |
必须统一测试条件:相同主机、Chromium 版本、Profile、页面、代理和资源状态。单次结果不能作为结论。
### P4:管理器封装
只有 P1/P2 证明可行后再实施:
- snapshot create / restore / inspect / delete。
- 状态机和并发锁。
- 日志、错误分类、超时和取消。
- 快照容量限制及过期清理。
- 环境兼容性校验和失败降级。
- 权限隔离,避免普通用户对任意系统进程执行 dump/restore。
## 8. 验收标准
首阶段必须全部满足:
1. 能对目标 Chromium 进程树成功 checkpoint。
2. 原浏览器进程停止后,能够从快照恢复。
3. 恢复后原页面的验证标记、URL、主要 DOM 状态及滚动位置符合预期。
4. 页面可继续交互,且允许网络连接重新建立。
5. 失败时能够通过日志定位到具体 CRIU 错误或资源依赖。
6. 测得冷启动与恢复的耗时、CPU 峰值、快照大小和失败率。
性能目标在取得基线数据后设定,不预先承诺快照恢复一定比冷启动快。快照读取、内存恢复和页面恢复验证都可能消耗显著的磁盘 IO 与 CPU。
## 9. 安全与运维要求
- 快照可能包含 Cookie、认证令牌、页面内容及其他敏感内存数据,按敏感数据保护。
- 快照目录仅允许浏览器运行用户和快照管理服务访问,权限默认最小化。
- 不在日志中输出 Cookie、Authorization、代理密码或页面表单内容。
- 只允许管理器操作其登记的 Chromium 进程,不接受任意 PID 的外部请求。
- CRIU dump/restore 使用最小必要权限;如需 root 权限,限定服务边界并记录审计日志。
- 删除快照时清理完整目录,并记录清理结果。
- 版本、内核或启动参数不兼容时拒绝盲目恢复。
## 10. 参考资料
- CRIU:<https://github.com/checkpoint-restore/criu>
- CRIU 官方文档:<https://criu.org/>
- CRIU 使用手册:<https://criu.org/Basic_usage>
- Podman checkpoint/restore(用于参考容器集成方式):<https://docs.podman.io/>
## 11. 当前结论
采用“CRIU 底层 + ProfileMax 自有管理层”的路线。第一阶段只交付 PoC,不提前承诺 Chromium 全进程树一定可恢复。优先验证真实运行环境中的沙箱、GPU、共享资源和 socket 处理。TCP/WS 连续性不是验收目标;进程仍需正确处理网络相关 FD,恢复后允许应用重新连接。PoC 通过后再扩展为多实例快照管理。
## 12. 实测结论与落地记录(2026-10-20)
### 12.1 环境与实测数据
- 环境:Zorin OS 18.1(Ubuntu noble 基),内核 7.0.0-31-generic,veil-chromium 153.0.8010.52;
CRIU 4.2(源码编译,`/usr/local/bin/criu`,文件能力 `cap_sys_ptrace,cap_sys_admin,cap_net_admin+eip`,
非 root 可用,免改 ptrace_scope)。
- PoC(直启 chrome → baidu 搜索页 → dump → restore):
| 指标 | 实测值 |
|---|---|
| 冷启动(进程拉起 → CDP 就绪) | ≈ 0.6s |
| dump(9 进程树,RSS ≈ 1.13GB) | ≈ 1.3s,镜像 ≈ 354MB(397 个 .img) |
| restore(detached) | ≈ 0.36s |
| 现场校验 | URL/标题/JS 堆标记/滚动位置/搜索结果 DOM/localStorage 全部一致,`navigator.onLine=true` |
| 可交互 | 恢复后二次搜索成功(网络自动重连) |
- node 端到端(经 ProfileMax API:创建快照 Profile → 启动 → 搜索 → 停止自动 dump → 再启动):
停止含 dump ≈ 1.3s;再次启动 ≈ 0.4s 且 `restored:true`,CDP 端口原样恢复,现场校验同上全绿
(复测脚本 `node/scripts/criu-poc.ts`、`node/scripts/criu-e2e.ts`)。
### 12.2 关键结论(实测定论)
1. **沙箱与 CRIU 的结构性冲突**:criu 拒绝对「非根进程自建的嵌套 PID namespace」执行 dump
(`CLONE_SUBNS` 仅含 mount/net),而 chromium namespace 沙箱的 zygote/渲染进程恰在嵌套 pidns 中。
→ **快照模式 Profile 启动时显式追加 `--no-sandbox`**(browser.manager `snapshotSandboxArgs`);
生产节点为 root 容器,ProfileMax 本就强制 `--no-sandbox`,此处仅影响非 root 环境,非全局降级。
2. **仅支持 headless**:有头模式连接的 X11/Wayland socket 是树外 STREAM unix socket,
criu 的 `--ext-unix-sk` 仅支持 DGRAM 外部连接 → 有头实例停止时不做快照(回退常规关闭)。
3. **D-Bus 必须「干净失败」隔离**:chrome 对已建立后断开的 dbus 连接会 FATAL
("D-Bus connection was disconnected. Aborting.")。快照模式启动 env 将
`DBUS_SESSION_BUS_ADDRESS`/`DBUS_SYSTEM_BUS_ADDRESS` 指向 `unix:path=/nonexistent-bus`
(与生产容器无 bus 的现实一致);地址格式非法(如 `/dev/null`)会导致导航失败,不可用。
4. **crashpad handler 在树外**:chrome 会把 handler daemonize 到进程树外(subreaper 接管),
其 SEQPACKET socketpair 端为树外对端。已给 criu 打补丁:dump 允许外部 STREAM/SEQPACKET,
restore 侧对非 DGRAM 外部对端跳过 connect(以「未连接」语义恢复,客户端优雅降级);
补丁内容两处(criu/fsnotify.c 悬空 inotify watch 跳过 + criu/sk-unix.c 外部 socket 放行),
生产镜像需携带补丁版 criu。
5. **chromium 共享内存临时文件**(`.org.chromium.Chromium.*`,实测 4MB 起步)远超 criu 默认
1MB ghost 限额 → dump/restore 统一 `--ghost-limit=512MB`(env `CRIU_GHOST_LIMIT_MB` 可调)。
6. **dump 参数**:`--file-locks --tcp-close --ext-unix-sk --ghost-limit=N [--unprivileged]`;
`--tcp-close` 表示已建 TCP 连接按「关闭」落镜像(符合 1.2 节「不要求连接连续性」),
恢复后由页面/浏览器自行重连,实测 baidu 页面正常。
7. **启动方式约束**:快照 Profile 由本服务直启(setsid 保证 session leader + 显式
`--user-data-dir`),不经 playwright 管道(管道对端在树外无法 dump);CDP 经 connectOverCDP
挂接,停止时 playwright 句柄 close() 仅断连不杀进程。
8. **参数哈希与端口绑定**:dump 时将完整启动参数(含 `--user-data-dir` 打头)哈希入 manifest,
restore 前重算比对,任一不一致拒绝恢复回退冷启动;impersonate MITM 端口记入 manifest,
恢复时 `ensureImpersonate` 优先复用同端口(浏览器重连无缝),端口被占则拒绝恢复。
9. **陈旧 DevToolsActivePort**:dump 后该文件残留,直启前必须删除,否则 CDP 就绪探测
可能打在死端口上(实测踩坑)。
10. **criu 单次操作超时 180s**,dump/restore 失败不重试:回退常规关闭/冷启动,
失败快照保留 `failed` 状态与日志供诊断(manifest.json / dump.log / restore.log)。
### 12.3 落地范围(本版)
- Profile 新增 `snapshot.enabled` 配置(admin「快照模式」开关,缺省关闭;仅 veil + headless 生效);
- 停止浏览器时自动 checkpoint(存储快照抓取先于 dump),启动时优先 restore 并回写 CDP/条目;
- 节点 API:`GET/DELETE /profiles/:id/snapshot`;admin 中继同路径 GET/DELETE + PUT 快捷开关;
- admin 概览卡:快照(含大小)/ 自动CF挑战 / 自动挑战 reCAPTCHA 三开关同行;
- 快照目录:`<profileDir>/<profileId>/snapshot/`(manifest.json + criu/ 镜像 + dump/restore 日志),
随 Profile 删除一并清理;同一 Profile 仅保留最近一次快照。
## 13. 镜像压缩与 USER_DATA 清理(2026-10-21,node v0.38.0 / admin v1.55.0)
### 13.1 镜像压缩(zstd 后处理)
CRIU 4.x 核心已移除内建压缩选项(旧版 `-z/--compress` 不存在,`criu-image-streamer` 需额外组件),
采用「dump 后 zstd 压缩大镜像 / restore 前解压还原」的后处理方案(snapshot.manager):
- dump 成功后(进程已退出)对镜像目录中 >1MB 的 `*.img` 逐文件 `zstd -3 -T0` 压缩,
压缩成功才删原文件,单文件失败保留原样不阻塞;`SNAPSHOT_COMPRESS=off` 可整体关闭。
- restore 前把 `*.img.zst` 解压还原(criu 不识别压缩镜像),耗时记入 manifest
`metrics.decompressDurationMs`;压缩前/后体积分别记 `snapshotBytesRaw`/`snapshotBytes`。
- 实测(同环境同场景,baidu 搜索现场,两轮):
| 指标 | 压缩前(10-20 基线) | 压缩后(10-21 实测) |
|---|---|---|
| 快照镜像大小 | 308~312MB | **67.5~70.6MB(约 4.4x 缩小)** |
| dump 耗时 | ≈1.0~1.3s | ≈1.0~1.3s(不变) |
| 停止总耗时(含 dump+压缩) | ≈1.2~1.3s | ≈2.4s(压缩约 +1.1s,zstd -3 -T0) |
| restore(criu 自身) | ≈0.3s | ≈0.3s(不变) |
| restore 前解压 | — | ≈0.58s |
| 再次启动总耗时 | ≈0.43~0.58s | ≈1.11~1.16s(解压 +0.6s) |
| 现场校验(8 项) | 全绿 | 全绿(URL/标题/JS 标记/滚动/localStorage/结果数/在线/二次搜索) |
结论:以「每次停止 +≈1.1s、每次恢复 +≈0.6s」换「磁盘占用 -77%」,默认开启;
磁盘敏感场景收益显著,对恢复可用性无影响。
### 13.2 USER_DATA 静态缓存清理
- **自动清理(默认开启)**:浏览器停止时实测 USER_DATA 体积(关闭前采样)超过
`USERDATA_CLEAN_THRESHOLD_MB`(默认 100MB)→ 进程完全退出后软清理静态缓存
(cache.manager `autoCleanOnStop`);清理后体积才回传 admin(profiles.user_data_size)。
- **软清理范围(CACHE_DIRS)**:根级 + `Default/` 子目录双布局——HTTP Cache、Code Cache、
GPUCache、Dawn/GrShader/Graphite 缓存、Media Cache、Shared Dictionary、组件 crx 缓存等;
Cookie/LocalStorage/IndexedDB/Service Worker/登录态一律保留(实测主要占用
`Default/Cache` + `Default/Code Cache`,约占 USER_DATA 80%)。
- **手动清理**:节点 `POST /profiles/:id/cleanup`(admin 中继 `POST /api/profiles/:id/cleanup`,
Profile 详情页「编辑」与「复制」之间的「清理」按钮):软清理 + **删除现有 CRIU 快照**
(快照镜像含缓存页,restore 会原样还原缓存,不删等于没清;下次停止自动重建快照);
浏览器运行中节点拒绝(`CACHE_CLEAR_FAILED`,提示先停止)。返回 before/after/freedBytes
与 snapshotDeleted,前端 toast 展示释放体积。
- 验证:130MB 假缓存(Default/Cache)触发清理释放 120MB,Cookie/LocalStorage 保留;
50MB 未触发;E2E 全流程(含手动清理后快照 bytes=0)通过。
### 13.3 启动方式对比:正常冷启动 vs 快照恢复(到达同一现场)
口径:从 `POST /browser/start` 发起,到「baidu 同一关键词搜索结果页 DOM 已渲染」为止
(CDP 连接与现场确认均计入);基准脚本 `node/scripts/criu-bench-compare.ts`,两轮实测:
| 阶段 | 冷启动(非快照) | 快照恢复 |
|---|---|---|
| 启动 → CDP 就绪 | 0.80~0.96s | 0.99~1.51s(含解压≈0.6s + restore≈0.3s) |
| 导航加载搜索结果 | 2.52~4.08s(随网络波动) | 0(现场已在,免导航) |
| 现场确认 | 0.08~0.11s | 0.04~0.32s |
| **到达同一现场总计** | **3.69s / 4.44s** | **1.18 / 1.40 / 1.49 / 1.59s(均值 ≈1.4s)** |
| 现场一致性 | — | 4/4 轮 URL/标题/结果数完全一致 |
| **加速比** | — | **2.86x / 2.88x(两轮稳定)** |
附:快照 Profile 自身冷启动(3.61s/5.14s)与普通 Profile 无差异,快照模式不拖累冷启动;
本组 dump 耗时 1.7~3.3s、快照 60.4~70.9MB(压缩后),dump 耗时随当时浏览器内存占用浮动。