docs: 联网搜索服务架构方案全套(plan-final/design-arch/选型决策/整合导览/MCP文档/部署预设/联调手册) bench: 5 方案 + 代理 + 站点矩阵本机实测工程(无密钥) 部署目标:primary mgr1 先行测试(待批准后执行)
488 lines
19 KiB
Markdown
488 lines
19 KiB
Markdown
# S3b / S3c 本机 Docker 实测计划
|
||
|
||
- 对应筛选:`.dsh/artifacts/run-20260901-browser-arch/select.md`
|
||
- 主机假设:darwin arm64 / Docker Desktop 29.4.0(与 S3a 相同)
|
||
- 代理:先 `export PROXY_SUB_URL`(只从 `.dsh/artifacts/proxy-subscriptions.local.md` SUB-1 注入),再 `bash bench/proxy/up.sh`。国外组复用 `http://127.0.0.1:17890`。**脚本与 JSON 禁止出现订阅 URL / uuid / password。**
|
||
- 同时运行 **候选容器 ≤3**。`bench-proxy-mihomo` 算基建,不占 3 席。
|
||
- 每方案第一次发业务请求前:**idle 采样 5 分钟**。
|
||
|
||
## 0. 目录骨架(S3b 建,本文件只约定)
|
||
|
||
```
|
||
bench/
|
||
lib/
|
||
sample_stats.sh # docker stats 循环
|
||
curl_time.sh # 单次计时
|
||
summarize.py # 读 raw → results.json
|
||
searxng-cn/ compose.yml settings.yml request.sh results.json
|
||
trafilatura-http/ compose.yml Dockerfile app.py request.sh results.json
|
||
searxng-global/ compose.yml settings.yml request.sh results.json
|
||
lightpanda/ compose.yml request.sh results.json
|
||
chrome-headless-shell/ compose.yml request.sh results.json
|
||
raw/ # 各批次 stats-*.tsv 与 curl-*.jsonl(可选)
|
||
```
|
||
|
||
`results.json` 顶层必须能被评分卡直接引用,字段见 §4。
|
||
|
||
---
|
||
|
||
## 1. 统一采集规范
|
||
|
||
### 1.1 容器命名
|
||
|
||
| 方案 | 容器名 | 宿主机端口 |
|
||
|---|---|---|
|
||
| searxng-cn | `bench-searxng-cn` | 18880 → 8080 |
|
||
| trafilatura-http | `bench-trafilatura` | 18881 → 8080 |
|
||
| searxng-global | `bench-searxng-global` | 18882 → 8080 |
|
||
| lightpanda | `bench-lightpanda` | 19222 → 9222 |
|
||
| chrome-headless-shell | `bench-headless-shell` | 19223 → 9222 |
|
||
| 代理(基建) | `bench-proxy-mihomo` | 17890 / 19090(已有) |
|
||
|
||
### 1.2 docker stats
|
||
|
||
`bench/lib/sample_stats.sh` 约定(S3b 实现时按此抄):
|
||
|
||
```bash
|
||
# 用法: sample_stats.sh <label> <interval_s> <duration_s> <container...>
|
||
# 例: bash bench/lib/sample_stats.sh searxng-cn-idle 5 300 bench-searxng-cn
|
||
label="$1"; interval="$2"; duration="$3"; shift 3
|
||
out="bench/raw/${label}.tsv"
|
||
echo -e "ts_iso\tname\tmem_bytes\tmem_limit_bytes\tcpu_pct" > "$out"
|
||
end=$(( $(date +%s) + duration ))
|
||
while [ "$(date +%s)" -lt "$end" ]; do
|
||
ts=$(date -u +%Y-%m-%dT%H:%M:%SZ)
|
||
docker stats --no-stream --format '{{.Name}}\t{{.MemUsage}}\t{{.CPUPerc}}' "$@" \
|
||
| while IFS=$'\t' read -r name mem cpu; do
|
||
# MemUsage 形如 "85.2MiB / 256MiB" —— summarize.py 解析
|
||
printf '%s\t%s\t%s\t%s\n' "$ts" "$name" "$mem" "$cpu" >> "$out"
|
||
done
|
||
sleep "$interval"
|
||
done
|
||
```
|
||
|
||
- idle:`interval=5` `duration=300`(5 分钟),**期间禁止发业务请求**。
|
||
- 单会话:发请求前 10s 起采到请求结束后 10s,`interval=1`。
|
||
- T5 burst:从 t=0 到全部结束 + 15s,`interval=1`。
|
||
- 指标:`idle_mb` = 5 min 中位;`session_delta_mb` = 单会话峰值 − idle 中位;`burst_peak_mb` = burst 窗口最大。
|
||
|
||
辅助(可选,更准 RSS):
|
||
|
||
```bash
|
||
docker exec "$c" sh -c 'cat /sys/fs/cgroup/memory.current 2>/dev/null || cat /sys/fs/cgroup/memory/memory.usage_in_bytes'
|
||
```
|
||
|
||
cgroup 读不到就只信 `docker stats`,在 `results.json` 标 `rss_source=docker_stats`。
|
||
|
||
### 1.3 curl 计时
|
||
|
||
```bash
|
||
# bench/lib/curl_time.sh
|
||
# 环境: URL METHOD DATA PROXY(可选)
|
||
extra=()
|
||
[ -n "${PROXY:-}" ] && extra+=(-x "$PROXY")
|
||
code_file=$(mktemp)
|
||
body_file=$(mktemp)
|
||
metrics=$(curl -sS "${extra[@]}" -X "${METHOD:-GET}" \
|
||
-o "$body_file" \
|
||
-w '%{http_code} %{time_namelookup} %{time_connect} %{time_starttransfer} %{time_total} %{size_download}' \
|
||
--connect-timeout 10 --max-time "${MAX_TIME:-30}" \
|
||
-A 'onesvm-bench/s3b' \
|
||
${DATA:+-H 'Content-Type: application/json' -d "$DATA"} \
|
||
"$URL")
|
||
# 输出一行 JSON 到 stdout,body 路径给断言脚本
|
||
```
|
||
|
||
写入 jsonl 的字段:`ts, scheme, template, http_code, t_namelookup, t_connect, ttfb, t_total, bytes, assert_ok, note`。
|
||
|
||
p50 / p95:对该模板全部 `t_total` 排序后取分位(线性插值即可)。**不要**用 Excel 手估。
|
||
|
||
### 1.4 镜像 pin 与 digest
|
||
|
||
每个 `compose.yml` 写死 `select.md` 的 tag,启动后:
|
||
|
||
```bash
|
||
docker inspect --format '{{.Name}} {{.Image}} {{index .RepoDigests 0}}' "$c"
|
||
```
|
||
|
||
写入 `results.json.image`。拉不到 Hub 时用 `docker load`(见 select.md §5),不要改 pin 成 `latest`。
|
||
|
||
### 1.5 清理
|
||
|
||
每批次结束:
|
||
|
||
```bash
|
||
docker rm -f bench-searxng-cn bench-trafilatura bench-searxng-global bench-lightpanda bench-headless-shell || true
|
||
# 代理只在当天国外批次全部结束时 down
|
||
# bash bench/proxy/down.sh
|
||
```
|
||
|
||
---
|
||
|
||
## 2. 五套需求模板
|
||
|
||
### T1 国内关键词搜索 — 方案 `searxng-cn`
|
||
|
||
**请求(可执行):**
|
||
|
||
```bash
|
||
curl -sS -G 'http://127.0.0.1:18880/search' \
|
||
--data-urlencode 'q=跨境电商 出口退税 政策 2026' \
|
||
--data-urlencode 'format=json' \
|
||
--data-urlencode 'language=zh-CN' \
|
||
--data-urlencode 'categories=general'
|
||
```
|
||
|
||
**断言(脚本硬判):**
|
||
|
||
1. HTTP 200。
|
||
2. `results` 为数组且 `length >= 5`。
|
||
3. 前 10 条中,至少 5 条同时具备非空 `title`、非空 `url`(`http` 开头)、非空 `content`(strip 后 ≥ 8 字符)。
|
||
4. `results[*].engine` 去重后 **≥ 2**(允许百度+必应,或搜狗+360)。若 `unresponsive_engines` 含某引擎,记入 `note`,不单独失败。
|
||
5. 至少 1 条 `url` host 匹配 `gov.cn|customs.gov.cn|chinatax.gov.cn|mofcom.gov.cn|yidaiyilu.gov.cn|news.cn|people.com.cn|xinhuanet.com`(政策向)。不满足则 `assert_ok=false` 但把实际 host 列表留下,供人工改阈值。
|
||
|
||
**失败分类:** `json_403`(忘开 formats)/ `engine_outage` / `thin_snippets` / `timeout`。
|
||
|
||
**质量抽检(人工 2 分钟):** 打开第 1 条 URL,标题是否与结果 `title` 同主题。
|
||
|
||
---
|
||
|
||
### T2 国内页面正文提取 — 方案 `trafilatura-http`
|
||
|
||
**URL 选择顺序:**
|
||
|
||
1. 优先用 T1 结果里第一条 host ∈ `gov.cn|news.cn|people.com.cn` 且 GET 200 的文章 URL。
|
||
2. 回退固定页(公开、长期稳定、有导航壳):
|
||
|
||
```
|
||
https://www.gov.cn/zhengce/2021-03/13/content_5592681.htm
|
||
```
|
||
|
||
(《国民经济和社会发展第十四个五年规划和2035年远景目标纲要》。若 2026 年该 URL 变更,改用 T1 第一条 gov.cn。)
|
||
|
||
**请求:**
|
||
|
||
```bash
|
||
# 约定包装 API(S3b 实现 app.py 时遵守)
|
||
curl -sS -X POST 'http://127.0.0.1:18881/v1/read' \
|
||
-H 'Content-Type: application/json' \
|
||
-d '{"url":"https://www.gov.cn/zhengce/2021-03/13/content_5592681.htm","formats":["markdown"],"max_chars":20000}'
|
||
```
|
||
|
||
包装器内部:`trafilatura.fetch_url` + `trafilatura.extract(..., output_format="markdown", include_comments=False, include_tables=True, favor_precision=True)`。
|
||
|
||
**断言:**
|
||
|
||
1. HTTP 200,`ok=true`,`markdown` 长度 ≥ 800。
|
||
2. `title` 非空。
|
||
3. **无导航/广告残渣(规则):** `markdown` 不得匹配下列任一条(忽略大小写):
|
||
- `网站地图|设为首页|加入收藏|政务微信|客户端下载|无障碍浏览`
|
||
- 连续导航口吻:`首页\s*[>|/]\s*政策` 且出现 ≥ 3 次面包屑分隔
|
||
4. **正文在:** 须同时命中 `十四五` 与 `2035`(回退 URL);若改用 T1 URL,改为命中该条 T1 `title` 的前 4 个汉字。
|
||
5. 不得把整页当 HTML 倾倒:`markdown` 中 `<div` / `<script` 出现次数 = 0。
|
||
6. 若 `truncated=true`,`char_count` 必须 = `max_chars`。
|
||
|
||
**失败分类:** `fetch_fail` / `empty_extract` / `nav_residue` / `html_dump`。
|
||
|
||
---
|
||
|
||
### T3 国外关键词搜索 — 方案 `searxng-global`(经代理)
|
||
|
||
**前置:** `bench-proxy-mihomo` 已 up;SearXNG 容器 `HTTP_PROXY=http://host.docker.internal:17890`(或 settings `outgoing.proxies`)。
|
||
|
||
**请求:**
|
||
|
||
```bash
|
||
curl -sS -G 'http://127.0.0.1:18882/search' \
|
||
--data-urlencode 'q=best bluetooth earbuds 2026 reddit' \
|
||
--data-urlencode 'format=json' \
|
||
--data-urlencode 'language=en-US' \
|
||
--data-urlencode 'categories=general'
|
||
```
|
||
|
||
**断言:**
|
||
|
||
1. HTTP 200,`results.length >= 5`。
|
||
2. `results[*].engine` 去重 ≥ 2(多源聚合)。
|
||
3. `results[*].url` host 去重 ≥ 3。
|
||
4. 至少 1 条 URL host 为 `reddit.com` 或 `redd.it`,**或** `title|content` 含 `reddit`(小写)。
|
||
说明:S3a 对 `https://www.reddit.com/` 裸 GET 为 **403**,本模板走元搜索,不直接打 reddit 首页。
|
||
5. 记录 `unresponsive_engines`。Google 单独 403/验证码 → `note=google_captcha`,只要其余引擎撑住断言 1–4 仍算通过。
|
||
|
||
**失败分类:** `proxy_down`(先 `curl -x http://127.0.0.1:17890 https://www.google.com/generate_204` 期望 204)/ `single_engine` / `no_reddit_ref`。
|
||
|
||
---
|
||
|
||
### T4 国外 JS 渲染页提取 — `lightpanda` 主测,`chrome-headless-shell` 对照
|
||
|
||
**页面(按序,记录每一档):**
|
||
|
||
| 档 | URL | 目的 |
|
||
|---|---|---|
|
||
| T4-ctrl | `https://quotes.toscrape.com/js/` | 无 WAF 的 JS 对照:至少 3 条 quote 文本 |
|
||
| T4-shop | `https://www.allbirds.com/products/mens-wool-runners` | Shopify 公开商品:标题 + 价格字段 |
|
||
| T4-amz | `https://www.amazon.com/dp/B08N5WRWNW` | Amazon 公开商品页(Echo Dot 常见 ASIN)。**预期反爬,必须记。** |
|
||
|
||
不要用 Medium 登录墙当主断言。若 Allbirds 404,改 `https://www.allbirds.com/` 首页抽首个商品价。
|
||
|
||
**驱动约定(两方案同一脚本,只换 CDP 端点):**
|
||
|
||
- Lightpanda:`http://127.0.0.1:19222`(CDP)。
|
||
- shell:`http://127.0.0.1:19223`。
|
||
- 实现可用 **Playwright** `connectOverCDP` 或 **chromedp**;不要再在客户端拉起本地 Chrome。
|
||
- 导航超时 25s;`waitUntil=networkidle` 最多 8s,超时则退 `domcontentloaded` + 固定 sleep 2s。
|
||
- 代理:容器启动已带 `--proxy-server` / `HTTP_PROXY`,客户端不要套两层。
|
||
|
||
**抽取:**
|
||
|
||
```
|
||
title = document.title
|
||
text = document.body.innerText.slice(0, 8000)
|
||
# T4-shop / T4-amz:
|
||
price = meta[itemprop=price] || [class*="price"] 首个匹配的 innerText
|
||
jsonld = script[type="application/ld+json"] 里 Offers.price(有则优先)
|
||
```
|
||
|
||
**断言:**
|
||
|
||
| 档 | 通过条件 |
|
||
|---|---|
|
||
| T4-ctrl | `text` 含 `quote` 或作者名;或 ≥3 个 `.quote` 节点。失败 = 内核 JS 基本不可用。 |
|
||
| T4-shop | `title` 含 `Wool Runner` 或 `Allbirds`;`price` 匹配 `\$[0-9]` 或 `jsonld` 有数字价。 |
|
||
| T4-amz | 能解析 `title` 且不像验证码页;`price` 可选。若 title/text 匹配 `(?i)robot|captcha|sorry|click the button|continue shopping` → `blocked=true`,**不记方案失败**,记 `waf`。 |
|
||
|
||
**反爬记录(强制字段):** `http_status_in_page`, `blocked`, `challenge_vendor`(`cloudflare|datadome|akamai|amazon|unknown|none`), `final_url`。
|
||
|
||
评分:T4-ctrl 失败重创质量分;T4-amz 拦截只进 `note`,不把成功率打到 0。
|
||
|
||
---
|
||
|
||
### T5 60 会话 burst
|
||
|
||
**语义:** 60 = **同时涌入的请求数**(队列深度),不是 60 个 Chromium。浏览器方案 `CONCURRENT=1`(shell)或 Lightpanda 单进程多客户端;超槽位必须排队或 429,禁止把 60 个 Chrome 拉起来。
|
||
|
||
| 方案 | 涌入内容 | 并发模型 |
|
||
|---|---|---|
|
||
| searxng-cn | 60× T1 同 query | 直接打 SearXNG,无自研队列 |
|
||
| trafilatura-http | 60× T2 同 URL | 包装器内 semaphore=8(避免 60 条 TCP 打爆目标站) |
|
||
| searxng-global | 60× T3 同 query | 同 CN |
|
||
| lightpanda | 60× T4-ctrl | 客户端最多 4 个并行 CDP 导航,其余等(模拟网关 QUEUED) |
|
||
| chrome-headless-shell | 60× T4-ctrl | **并行度 1**,其余 FIFO;超时 30s/个则记 fail 继续 |
|
||
|
||
**发射:**
|
||
|
||
```bash
|
||
# 60 个后台 curl 同一秒涌入(搜索类)
|
||
seq 60 | xargs -P 60 -I{} bash bench/lib/curl_time.sh
|
||
```
|
||
|
||
Trafilatura / 浏览器不要用 `-P 60` 打目标站;用本机队列脚本:60 个任务入队,worker 池 = 上表并行度。
|
||
|
||
**记录:**
|
||
|
||
- 排队:首个完成 ttfb、最后完成 `t_total`、是否出现 429/503。
|
||
- 成功率:断言通过 / 60。
|
||
- p50 / p95:60 个 `t_total`。
|
||
- `burst_peak_mb`、是否 OOM(`docker inspect .State.OOMKilled`)。
|
||
- 浏览器方案若未实现网关,用脚本侧 FIFO 代替,`results.json.queue_impl=client_fifo`,并在 note 写「生产应是 SQLite WAL + CONCURRENT」。
|
||
|
||
**断言(方案级):**
|
||
|
||
1. 容器未退出、`OOMKilled=false`。
|
||
2. 搜索类成功率 ≥ 85%;读取/JS ≥ 70%(T4-ctrl)。
|
||
3. 峰值内存:搜索/trafilatura < 400 MB;lightpanda < 256 MB cgroup;shell < 400 MB cgroup。超限记 `mem_over`,综合评分按评分卡 0 档。
|
||
|
||
---
|
||
|
||
## 3. 批次安排(本机 ≤3 候选容器)
|
||
|
||
每方案:**up → idle 5 min → 单模板 5 次(取中位)→ 该方案 T5 → down**。不要跨方案复用未清的浏览器进程。
|
||
|
||
| 批次 | 候选容器 | 基建 | 做的模板 | 预计墙钟 |
|
||
|---|---|---|---|---|
|
||
| **A 国内** | `searxng-cn` + `trafilatura-http` | 无 | T1(cn)→ T2(用 T1 URL)→ T5 cn → T5 trafilatura | 40–50 min |
|
||
| **B 国外搜索+轻渲染** | `searxng-global` + `lightpanda` | `bench-proxy-mihomo` | T3 → T4 三档(panda)→ T5 global → T5 panda | 50–70 min |
|
||
| **C 保真对照** | `chrome-headless-shell` + `lightpanda`(已有数据可不再 idle 5 min,若刚 down 过则重做 idle) | 同一代理 | T4 三档(shell)→ T5 shell | 40–60 min |
|
||
| **D(可选)合成冒烟** | `searxng-cn` + `searxng-global` + `trafilatura-http` | 代理 | 各 1 次 T1/T2/T3,只看三容器 RSS 之和 | 15 min |
|
||
|
||
批次 A 与 B 不可与 C 重叠。D 不得加入 shell。
|
||
|
||
**代理:** 批次 B 开始时 `up.sh`,C 结束或当天收工时 `down.sh`。切换节点(可选):
|
||
|
||
```bash
|
||
curl -sS -X PUT "http://127.0.0.1:19090/proxies/%F0%9F%9A%80%E8%8A%82%E7%82%B9%E9%80%89%E6%8B%A9" \
|
||
-H 'Content-Type: application/json' \
|
||
-d '{"name":"🇺🇸美国圣何塞02 | 三网推荐"}'
|
||
```
|
||
|
||
节点名以 `bench/proxy/probe-results.json` 为准。
|
||
|
||
---
|
||
|
||
## 4. 各方案 compose / 请求要点
|
||
|
||
### 4.1 `bench/searxng-cn/compose.yml`
|
||
|
||
```yaml
|
||
services:
|
||
searxng:
|
||
image: docker.io/searxng/searxng:2026.8.29-d226b78bc
|
||
container_name: bench-searxng-cn
|
||
ports: ["18880:8080"]
|
||
volumes:
|
||
- ./settings.yml:/etc/searxng/settings.yml:ro
|
||
environment:
|
||
- SEARXNG_BASE_URL=http://localhost:18880/
|
||
mem_limit: 192m
|
||
restart: "no"
|
||
```
|
||
|
||
`request.sh t1|t5`。settings 见 `select.md` §1.1。
|
||
|
||
### 4.2 `bench/trafilatura-http/`
|
||
|
||
`Dockerfile`:
|
||
|
||
```
|
||
FROM python:3.12-slim-bookworm
|
||
RUN pip install --no-cache-dir trafilatura==2.2.0
|
||
WORKDIR /app
|
||
COPY app.py .
|
||
EXPOSE 8080
|
||
CMD ["python", "-u", "app.py"]
|
||
```
|
||
|
||
`app.py`:stdlib `http.server` 即可,避免再拉 Flask。只实现 `POST /v1/read`。`mem_limit: 128m`。
|
||
|
||
国外复用时加:
|
||
|
||
```yaml
|
||
environment:
|
||
HTTP_PROXY: http://host.docker.internal:17890
|
||
HTTPS_PROXY: http://host.docker.internal:17890
|
||
NO_PROXY: 127.0.0.1,localhost
|
||
```
|
||
|
||
本轮 T2 **不要**开代理。
|
||
|
||
### 4.3 `bench/searxng-global/compose.yml`
|
||
|
||
同 4.1,端口 18882,容器名 `bench-searxng-global`,`extra_hosts: ["host.docker.internal:host-gateway"]`,环境或 settings 走 17890。`mem_limit: 192m`。
|
||
|
||
### 4.4 `bench/lightpanda/compose.yml`
|
||
|
||
```yaml
|
||
services:
|
||
lightpanda:
|
||
image: docker.io/lightpanda/browser:0.3.7
|
||
container_name: bench-lightpanda
|
||
command: ["lightpanda", "serve", "--host", "0.0.0.0", "--port", "9222"]
|
||
ports: ["19222:9222"]
|
||
extra_hosts: ["host.docker.internal:host-gateway"]
|
||
environment:
|
||
HTTP_PROXY: http://host.docker.internal:17890
|
||
HTTPS_PROXY: http://host.docker.internal:17890
|
||
mem_limit: 256m
|
||
```
|
||
|
||
`request.sh`:Node 或 Python Playwright `connectOverCDP('http://127.0.0.1:19222')`。
|
||
|
||
### 4.5 `bench/chrome-headless-shell/compose.yml`
|
||
|
||
```yaml
|
||
services:
|
||
shell:
|
||
image: docker.io/chromedp/headless-shell:151.0.7922.109
|
||
container_name: bench-headless-shell
|
||
ports: ["19223:9222"]
|
||
extra_hosts: ["host.docker.internal:host-gateway"]
|
||
command:
|
||
- --no-sandbox
|
||
- --remote-debugging-address=0.0.0.0
|
||
- --remote-debugging-port=9222
|
||
- --proxy-server=http://host.docker.internal:17890
|
||
shm_size: "128m"
|
||
mem_limit: 400m
|
||
```
|
||
|
||
镜像 ENTRYPOINT 已是 headless-shell 时,`command` 只追加 flag。S3b 若启动即退,把 `docker logs` 贴进 `results.json.note`(**未验证** Desktop 对 151.x arm64)。
|
||
|
||
---
|
||
|
||
## 5. `results.json` schema
|
||
|
||
每个方案一份:
|
||
|
||
```json
|
||
{
|
||
"scheme": "searxng-cn",
|
||
"group": "domestic",
|
||
"image": {"ref": "docker.io/searxng/searxng:2026.8.29-d226b78bc", "digest": "sha256:…"},
|
||
"probed_at": "2026-09-01T00:00:00+08:00",
|
||
"rss_source": "docker_stats",
|
||
"idle_mb_p50": null,
|
||
"session_delta_mb": null,
|
||
"burst_peak_mb": null,
|
||
"templates": {
|
||
"T1": {
|
||
"n": 5,
|
||
"success": 0,
|
||
"http_codes": [],
|
||
"p50_s": null,
|
||
"p95_s": null,
|
||
"assert_ok": false,
|
||
"note": ""
|
||
}
|
||
},
|
||
"t5": {
|
||
"n": 60,
|
||
"parallelism": 60,
|
||
"queue_impl": "none",
|
||
"success": 0,
|
||
"p50_s": null,
|
||
"p95_s": null,
|
||
"oom": false,
|
||
"http_429": 0,
|
||
"http_503": 0
|
||
},
|
||
"t4_waf": [],
|
||
"scorecard": {
|
||
"mem": null, "quality": null, "stability": null, "latency": null, "ops": null, "total": null
|
||
}
|
||
}
|
||
```
|
||
|
||
T4 的 `t4_waf` 元素:`{tier, url, blocked, vendor, http_status_in_page}`。
|
||
|
||
填完后把数字抄回 `select.md` §4.7。本文件不改 select 以外的架构文档。
|
||
|
||
---
|
||
|
||
## 6. S3b / S3c 执行顺序(可当 checklist)
|
||
|
||
**S3b(国内,可无代理)**
|
||
|
||
1. `docker pull` 或 `load`:`searxng/searxng:2026.8.29-d226b78bc`、`python:3.12-slim-bookworm`。
|
||
2. 批次 A:建 `searxng-cn` + `trafilatura-http` 目录与 compose。
|
||
3. 只起 `bench-searxng-cn` → idle 5 min → T1 ×5 → T5。
|
||
4. 保持 cn 或 down 后起 `bench-trafilatura`(同时 ≤2)→ idle 5 min → T2 ×5(URL 来自 T1)→ T5。
|
||
5. 写两份 `results.json`。两容器同时存在时再采 30s,看 RSS 之和(P0 冒烟)。
|
||
|
||
**S3c(国外,必须代理)**
|
||
|
||
1. `bash bench/proxy/up.sh`;`curl -x http://127.0.0.1:17890 -o /dev/null -w '%{http_code}\n' https://www.google.com/generate_204` 期望 204。
|
||
2. pull/load:`lightpanda/browser:0.3.7`、`chromedp/headless-shell:151.0.7922.109`。
|
||
3. 批次 B:global idle → T3 ×5 → T5;panda idle → T4 三档各 3 次 → T5-ctrl。
|
||
4. 批次 C:down panda(或留着对照但 **不要** 同时 T5)→ shell idle → T4 三档 → T5-ctrl。
|
||
5. `down.sh`。写 `results.json` + 回填评分卡。
|
||
|
||
密钥扫描(收工):`rg -n 'uuid:|password:|PROXY_SUB_URL=http' bench` 应无节点凭据。
|
||
|
||
---
|
||
|
||
## 7. 本机注意
|
||
|
||
- Apple Silicon 必须拉 **arm64** digest。`docker image inspect --format '{{.Architecture}}'` 若为 `amd64` 会走 qemu,内存与延迟作废,重拉 `--platform linux/arm64`。
|
||
- `host.docker.internal` 在 Docker Desktop 可用;若不通,改 `172.17.0.1` 或 `host-gateway`,记入 note。
|
||
- 目标站限流:T2/T4 单 URL 5 次 + T5 会打同一 host。Trafilatura T5 并行度 ≤8;Amazon T4 每方案最多 3 次,禁止 T5 打 Amazon。
|
||
- 合规:只打公开页;不登录、不绕验证码、不采集个人数据。拦截页当 `blocked`,不当成功正文。
|