docs: 联网搜索服务架构方案全套(plan-final/design-arch/选型决策/整合导览/MCP文档/部署预设/联调手册) bench: 5 方案 + 代理 + 站点矩阵本机实测工程(无密钥) 部署目标:primary mgr1 先行测试(待批准后执行)
173 lines
5.7 KiB
Bash
Executable file
173 lines
5.7 KiB
Bash
Executable file
#!/usr/bin/env bash
|
||
# searxng-global full S3c run: pull → up → idle 5min → T3×5 + engine matrix → T5 → summarize
|
||
set -euo pipefail
|
||
ROOT="$(cd "$(dirname "$0")" && pwd)"
|
||
# shellcheck disable=SC1091
|
||
source "$ROOT/_lib.sh"
|
||
NAME="bench-s3c-searxng-global"
|
||
IMG="docker.io/searxng/searxng:2026.8.29-d226b78bc"
|
||
RAW="$ROOT/raw"
|
||
SAMP="$ROOT/samples"
|
||
mkdir -p "$RAW" "$SAMP"
|
||
exec > >(tee -a "$RAW/run.log") 2>&1
|
||
|
||
log "=== searxng-global S3c start cwd=$ROOT ==="
|
||
ensure_image "$IMG" "$RAW/pull.how"
|
||
PULL_HOW="$(cat "$RAW/pull.how" 2>/dev/null || echo unknown)"
|
||
|
||
log "compose down leftover"
|
||
docker rm -f "$NAME" >/dev/null 2>&1 || true
|
||
|
||
log "docker compose up -d (project bench-s3c-searxng-global)"
|
||
(cd "$ROOT" && docker compose -p bench-s3c-searxng-global up -d --force-recreate)
|
||
|
||
log "wait /healthz"
|
||
if ! wait_http "http://127.0.0.1:18882/healthz" 60; then
|
||
log "healthz failed; try /"
|
||
wait_http "http://127.0.0.1:18882/" 20 || true
|
||
docker logs --tail 80 "$NAME" | tee "$RAW/container-start.log" || true
|
||
fi
|
||
|
||
ARCH="$(docker image inspect --format '{{.Architecture}}' "$IMG")"
|
||
DIGEST="$(docker inspect --format '{{index .RepoDigests 0}}' "$NAME" 2>/dev/null || true)"
|
||
IID="$(docker inspect --format '{{.Image}}' "$NAME")"
|
||
log "image arch=$ARCH digest=$DIGEST id=$IID pull=$PULL_HOW"
|
||
|
||
# proxy egress check from HOST (same pool the container uses)
|
||
PROXY_CODE="$(curl -sS -o /dev/null -w '%{http_code}' --connect-timeout 10 --max-time 20 \
|
||
-x http://127.0.0.1:17890 -A onesvm-bench/s3c \
|
||
https://www.google.com/generate_204 || true)"
|
||
log "proxy generate_204 via 127.0.0.1:17890 http=$PROXY_CODE"
|
||
|
||
# also check container can resolve host.docker.internal
|
||
HOST_RES="$(docker exec "$NAME" getent hosts host.docker.internal 2>/dev/null || docker exec "$NAME" sh -c 'python3 -c "import socket;print(socket.gethostbyname(\"host.docker.internal\"))"' 2>/dev/null || echo unresolved)"
|
||
log "container host.docker.internal => $HOST_RES"
|
||
|
||
log "idle 300s interval=5 (no business traffic)"
|
||
sample_stats "$RAW/idle.tsv" 5 300 "$NAME"
|
||
log "idle done lines=$(($(wc -l < "$RAW/idle.tsv") - 1))"
|
||
|
||
# session window: 10s before first request through 10s after last
|
||
SENT="$RAW/session.done"
|
||
rm -f "$SENT"
|
||
sample_until_file "$RAW/session.tsv" 1 "$SENT" 10 "$NAME" &
|
||
STAT_PID=$!
|
||
sleep 10
|
||
|
||
: > "$RAW/t3.jsonl"
|
||
: > "$RAW/t3-engines.jsonl"
|
||
log "T3 x5 q='best bluetooth earbuds 2026 reddit'"
|
||
for i in 1 2 3 4 5; do
|
||
log "T3 trial $i"
|
||
set +e
|
||
line="$(bash "$ROOT/request.sh" t3 2>"$RAW/t3-excerpt-$i.json")"
|
||
rc=$?
|
||
set -e
|
||
echo "$line" | tee -a "$RAW/t3.jsonl"
|
||
if [[ "$i" -le 3 && -s "$RAW/t3-excerpt-$i.json" ]]; then
|
||
cp "$RAW/t3-excerpt-$i.json" "$SAMP/t3-$i.json"
|
||
fi
|
||
log "T3 trial $i rc=$rc"
|
||
sleep 2
|
||
done
|
||
|
||
log "T3 per-engine matrix google/bing/duckduckgo/brave"
|
||
for eng in google bing duckduckgo brave; do
|
||
log "engine probe $eng"
|
||
set +e
|
||
line="$(bash "$ROOT/request.sh" engine "$eng" 2>"$RAW/t3-engine-$eng.excerpt")"
|
||
rc=$?
|
||
set -e
|
||
echo "$line" | tee -a "$RAW/t3-engines.jsonl"
|
||
cp "$RAW/t3-engine-$eng.excerpt" "$SAMP/t3-engine-$eng.json" 2>/dev/null || true
|
||
log "engine $eng rc=$rc"
|
||
sleep 1
|
||
done
|
||
|
||
touch "$SENT"
|
||
wait "$STAT_PID" || true
|
||
|
||
log "T5 60 concurrent same query"
|
||
SENT5="$RAW/t5.done"
|
||
rm -f "$SENT5"
|
||
sample_until_file "$RAW/t5-stats.tsv" 1 "$SENT5" 15 "$NAME" &
|
||
STAT5_PID=$!
|
||
T5_START=$(date +%s)
|
||
rm -rf "$RAW/t5-parts"
|
||
mkdir -p "$RAW/t5-parts"
|
||
# 60 background curls via request.sh (each writes its own file)
|
||
t5_pids=()
|
||
for i in $(seq 1 60); do
|
||
(
|
||
set +e
|
||
bash "$ROOT/request.sh" t5 >"$RAW/t5-parts/$(printf '%02d' "$i").json" 2>/dev/null
|
||
) &
|
||
t5_pids+=($!)
|
||
done
|
||
for p in "${t5_pids[@]}"; do
|
||
wait "$p" || true
|
||
done
|
||
: > "$RAW/t5.jsonl"
|
||
for f in "$RAW/t5-parts"/*.json; do
|
||
[[ -s "$f" ]] && cat "$f" >> "$RAW/t5.jsonl"
|
||
done
|
||
T5_END=$(date +%s)
|
||
T5_WALL=$((T5_END - T5_START))
|
||
log "T5 wall=${T5_WALL}s"
|
||
touch "$SENT5"
|
||
wait "$STAT5_PID" || true
|
||
|
||
# first 2 t5 excerpts
|
||
python3 - "$RAW/t5.jsonl" "$SAMP" <<'PY'
|
||
import json,sys
|
||
from pathlib import Path
|
||
p=Path(sys.argv[1]); d=Path(sys.argv[2])
|
||
rows=[]
|
||
for line in p.read_text(encoding="utf-8").splitlines():
|
||
if line.strip():
|
||
rows.append(json.loads(line))
|
||
for i,r in enumerate(rows[:2],1):
|
||
(d/f"t5-{i}.json").write_text(json.dumps(r,ensure_ascii=False,indent=2)+"\n",encoding="utf-8")
|
||
print(f"t5 n={len(rows)} ok={sum(1 for r in rows if r.get('assert_ok'))}")
|
||
PY
|
||
|
||
OOM="$(docker inspect --format '{{.State.OOMKilled}}' "$NAME")"
|
||
STATUS="$(docker inspect --format '{{.State.Status}}' "$NAME")"
|
||
log "container status=$STATUS oom=$OOM"
|
||
docker logs --tail 40 "$NAME" | tee "$RAW/container-tail.log" || true
|
||
|
||
python3 - "$RAW/image-meta.json" <<PY
|
||
import json, datetime
|
||
from pathlib import Path
|
||
p = Path("$RAW/image-meta.json")
|
||
meta = {
|
||
"ref": "$IMG",
|
||
"digest": "$DIGEST" if "$DIGEST" != "<no value>" else None,
|
||
"id": "$IID",
|
||
"arch": "$ARCH",
|
||
"pull": "$PULL_HOW",
|
||
"probed_at": datetime.datetime.now().astimezone().isoformat(timespec="seconds"),
|
||
"oom": str("$OOM").lower() == "true",
|
||
"container_status": "$STATUS",
|
||
"t5_wall_s": $T5_WALL,
|
||
"proxy": {
|
||
"mixed": "http://127.0.0.1:17890",
|
||
"container_via": "http://host.docker.internal:17890",
|
||
"generate_204_http": "$PROXY_CODE",
|
||
"host_docker_internal": """$HOST_RES""".strip(),
|
||
"egress_note": "SearXNG outgoing.proxies all:// + HTTP(S)_PROXY; host.docker.internal via extra_hosts host-gateway",
|
||
},
|
||
"commands": [
|
||
"docker compose -p bench-s3c-searxng-global up -d",
|
||
"curl -x http://127.0.0.1:17890 https://www.google.com/generate_204",
|
||
"bash request.sh t3 # x5",
|
||
"bash request.sh engine google|bing|duckduckgo|brave",
|
||
"60x bash request.sh t5",
|
||
],
|
||
"notes": [],
|
||
}
|
||
p.write_text(json.dumps(meta, ensure_ascii=False, indent=2) + "\n", encoding="utf-8")
|
||
PY
|
||
|
||
python3 "$ROOT/summarize.py"
|
||
log "=== searxng-global S3c done ==="
|