onesvm-browser-server/bench/searxng-cn/run.sh
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

240 lines
8.6 KiB
Bash
Executable file

#!/usr/bin/env bash
# phases: up | wait | inspect | idle | t1 | t5 | down | summarize
set -euo pipefail
unset HTTP_PROXY HTTPS_PROXY ALL_PROXY http_proxy https_proxy all_proxy NO_PROXY no_proxy
ROOT="$(cd "$(dirname "$0")" && pwd)"
cd "$ROOT"
NAME="bench-s3b-searxng-cn"
COMPOSE=(docker compose -p bench-s3b-searxng-cn -f "$ROOT/compose.yml")
RAW="$ROOT/raw"
SAMPLES="$ROOT/samples"
mkdir -p "$RAW/bodies" "$SAMPLES"
LOG="$RAW/commands.log"
phase="${1:-}"
log() {
local ts
ts=$(date -u +%Y-%m-%dT%H:%M:%SZ)
echo "[$ts] $*" | tee -a "$LOG"
}
wait_ready() {
local i code
for i in $(seq 1 90); do
set +e
code=$(curl -sS -o /dev/null -w '%{http_code}' --connect-timeout 2 --max-time 3 -A 'onesvm-bench/s3b' "http://127.0.0.1:18880/" || true)
set -e
if [ "$code" = "200" ] || [ "$code" = "302" ] || [ "$code" = "403" ]; then
# 403 can happen on / without format; try /healthz
set +e
hz=$(curl -sS -o /dev/null -w '%{http_code}' --max-time 3 -A 'onesvm-bench/s3b' "http://127.0.0.1:18880/healthz" || true)
set -e
log "ready http=/=>$code healthz=$hz after ${i}s"
return 0
fi
sleep 1
done
log "ERROR: searxng not ready"
docker logs "$NAME" 2>&1 | tail -80 | tee -a "$LOG" || true
return 1
}
inspect_image() {
python3 - <<PY
import json, subprocess, pathlib
raw = pathlib.Path("$RAW")
meta = {}
mp = raw / "meta.json"
if mp.exists():
meta = json.loads(mp.read_text())
out = subprocess.check_output([
"docker","inspect","--format",
"{{.Name}}\t{{.Image}}\t{{json .Config.Image}}",
"$NAME"
], text=True).strip()
arch = subprocess.check_output(["docker","image","inspect","--format","{{.Architecture}}","docker.io/searxng/searxng:2026.8.29-d226b78bc"], text=True).strip()
digests = subprocess.check_output(["docker","image","inspect","--format","{{json .RepoDigests}}","docker.io/searxng/searxng:2026.8.29-d226b78bc"], text=True).strip()
id_ = subprocess.check_output(["docker","image","inspect","--format","{{.Id}}","docker.io/searxng/searxng:2026.8.29-d226b78bc"], text=True).strip()
meta["image"] = {
"ref": "docker.io/searxng/searxng:2026.8.29-d226b78bc",
"digest": (json.loads(digests) or [id_])[0],
"id": id_,
"architecture": arch,
"inspect_line": out,
}
meta.setdefault("commands", []).append({"ts": __import__("datetime").datetime.utcnow().strftime("%Y-%m-%dT%H:%M:%SZ"), "cmd": "docker inspect $NAME + image"})
mp.write_text(json.dumps(meta, ensure_ascii=False, indent=2))
print(json.dumps(meta["image"], indent=2))
PY
}
case "$phase" in
up)
log "compose up $NAME"
"${COMPOSE[@]}" up -d --no-build
wait_ready
inspect_image
;;
wait)
wait_ready
;;
inspect)
inspect_image
;;
idle)
log "idle sample 5min interval=5 container=$NAME"
STATS_DIR="$RAW" bash "$ROOT/lib/sample_stats.sh" searxng-cn-idle 5 300 "$NAME"
log "idle done lines=$(wc -l < "$RAW/searxng-cn-idle.tsv")"
;;
t1)
log "T1 x5 + session RSS around request 1"
: > "$RAW/t1.jsonl"
STATS_DIR="$RAW" bash "$ROOT/lib/sample_stats.sh" searxng-cn-session 1 0 "$NAME" &
spid=$!
sleep 10
pick_url=""
pick_title=""
pick_cjk=""
for i in 1 2 3 4 5; do
log "T1 request $i"
BODY_OUT="$RAW/bodies/t1-${i}.json" RAW_DIR="$RAW" bash "$ROOT/request.sh" t1 "$i" > "$RAW/t1-${i}.metrics.json"
verdict=$(python3 "$ROOT/eval_t1.py" "$RAW/bodies/t1-${i}.json")
python3 - "$RAW/t1-${i}.metrics.json" "$verdict" "$RAW/t1.jsonl" <<'PY'
import json, sys
m = json.loads(open(sys.argv[1], encoding="utf-8").read())
v = json.loads(sys.argv[2])
m.update(v)
open(sys.argv[3], "a", encoding="utf-8").write(json.dumps(m, ensure_ascii=False) + "\n")
print(json.dumps({"idx": m.get("idx"), "http": m.get("http_code"), "assert_ok": m.get("assert_ok"), "n": m.get("n_results"), "engines": m.get("engines"), "t_total": m.get("t_total")}, ensure_ascii=False))
PY
if [ -z "$pick_url" ]; then
pick_url=$(python3 -c "import json; d=json.load(open('$RAW/bodies/t1-${i}.json',encoding='utf-8'));
import sys
sys.path.insert(0,'$ROOT')
from eval_t1 import eval_body
v=eval_body(open('$RAW/bodies/t1-${i}.json',encoding='utf-8').read());
print(v.get('t2_url') or '')")
pick_title=$(python3 -c "from eval_t1 import eval_body; v=eval_body(open('$RAW/bodies/t1-${i}.json',encoding='utf-8').read()); print(v.get('t2_title') or '')")
pick_cjk=$(python3 -c "from eval_t1 import eval_body; v=eval_body(open('$RAW/bodies/t1-${i}.json',encoding='utf-8').read()); print(v.get('t2_title_cjk4') or '')")
fi
if [ "$i" -eq 1 ]; then
sleep 10
kill "$spid" 2>/dev/null || true
wait "$spid" 2>/dev/null || true
fi
done
kill "$spid" 2>/dev/null || true
wait "$spid" 2>/dev/null || true
if [ -z "$pick_url" ]; then
pick_url="https://www.gov.cn/zhengce/2021-03/13/content_5592681.htm"
pick_title="国民经济和社会发展第十四个五年规划和2035年远景目标纲要"
pick_cjk="国民经社"
source="fallback"
else
source="t1"
fi
python3 - "$RAW/meta.json" "$pick_url" "$pick_title" "$pick_cjk" "$source" <<'PY'
import json, sys, pathlib
p = pathlib.Path(sys.argv[1])
meta = json.loads(p.read_text()) if p.exists() else {}
meta["t2_pick"] = {"url": sys.argv[2], "title": sys.argv[3], "title_cjk4": sys.argv[4], "source": sys.argv[5]}
p.write_text(json.dumps(meta, ensure_ascii=False, indent=2))
print(json.dumps(meta["t2_pick"], ensure_ascii=False, indent=2))
PY
python3 - <<PY
import json, pathlib
root = pathlib.Path("$SAMPLES")
raw = pathlib.Path("$RAW/bodies")
n = 0
for i in (1,2,3):
src = raw / f"t1-{i}.json"
if not src.exists():
continue
data = json.loads(src.read_text(encoding="utf-8"))
slim = {
"query": data.get("query"),
"number_of_results": data.get("number_of_results"),
"unresponsive_engines": data.get("unresponsive_engines"),
"results": []
}
for item in (data.get("results") or [])[:8]:
slim["results"].append({
"title": (item.get("title") or "")[:160],
"url": (item.get("url") or "")[:220],
"content": (item.get("content") or "")[:240],
"engine": item.get("engine"),
})
(root / f"t1-{i}.excerpt.json").write_text(json.dumps(slim, ensure_ascii=False, indent=2), encoding="utf-8")
n += 1
print(f"samples={n}")
PY
log "T1 done pick_url=$pick_url source=$source"
;;
t5)
log "T5 burst 60 concurrent"
: > "$RAW/t5.jsonl"
STATS_DIR="$RAW" bash "$ROOT/lib/sample_stats.sh" searxng-cn-t5 1 0 "$NAME" &
spid=$!
t5start=$(date +%s)
seq 1 60 | xargs -P 60 -I{} bash -c '
unset HTTP_PROXY HTTPS_PROXY ALL_PROXY http_proxy https_proxy all_proxy NO_PROXY no_proxy
ROOT="'"$ROOT"'"
RAW="'"$RAW"'"
i="$1"
BODY_OUT="$RAW/bodies/t5-${i}.json" RAW_DIR="$RAW" bash "$ROOT/request.sh" t5-once "$i" > "$RAW/t5-${i}.metrics.json"
' _ {}
t5end=$(date +%s)
log "T5 curls finished wall=$((t5end-t5start))s; cooling 15s"
sleep 15
kill "$spid" 2>/dev/null || true
wait "$spid" 2>/dev/null || true
python3 - <<PY
import json, pathlib, subprocess
root = pathlib.Path("$ROOT")
raw = pathlib.Path("$RAW")
out = raw / "t5.jsonl"
lines = []
for i in range(1, 61):
mp = raw / f"t5-{i}.metrics.json"
bp = raw / "bodies" / f"t5-{i}.json"
if not mp.exists():
continue
m = json.loads(mp.read_text(encoding="utf-8"))
if bp.exists():
v = json.loads(subprocess.check_output(["python3", str(root/"eval_t1.py"), str(bp)], text=True))
m.update(v)
else:
m["assert_ok"] = False
m["fail_class"] = "timeout"
m["note"] = "no_body"
lines.append(m)
out.write_text("".join(json.dumps(x, ensure_ascii=False)+"\n" for x in lines), encoding="utf-8")
ok = sum(1 for x in lines if x.get("assert_ok"))
print(f"t5 n={len(lines)} ok={ok}")
PY
oom=$(docker inspect --format '{{.State.OOMKilled}} {{.State.Status}}' "$NAME" 2>/dev/null || echo "unknown unknown")
log "T5 oom/status=$oom"
python3 - "$RAW/meta.json" "$oom" <<'PY'
import json, sys, pathlib
p = pathlib.Path(sys.argv[1])
meta = json.loads(p.read_text()) if p.exists() else {}
parts = sys.argv[2].split()
meta["oom"] = parts[0].lower() == "true"
meta["container_status_after_t5"] = sys.argv[2]
p.write_text(json.dumps(meta, ensure_ascii=False, indent=2))
PY
;;
down)
log "compose down"
"${COMPOSE[@]}" down --remove-orphans || true
docker rm -f "$NAME" 2>/dev/null || true
;;
summarize)
python3 "$ROOT/summarize.py" "$ROOT"
;;
*)
echo "usage: $0 up|wait|inspect|idle|t1|t5|down|summarize" >&2
exit 2
;;
esac