onesvm-browser-server/docs/plan-final-20260901.md
chii 983259836d chore: init workspace with onesvm-dev-md + casa-commander
docs: 联网搜索服务架构方案全套(plan-final/design-arch/选型决策/整合导览/MCP文档/部署预设/联调手册)
bench: 5 方案 + 代理 + 站点矩阵本机实测工程(无密钥)
部署目标:primary mgr1 先行测试(待批准后执行)
2026-09-01 15:19:52 +08:00

179 lines
18 KiB
Markdown
Raw 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.

---
type: arch
status: active
created: 2026-09-01
step: S5 / plan-20260901-01 / run-20260901-browser-arch
---
# onesvm-browser-server 最终方案 v1(用户 review 版)
> 时间口径 Asia/Shanghai。本文整合:S1 调研(`research/01–05`)、S2 筛选(`select.md`)、
> S3a 代理探活(`proxy-probe.md`)、S3b/S3c 本机 Docker 实测(`bench/S3b-summary.md` / `S3c-summary.md`,原始数据 `bench/*/results.json`)、
> S4 架构设计全文(`docs/design-arch-20260901.md`,机制细节权威;冲突处以本文为准)。
> 本文所有性能数字均为 **2026-09-01 本机实测**(darwin arm64 / Docker Desktop 29.4.0),非纸面推算;外推处显式标注。
> **权威关系**:本文为决策与结论权威;机制细节权威为 design-arch(冲突处以本文为准)。
```mermaid
flowchart LR
C[智能体消费者<br/>Vlepontas / EAI / 注册主体] --> G[统一出口网关 ×N 无状态<br/>MCP 主 + HTTP 兜底 · X-Service-Token]
G -->|overlay enqueue| S[scheduler 单副本<br/>SQLite WAL 队列 · ADMIT_MAX=60]
S --> D{Dock 适配器}
D --> A[A 无浏览器<br/>SearXNG-CN/Global · Trafilatura]
D --> B[B 轻渲染<br/>Lightpanda]
D --> H[C 保真按需槽<br/>chrome-headless-shell]
D -.插拔预留.-> HD[(有头档·默认不部署)]
B & H --> P[ProxyManager 单副本<br/>mihomo · vless 热池 · 合规路由]
A -->|国内域| DI[国内直连]
A -->|境外搜索| P
G --> POL[合规拦截·策略包单源<br/>请求侧@网关 / 响应侧@worker模版层]
```
---
## 0. TL;DR
1. **1GB 够开机、也够维持 Vlepontas 60 会话级 + EAI 日常使用**——前提是三条纪律:60 = 队列深度而非浏览器并发;渲染槽 ≤5 且重页互斥;保真 Chrome 槽按需启动。详见 §2 与 §7-D1。
2. **实测最痛的不是内存,是上游反爬**:60 并发裸打 SearXNG,百度/搜狗全灭(CAPTCHA)、必应中国 60/60 扛住;国外方向数据中心 vless IP 下 Google/DDG/Brave 全灭、只有 Bing 出结果。两者都由「网关排队 + 每 host 限速 + 缓存」消化,不由加内存解决。
3. **入选 5 套**:国内 `SearXNG-CN` + `Trafilatura-HTTP`;国外 `SearXNG-Global`(带质量警示)+ `Lightpanda` + `chrome-headless-shell`。预留 `Camoufox`(强对抗,需住宅代理)。
4. **架构零 Redis**:SQLite WAL 队列 + 进程内快通道;网关无状态 ×N,scheduler/ProxyManager 单副本。
5. 需你拍板 6 个决策点(§7),最关键的是 **D1 内存档位** 与 **D2 国外搜索质量路线**。
---
## 1. 任务 1:统一消费出口
设计全文:`docs/design-arch-20260901.md` §2。要点:
- **注册/凭证**:`Consumer`(注册主体:vlepontas、eai…)+ `ApiKey`(可吊销、带 scopes/rpm/日配额/月配额/并发会话数)+ `QuotaLedger`(预扣防超卖)。明文 key 只回传一次,库存 hash,`hmac.compare_digest` 比对。
- **双形态同一内核**:MCP Server 为主(`POST /mcp`,Streamable HTTP,无协议会话态)+ HTTP API 兜底(`/v1/search` `/v1/read`,`/v1/extract` 特权);同一 Auth → Policy → Queue → Engine 流水线,错误码两面对齐。
- **认证头遵循组织 service-secret-protocol**:静态 key 走 `X-Service-Token: bs_<random>`,🔴 禁 `Authorization: Bearer` 塞静态 secret;密钥 `${VAR:?required}` fail-closed。
- **urlapi**:HTTP 监听独立端口(**提议 `:8640`**,见 §7-D3;S4 原设计值 `:8300` 与 dev-swarm `voc-analysis-dev` 冲突,已改),反代前缀 `/bs-api`(对齐组织 `/search-api` 先例),strip 后转发。
- 管理面(签发/吊销 key)仅 overlay 内网 + 独立 admin token,CLI + SQL 先行。
## 2. 任务 2:集群规格与无 Redis 排队(bench 校准后)
### 2.1 排队机制(零 Redis)
**入队路径**(跨文档统一定义):消费者 → gateway(无状态:认证/配额预扣/合规预检)→ **overlay 内网 `POST /enqueue`** → scheduler(**SQLite 唯一写者**)进程内 bounded queue 快通道 + 立即落 SQLite WAL → 落盘成功才经 gateway 向消费者 ACK 排队位。scheduler 不可达时 gateway 返回 503 + `Retry-After`(fail-closed,gateway 本地不落盘)。执行侧:scheduler 用 `UPDATE…RETURNING` 原子抢单派发 worker;租约 + reaper 收割 + 指数退避(`attempts≤2`,仅瞬时错误重试)+ 死信表。背压三层:`ADMIT_MAX=60`(running+queued 合计)→ 超限 503/429 + `Retry-After` 只拒新不杀旧。理由与机制细节:design-arch §4。
### 2.2 实测内存底账(2026-09-01 cgroup 口径)
| 组件 | idle | 单会话峰值 | 60 burst 峰值 | 建议 cgroup |
|---|---:|---:|---:|---:|
| searxng-cn | 99 MB | 122 MB | 170 MB | 192m |
| trafilatura-http | 33 MB | 35 MB | 41 MB | 64m |
| searxng-global | 122 MB | 150 MB | 181 MB | 192m |
| lightpanda | **3.6 MB** | **251 MB**(重 Shopify 页) | 143 MB | 320m |
| chrome-headless-shell | 37 MB | **394 MB**(同页) | 179 MB | 400m |
| mihomo(代理数据面) | 小(探活期运行平稳;RSS 未单独采样,**估算·待部署后校准**) | — | — | 64m |
| gateway + scheduler(Go/Rust 单二进制+SQLite,估算·待首轮实现校准) | — | — | — | 96m 合计(64m+32m) |
### 2.3 渐进档位表(实测校准版)
**记账口径**(P1-1 修订):「档标」= **常驻业务峰预算**(实测 idle + burst 峰值推算 + 余量);各组件 cgroup limit 是**防暴走天花板,允许超配**(上限合计可超档标)——重页峰值由渲染互斥调度保证不同时发生,超限杀 worker 不杀网关。实测依据:§2.2 底账。
| 档 | 档标(常驻业务峰) | 实测 idle / 业务峰推算 | cgroup 天花板合计 | 组成 | 能力(实测/换算) |
|---|---|---|---|---|---|
| **L0 起步 ~350MB** | ~350MB | idle ≈178MB / 峰 ≈257MB | 352m | gateway×1(64m) + scheduler(32m) + searxng-cn(192m) + trafilatura(64m) | 国内搜索+正文精读全开;搜索单发 p50 0.63s;读取 p50 0.06s |
| **L1 标准 ~700MB** | ~700MB | idle ≈350MB / 峰 ≈627MB | 960m | L0 + ProxyManager(32m) + mihomo(64m) + searxng-global(192m) + lightpanda(320m) | 国外搜索(仅 Bing 可用,见 D2)+ 轻渲染 4 槽(实测 2.13 jobs/s) |
| **L2 满配 1GB** | ≤1GB | idle ≈380MB / 峰 ≈660MB | 1024m 常驻;shell 按需 400m **非常驻**,与 lightpanda 重页互斥 | L1 + gateway×2(+64m) + shell 按需槽 | +保真渲染 1 槽(实测 FIFO 60/60、74s 零拒绝) |
| **L3 舒适 1.5GB(扩容提议,见 D1/§2.5)** | ~1.5GB | —(推算) | ~1536m | L2 且 shell 常驻 400m + searxng-cn/global 各 ×2 + 余量 | 渲染槽 4+1 免互斥;搜索双副本冗余;见 §2.5 换算 |
| **L4 强对抗档(另议)** | 3–4GB + 住宅代理 | — | — | + Camoufox ×2(150–300MB/实例) | Amazon/Medium 级 WAF 目标(实测确认数据中心 IP 打不过) |
**节点布局**:【2026-09-01 用户更正】目标环境为 **primary 生产 Swarm(mgr1 .51 / mgr2 .52 / mgr3 .53)**,非 dev-swarm。**测试期全部署于 mgr1 单节点**;扩展期:mgr1 控制面(scheduler + ProxyManager + 本地卷 SQLite + gateway×1)、mgr2 国内组+轻渲染(searxng-cn + trafilatura + lightpanda)、mgr3 国外组+保真(searxng-global + shell 按需槽 + gateway×1)。有状态钉节点,网关可漂移。部署细节权威为 `deploy-prod-preset-20260901.md`。(原 dev-swarm .61/.62/.63 布局作废——1GB 内存约束与档位表不变。)
> 注(P6 F1):若适配器采用 scheduler 进程内形态(deploy 预设 D8),scheduler 由 32m 提额至 64m,L2 常驻天花板 1024m → 1056m(超配口径,档标不变)。
### 2.4 为什么 60 不是 60 个浏览器(实测证据)
- chrome-headless-shell `CONCURRENT=1`:60 任务全部 FIFO 入队、顺序执行、**0 拒绝、0 OOM**,墙钟 74s。
- lightpanda 4 槽:60/60 全过,28s。
- searxng-cn 裸 60 并发:HTTP 全 200 但断言仅 4/60——**瓶颈是百度/搜狗 CAPTCHA**;必应中国 60/60、360 53/60。结论:网关把对上游并发钳在 4–8 + 每 host 最小间隔 + 短缓存,队列深度照常 60。
- 注意:国内反爬按**出口 IP**计,dev-swarm 出口 IP 单一,**多副本不能分散 CAPTCHA**,只能靠限速与缓存(这是设计结论,不是缺陷)。
### 2.5 负载模型与扩容换算(D1 的决策依据)
**实测吞吐锚点**(bench 原始数据换算):
| 通道 | 实测 | 持续吞吐换算 |
|---|---|---|
| 国内搜索(searxng-cn) | 单发 p50 0.63s | 上游钳 6 并发 → ≈9.5 qps |
| 国外搜索(searxng-global,仅 Bing) | T3 p50 4.68s | 钳 4 并发 → ≈0.85 qps(质量受限见 D2,非容量受限) |
| 正文读取(trafilatura) | p50 0.058s @8 并发 | 服务侧潜力 ≫100/s,瓶颈在上游站点限速 |
| 轻渲染(lightpanda 4 槽) | 60 任务/28.2s | **2.13 jobs/s** |
| 保真渲染(shell 1 槽) | 60 任务/74.0s | **0.81 jobs/s** |
**负载模型**(假设·比例待你校准):60 会话活跃,每会话每分钟 2 次搜索 + 3 次读取 + 0.1 次渲染 → 搜索 2 qps、读取 3 qps、渲染 0.1 jobs/s。
**结论**:L2(1GB)稳态占用率——国内搜索 ~21%、读取 ~3%、渲染 ~5%,**可维持 Vlepontas 60 会话级 + EAI 日常负载**;压力只在「60 同发突发」与「重页叠加」两个瞬间,由队列(ADMIT_MAX=60)与渲染互斥消化。
**L3 1.5GB 的增量价值**:① shell 常驻,省每次冷启动(估算 5–10s/次·未单独测);② 重页免互斥,消除渲染互斥排队等待;③ searxng 双副本,滚动重启不断流;④ gateway×2 滚动发布不断线。**提议:1GB 承诺不变先上线 L0→L2;若渲染等待或重页互斥成为日常痛点,再申请升至 L3(dev-swarm 节点各 6.5GB,1.5GB 总预算宽裕)。**
## 3. 任务 3:Dock 协议 + 整合器 + 统一输出
设计全文:design-arch §3。要点:
- **DockAdapter 五方法**:`init / health / execute / teardown / capabilities`;`health()` 强制上报 `rss_bytes / startup_ms / slots_free`;适配器负责「统一意图 → 引擎原生调用」的输入转换,**只产出 RawResult**;「RawResult → 统一信封」的输出整合(Size guard → fit markdown → 安全扫描 → Schema 封装)收敛在 **Dock worker 共享模版层(整合器)**,词表/规则单源版本化,N 个适配器零合规代码(S7 架构审查锁定);回收按 N 页/T 分钟硬重启。
- **统一输入两类意图**:`Search{query, max_results≤20, time_range?, lang?}` 与 `Read{url, formats=[markdown], max_chars, extract?}`;第三类 `browse` 协议预留默认关闭。
- **消费者自选国内/国外**:MCP 工具暴露 `region: domestic|overseas` 参数(对应任务 3 的「两种接口类型」),消费者按 MCP 文档自行选择;网关仍按域名路由表强制合规(选了 overseas 也不会把国内域送代理)。
- **统一 AI 原生信封**:`{ok, kind, request_id, took_ms, usage{credits,engine,tokens_estimate}, provenance{url,retrieved_at+08:00,adapter,proxy_exit,cached}, error{code,message,retry_after_s?}}`;search 给 `results[{title,url,content≤800字,score 0–1,engine}]`;read 给 fit markdown(实测提纯:Shopify 壳页 1.44MB HTML → 2.9–3.4KB 正文,约 **420–500 倍**,lightpanda/chrome 两内核样本)+ 可选 extract 旁路(默认零 LLM 路径:JSON-LD/OG/CSS);错误码 `blocked|denied|timeout|quota|rate_limited|extract_failed|upstream` 与 HTTP 对齐。
- **降级链**:C(保真)槽满 → B(轻渲染)→ A(HTTP+fit)→ `blocked/upstream`,不静默降数据质量。
- **有头浏览器仅抽象插拔预留**:Dock Protocol 预留 `render=full+headful` 能力位(有头/Camoufox 档),默认不装镜像、不占内存预算。
## 4. 任务 4:ProxyManager + 合规双向保险
设计全文:design-arch §5。要点:
- **数据面 mihomo + 控制面自研**(单副本):订阅解析(实测 SUB-1 为 Clash YAML,69 节点:vless 52 全活、hy2 17 容器 UDP 全灭弃用);多订阅容灾位已留(SUB-2 待你提供);探针 `google generate_204`,活跃出口 30s、全池 5min/轮;P2C 轮换 + 同域名 sticky;主圣何塞(167ms 实测)备东京。
- **域名路由表**:国内域/`*.onesvm.com` → DIRECT;黑名单 → deny;高对抗域 → 标记 render=full;默认境外 → vless 池。
- **生产侧出口拦截**(统一策略包单源 + 两个执行点,Schema 之前,MCP/HTTP 共用):**请求侧在 gateway**(入队前:SSRF fail-closed 每次重定向重验、仅 80/443 → 域名 blocklist + robots 普通 key 遵守);**响应侧在 Dock worker 共享模版层**(fetch 后、封装前:体积/Content-Type 白名单 → 关键词分类词表对齐《生成式 AI 办法》第 4 条(NFKC 归一,高危 block,PII 默认 redact)→ 注入防护包裹)。词表版本化(`wordlist_version` 入审计)。命中合规即 `error.code=denied` 并写审计(`consumer_id,url,rule_id,ts+08:00`),不假装成功。
- **消费侧 MCP 文档规则**(server instructions 固化):不得用于非法采集、破登录/支付墙/验证码(默认无此能力)、整站搬迁式 crawl、汇总公开个人信息成档案、把含境内个人信息的 query 发往境外引擎。
- **法律主路径结论**(research/05,非法律意见,上线前法务复核):境内集群拉境外公开网页回境内 ≠ 数据出境;但一旦走境外托管 SaaS(Tavily/Jina 云)query 即出境 → 默认境内闭环。
- 订阅 URL 只进环境变量;节点凭据脱敏;日志禁记 key 明文/query 原文(记 hash+长度)。
## 5. 任务 5:实测评定结论
评分卡(权重:内存三档 30% / 质量 25% / 成功率 20% / 延迟 15% / 运维 10%;门槛 综合≥60):
| 方案 | 组 | 综合分 | 实测亮点 | 实测短板 | 结论 |
|---|---|---:|---|---|---|
| trafilatura-http | 国内 | **96.8** | 60/60、p50 0.06s、41MB burst | gov.cn 联播壳页 favor_precision 弃取(能力边界) | **P0 默认开机** |
| searxng-cn | 国内 | **71.5** | 单发 5/5、p50 0.63s、政策域命中准 | 60 burst 断言 4/60(百度/搜狗 CAPTCHA;bing-cn 60/60) | **P0**(须网关排队钳 4–8 + 短缓存) |
| lightpanda | 国外 | **91.0** | idle 3.6MB、JS 对照 3/3、T5 60/60 | 重 Shopify 页 251/320m;CF/Amazon 过不去 | **P2 默认 JS 核** |
| chrome-headless-shell | 国外 | **85.5** | JS 对照 3/3、Shopify 列表价更完整、单槽 FIFO 零拒绝 | 重页 394/400m;Medium/Amazon 仍拦 | **P3 保真槽(L2 按需 / L3 常驻)** |
| searxng-global | 国外 | **62.0** | 实例稳、181MB burst 安全 | T3 断言 0/5:vless 数据中心 IP 下 Google/DDG/Brave 全 CAPTCHA/429,仅 Bing 且偏题 | **擦线入选**,部署但产品层不承诺多源(见 D2) |
**排除**:playwright-distributed(Redis 硬依赖)、browser-swarm(仅 macOS,不适配 Swarm)、Browserless(官方建议 4GB 档,重)、Jina reader:oss(捆绑 Chrome+LibreOffice;云端出境)、FerrumMCP/firefox-docker-mcp(生态弱)、Bouncy(无官方镜像、维护风险,列备选)。
**预留**:Camoufox(强对抗,须住宅代理,150–300MB/实例)→ L4 档。
**强对抗事实**:Amazon WAF 验证页 / Medium Cloudflare / Reddit 匿名 403——本代理池打不过,设计记 `blocked` 交预留档,不加并发硬刚。
复跑入口:`bench/<方案>/run.sh`(无密钥);代理 `bench/proxy/up.sh`(读 `PROXY_SUB_URL`)。
## 6. 任务 6:交付 review
即本文。请你重点过:§2.3 档位表、§5 评分与结论、§7 决策点。
## 7. 决策点(请你拍板)
| # | 决策 | 我的提议 | 依据 |
|---|---|---|---|
| **D1** | 内存档位 | **先按 L0→L2 渐进上线(≤1GB 承诺不变);若渲染互斥/冷启动成为日常痛点,再申请升 L3 1.5GB**。1GB 稳态可维持(占用率见 §2.5),L3 增量是体验与冗余 | §2.2/2.3 实测底账 + §2.5 换算 |
| **D2** | 国外搜索质量路线 | 三选一:**a)** 接受「仅 Bing + 可能偏题」零成本先用;**b)** 补充更优质代理套餐/住宅出口(成本项,质量恢复多源);**c)** 接 Brave Search API 等官方 key(质量好,但 query 出境,须法务确认 + 特权 scope)。提议 a 起步、b 列入采购、c 仅特权 | S3c §2 引擎矩阵 |
| **D3** | 端口与前缀 | **`:8640` + `/bs-api`**(`:8300` 已被 voc-analysis-dev 占用;8640 邻近 WSG 8620 段,无冲突;确认后同步 inventory) | inventory §3.2/§5 |
| **D4** | 域名策略默认姿态 | blocklist + 高危类 deny(白名单档做成可选配置,政企交付再开) | design-arch §5.4 |
| **D5** | Camoufox 强对抗档 | 暂不建;等你确认有 Amazon/Medium 类刚需 + 住宅代理预算再启 L4 | S3c §7 |
| **D6** | MCP 兼容 | 首版仅 2026 Streamable HTTP 无状态;出现旧客户端再加 2025 腿 | research/01 §4.1 |
其余开放问题(SUB-2 容灾订阅、审计留存期、境外 SaaS 特权通道、办法适用性法务判定、scheduler 卷备份演练、amd64 复测、镜像 tag 约定等)见 design-arch §8 O1–O13。
## 8. 产物索引与验收状态
| 产物 | 路径 |
|---|---|
| 架构设计全文(任务1–4) | `docs/design-arch-20260901.md` |
| 调研 5 份 | `.dsh/artifacts/run-20260901-browser-arch/research/` |
| 候选筛选+评分卡 | `.dsh/artifacts/run-20260901-browser-arch/select.md` |
| 代理探活 | `.dsh/artifacts/run-20260901-browser-arch/proxy-probe.md` |
| 实测汇总+原始数据 | `.dsh/artifacts/run-20260901-browser-arch/bench/` + `bench/` |
| 实测计划/模板 | `bench/plan.md` |
| Verify / Reverify / Arch-Review | `.dsh/artifacts/run-20260901-browser-arch/{review,reverify,arch-review}.md` |
验收链(已闭环,各经一轮 ITERATE 修订后复审通过):**S6 Verify PASS → S6 Reverify PASS → S7 Architecture Review PASS**(报告:`.dsh/artifacts/run-20260901-browser-arch/{review,reverify,arch-review}.md`)。