#!/bin/bash # 中转全面基线测量。 # # 目的:把"优化到什么程度"变成可量化的数字,而不是感觉。 # 五类指标,每类都记录成功率和耗时分布: # A. 公网 HTTP 可用率(100 次 /v1/health) # B. 长轮询(10 次真实 poll,每次挂 60 秒) # C. 三个发布产物的下载成功率和吞吐 # D. 隧道连接数稳定性 + 重连次数 # E. 静态资源(官网 / 截图 / favicon) # # 用法: bash bench.sh [标签] set -u BASE=${BASE:-https://relay.xxmxxs.top} UA='LanRemote/1.8.1' LABEL=${1:-baseline} OUT="/root/bench_${LABEL}.txt" echo "════════════════════════════════════════════════════════" | tee "$OUT" echo " 中转基准测量 · $LABEL · $(date '+%Y-%m-%d %H:%M:%S')" | tee -a "$OUT" echo "════════════════════════════════════════════════════════" | tee -a "$OUT" echo | tee -a "$OUT" echo "── 隧道配置 ──" | tee -a "$OUT" CAP=$(systemctl show lanremote-tunnel -p ExecStart --value 2>/dev/null | tr ';' '\n' | grep -oE 'argv\[\]=[^ ]*|--[a-z-]+|/[a-z/]*cloudflared' | tr '\n' ' ') grep -oE '\-\-protocol [a-z0-9]+|\-\-ha-connections [0-9]+|\-\-edge-ip-version [0-9]+' /etc/systemd/system/lanremote-tunnel.service 2>/dev/null | tr '\n' ' ' | sed 's/^/ 参数: /' | tee -a "$OUT" echo " 长轮询: $(tail -40 /root/lanremote-relay/relay.log 2>/dev/null | grep -oE '长轮询 [0-9]+ 秒' | tail -1)" | tee -a "$OUT" echo " 连接数: $(curl -s --max-time 5 http://127.0.0.1:20241/metrics 2>/dev/null | grep '^cloudflared_tunnel_ha_connections' | awk '{print $2}')" | tee -a "$OUT" # ---------------------------------------------------------------- A echo | tee -a "$OUT" echo "── A. 公网 HTTP 可用率(100 次,间隔 0.4 秒)──" | tee -a "$OUT" okA=0; failA=0; timesA=() for i in $(seq 1 100); do out=$(curl -s -o /dev/null -w '%{http_code} %{time_total}' --max-time 25 -H "User-Agent: $UA" "$BASE/v1/health") code=$(echo "$out" | awk '{print $1}') ms=$(echo "$out" | awk '{printf "%d", $2*1000}') if [ "$code" = "200" ]; then okA=$((okA+1)); timesA+=("$ms"); else failA=$((failA+1)); fi sleep 0.4 done pctA=$((okA * 100 / 100)) echo " 可用率: $okA/100 = ${pctA}% 失败 $failA 次" | tee -a "$OUT" if [ "${#timesA[@]}" -gt 0 ]; then printf '%s\n' "${timesA[@]}" | sort -n | awk '{ a[NR]=$1 } END { printf " 耗时: 最小 %d 中位 %d P90 %d P99 %d 最大 %d ms\n", a[1], a[int(NR/2)+1], a[int(NR*0.9)+1], a[int(NR*0.99)+1], a[NR] }' | tee -a "$OUT" fi # ---------------------------------------------------------------- E(快的先做) echo | tee -a "$OUT" echo "── E. 静态资源(各 10 次)──" | tee -a "$OUT" for path in "/" "/shot/pc-main.png" "/favicon.ico"; do ok=0; times=() for i in $(seq 1 10); do out=$(curl -s -o /dev/null -w '%{http_code} %{time_total}' --max-time 25 -H "User-Agent: $UA" "$BASE$path") c=$(echo "$out" | awk '{print $1}') ms=$(echo "$out" | awk '{printf "%d", $2*1000}') [ "$c" = "200" ] && { ok=$((ok+1)); times+=("$ms"); } sleep 0.3 done stats=$(printf '%s\n' "${times[@]:-0}" | sort -n | awk '{a[NR]=$1} END {printf "中位 %d 最大 %d ms", a[int(NR/2)+1], a[NR]}') printf " %-22s %2d/10 %s\n" "$path" "$ok" "$stats" | tee -a "$OUT" done # ---------------------------------------------------------------- C echo | tee -a "$OUT" echo "── C. 三个成品下载(完整下载,量吞吐)──" | tee -a "$OUT" for f in ykxmz-setup-1.8.1.exe ykxmz-server-1.8.1.zip ykxmz-watch-1.8.1.apk; do rm -f /tmp/dl.bin out=$(curl -s -o /tmp/dl.bin -w '%{http_code} %{size_download} %{time_total}' \ --max-time 180 -H "User-Agent: $UA" "$BASE/download/$f") code=$(echo "$out" | awk '{print $1}') size=$(echo "$out" | awk '{print $2}') secs=$(echo "$out" | awk '{print $3}') kbps=$(echo "$secs $size" | awk '{if ($1 > 0) printf "%.0f", $2/$1/1024; else print 0}') printf " %-30s HTTP %-4s %9s 字节 %6.1fs %6s KB/s\n" \ "$f" "$code" "$size" "$secs" "$kbps" | tee -a "$OUT" done # ---------------------------------------------------------------- D echo | tee -a "$OUT" echo "── D. 隧道连接数稳定性(采样 60 秒,每 2 秒一次)──" | tee -a "$OUT" MARK=$(wc -l < /root/lanremote-relay/tunnel.log 2>/dev/null || echo 0) minc=99; maxc=0; vals=() for i in $(seq 1 30); do n=$(curl -s --max-time 4 http://127.0.0.1:20241/metrics 2>/dev/null | grep '^cloudflared_tunnel_ha_connections' | awk '{print $2}') [ -z "${n:-}" ] && n=0 [ "$n" -lt "$minc" ] && minc="$n" [ "$n" -gt "$maxc" ] && maxc="$n" vals+=("$n") sleep 2 done reconn=$(tail -n +$((MARK+1)) /root/lanremote-relay/tunnel.log 2>/dev/null | grep -c 'Registered tunnel connection' || echo 0) lost=$(tail -n +$((MARK+1)) /root/lanremote-relay/tunnel.log 2>/dev/null | grep -c 'Lost connection' || echo 0) iot=$(tail -n +$((MARK+1)) /root/lanremote-relay/tunnel.log 2>/dev/null | grep -c 'i/o timeout' || echo 0) echo " 连接数: 最低 $minc 最高 $maxc 采样期间重连 $reconn 次 · 掉线 $lost 次 · i/o timeout $iot 次" | tee -a "$OUT" # ---------------------------------------------------------------- B echo | tee -a "$OUT" echo "── B. 长轮询(10 次真实 poll,每次挂 60 秒 ≈ 10 分钟)──" | tee -a "$OUT" STAMP=$(date +%s) DEV="bench-${LABEL}-${STAMP}" CODE=$(printf "%06d" $(( STAMP % 1000000 ))) REG=$(curl -s --max-time 30 -X POST "$BASE/v1/agent/register" \ -H 'Content-Type: application/json' -H "User-Agent: $UA" \ -d "{\"deviceId\":\"$DEV\",\"code\":\"$CODE\",\"name\":\"bench\",\"version\":\"1.8.1\"}") TOKEN=$(echo "$REG" | python3 -c "import sys,json; print(json.load(sys.stdin).get('token',''))" 2>/dev/null) if [ -z "$TOKEN" ]; then echo " [失败] 探针注册没拿到 token" | tee -a "$OUT" else okB=0; timesB=(); failsB="" MARK2=$(wc -l < /root/lanremote-relay/tunnel.log 2>/dev/null || echo 0) for i in $(seq 1 10); do out=$(curl -s -o /dev/null -w '%{http_code} %{time_total}' --max-time 130 \ -X POST "$BASE/v1/agent/poll" -H "X-Token: $TOKEN" -H "User-Agent: $UA") c=$(echo "$out" | awk '{print $1}') secs=$(echo "$out" | awk '{printf "%d", $2*1000}') if [ "$c" = "200" ]; then okB=$((okB+1)); timesB+=("$secs") printf " %2d: 200 %6dms\n" "$i" "$secs" | tee -a "$OUT" else failsB="$failsB ${i}:${c}" printf " %2d: %-4s **失败**\n" "$i" "$c" | tee -a "$OUT" fi done echo " 长轮询成功: $okB/10 = $((okB*10))% 失败:$failsB" | tee -a "$OUT" if [ "${#timesB[@]}" -gt 0 ]; then printf '%s\n' "${timesB[@]}" | sort -n | awk '{ a[NR]=$1 } END { printf " 耗时: 最小 %d 中位 %d P90 %d 最大 %d ms(理想 ≈ 61000)\n", a[1], a[int(NR/2)+1], a[int(NR*0.9)+1], a[NR] }' | tee -a "$OUT" fi r2=$(tail -n +$((MARK2+1)) /root/lanremote-relay/tunnel.log 2>/dev/null | grep -c 'Registered tunnel connection' || echo 0) echo " 这 10 分钟里隧道重连 $r2 次" | tee -a "$OUT" KEY=$(cat /root/lanremote-relay/data/admin_key.txt 2>/dev/null) curl -s --max-time 20 -X POST "http://127.0.0.1:8080/v1/admin/delete" \ -H "X-Admin: $KEY" -H 'Content-Type: application/json' \ -d "{\"deviceId\":\"$DEV\"}" > /dev/null 2>&1 fi echo | tee -a "$OUT" echo "════════════════════════════════════════════════════════" | tee -a "$OUT" echo " 基线存档: $OUT" | tee -a "$OUT" # 顺便把关键数字汇总成一行,便于前后对比 { echo echo "===== 汇总($LABEL)=====" echo "A 公网可用率 ${pctA}% ($okA/100)" echo "B 长轮询成功 ${okB:-0}/10" echo "D 隧道连接 最低 ${minc} 最高 ${maxc} 重连 ${reconn} 掉线 ${lost}" } | tee -a "$OUT"