#!/bin/bash # 长窗口配比对照用的测量脚本(支持 A/B 两组,各跑 >=40 分钟) # # 与 rp_long2h.sh 的区别: # * 时长可指定(分钟) # * **额外采样内存和 CPU**(Lead 问 h2 提到 4 条对 460MB 设备有无影响) # * 输出文件名带标签,方便 A/B 分开比对 # # 用法: bash rp_ab_long.sh <标签> <分钟数> set -u LABEL=${1:-A} MINS=${2:-45} BASE=https://relay.xxmxxs.top UA='LanRemote/1.8.2' DUR=$((MINS * 60)) HEALTH_EVERY=15 CONN_EVERY=60 RES_EVERY=60 H=/root/ab_${LABEL}_health.tsv C=/root/ab_${LABEL}_conns.tsv R=/root/ab_${LABEL}_res.tsv S=/root/ab_${LABEL}_summary.txt rm -f "$H" "$C" "$R" "$S" conns_of() { curl -s --max-time 4 "http://127.0.0.1:$1/metrics" 2>/dev/null \ | grep '^cloudflared_tunnel_ha_connections' | awk '{print $2}' } M0=$(wc -l < /root/lanremote-relay/tunnel.log 2>/dev/null || echo 0) H0=$(wc -l < /root/lanremote-relay/tunnel-h2.log 2>/dev/null || echo 0) T0=$(date +%s) NEXT_CONN=$T0 NEXT_RES=$T0 echo " 开始 $LABEL: $(date '+%H:%M:%S') 持续 ${MINS} 分钟" while true; do NOW=$(date +%s) [ $((NOW - T0)) -ge "$DUR" ] && break 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}') echo "$(date '+%Y-%m-%d %H:%M:%S') $code $ms" >> "$H" if [ "$NOW" -ge "$NEXT_CONN" ]; then a=$(conns_of 20241); b=$(conns_of 20242) echo "$(date '+%Y-%m-%d %H:%M:%S') ${a:-X} ${b:-X}" >> "$C" NEXT_CONN=$((NOW + CONN_EVERY)) fi if [ "$NOW" -ge "$NEXT_RES" ]; then # 两个 cloudflared 各占多少常驻内存 + CPU qm=0; hm=0; qc=0; hc=0 for p in $(pgrep cloudflared); do proto=$(tr '\0' ' ' < /proc/$p/cmdline 2>/dev/null | grep -oE '\-\-protocol [a-z0-9]+' | awk '{print $2}') rss=$(awk '/VmRSS/{print $2}' /proc/$p/status 2>/dev/null) cpu=$(ps -o %cpu= -p $p 2>/dev/null | tr -d ' ') if [ "$proto" = "quic" ]; then qm=${rss:-0}; qc=${cpu:-0}; elif [ "$proto" = "http2" ]; then hm=${rss:-0}; hc=${cpu:-0}; fi done total=$(free -m | awk '/Mem:/{print $3}') avail=$(free -m | awk '/Mem:/{print $7}') load=$(awk '{print $1}' /proc/loadavg) echo "$(date '+%Y-%m-%d %H:%M:%S') ${qm} ${hm} ${qc} ${hc} ${total} ${avail} ${load}" >> "$R" NEXT_RES=$((NOW + RES_EVERY)) fi sleep "$HEALTH_EVERY" done M1=$(wc -l < /root/lanremote-relay/tunnel.log 2>/dev/null || echo 0) H1=$(wc -l < /root/lanremote-relay/tunnel-h2.log 2>/dev/null || echo 0) { echo "════════════════════════════════════════════════════════" echo " $LABEL 组 · ${MINS} 分钟 · $(date '+%Y-%m-%d %H:%M:%S')" echo "════════════════════════════════════════════════════════" echo echo "── 配置 ──" for svc in lanremote-tunnel lanremote-tunnel-h2; do echo " $svc: $(systemctl cat $svc 2>/dev/null | grep -oE '\-\-protocol [a-z0-9]+|\-\-ha-connections [0-9]+' | tr '\n' ' ')" done echo echo "── 公网可用率 ──" n=$(grep -c . "$H" 2>/dev/null || echo 0) ok=$(awk -F'\t' '$2=="200"' "$H" 2>/dev/null | wc -l) echo " $ok/$n = $(awk -v a="$ok" -v b="$n" 'BEGIN{if(b>0)printf "%.2f", a*100/b; else print 0}')%" echo " 状态码: $(awk -F'\t' '{print $2}' "$H" 2>/dev/null | sort | uniq -c | tr '\n' ' ')" awk -F'\t' '$2=="200"{print $3}' "$H" 2>/dev/null | sort -n | awk ' {a[NR]=$1} END{if(NR==0){print " 无数据"; exit} 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]}' echo " 失败时刻:" awk -F'\t' '$2!="200"{print " " $1 " 码=" $2 " " $3 "ms"}' "$H" 2>/dev/null echo echo "── 连接数 ──" awk -F'\t' 'NR>1 && $2 ~ /^[0-9]+$/ && $3 ~ /^[0-9]+$/ { t=$2+$3; cnt[t]++ if (t<=3) low++ if (tmax) max=t } END { printf " 最小 %d 最大 %d 平均 %.2f\n", min, max, 0 printf " 总连接数<=3 的采样: %d 次(占 %.1f%%)\n", low+0, (low+0)*100/NR }' "$C" 2>/dev/null echo " 分布: $(awk -F'\t' 'NR>1 && $2 ~ /^[0-9]+$/ && $3 ~ /^[0-9]+$/ {print $2+$3}' "$C" | sort -n | uniq -c | tr '\n' ' ')" echo echo "── 内存 / CPU ──" awk -F'\t' 'NR>1 { if ($2+0>qm) qm=$2 if ($3+0>hm) hm=$3 if ($4+0>qc) qc=$4 if ($5+0>hc) hc=$5 if ($6+0>tm) tm=$6 if (minav=="" || $7+0ld) ld=$8 } END { printf " QUIC 实例常驻内存峰值: %.1f MB\n", qm/1024 printf " HTTP/2 实例常驻内存峰值: %.1f MB\n", hm/1024 printf " 两者合计: %.1f MB\n", (qm+hm)/1024 printf " CPU 峰值: quic %.1f%% http2 %.1f%%\n", qc, hc printf " 设备已用内存峰值: %d MB 最少可用: %d MB\n", tm, minav printf " 负载峰值: %.2f\n", ld }' "$R" 2>/dev/null echo echo "── 隧道事件(本轮增量)──" printf " QUIC 注册 %s 失败 %s 掉线 %s\n" \ "$(tail -n +$((M0+1)) /root/lanremote-relay/tunnel.log 2>/dev/null | grep -c 'Registered tunnel connection')" \ "$(tail -n +$((M0+1)) /root/lanremote-relay/tunnel.log 2>/dev/null | grep -c 'Failed to dial')" \ "$(tail -n +$((M0+1)) /root/lanremote-relay/tunnel.log 2>/dev/null | grep -c 'Lost connection')" printf " HTTP/2 注册 %s 失败 %s 掉线 %s\n" \ "$(tail -n +$((H0+1)) /root/lanremote-relay/tunnel-h2.log 2>/dev/null | grep -c 'Registered tunnel connection')" \ "$(tail -n +$((H0+1)) /root/lanremote-relay/tunnel-h2.log 2>/dev/null | grep -c 'Failed to dial')" \ "$(tail -n +$((H0+1)) /root/lanremote-relay/tunnel-h2.log 2>/dev/null | grep -c 'Lost connection')" echo echo "── watchdog 处置(本轮)──" tail -12 /root/lanremote-relay/watchdog.log 2>/dev/null | sed 's/^/ /' } > "$S" 2>&1 cat "$S"