1.77.6: SERP sorry-重定向按验证码语义(不换号+15min冷却);浏览池保温释放跳过+60min持有上限;速率-门壳实验与监控工具
This commit is contained in:
@@ -0,0 +1,483 @@
|
||||
# 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 耗时随当时浏览器内存占用浮动。
|
||||
Reference in New Issue
Block a user