#!/bin/bash # 隧道长时稳定性测量(默认 30 分钟) # # 为什么要长时: # 短测(60 次请求)看到的可用率都在 98~100%,看不出区别。 # 真实的失败是"某条隧道连接掉了、重连期间打在上面的请求失败", # 这种事几十分钟才出现一两次 —— 必须跑长才能抓到。 # # 记录: # * 连接数采样(每 10 秒)—— 看有没有掉到配置值以下 # * 公网可用率采样(每 30 秒,从**本机**打,所以含设备自身 4G 的影响) # * 隧道日志里的 重连 / 掉线 / dial 失败 事件 # * 事件时间线(哪一刻掉的) # # 用法: bash longstab.sh [分钟数] [标签] set -u BASE=https://relay.xxmxxs.top UA='LanRemote/1.8.2' MINUTES=${1:-30} LABEL=${2:-run} ROUNDS=$((MINUTES * 6)) # 每 10 秒一轮 OUT=/root/longstab_${LABEL}.txt MARK=$(wc -l < /root/lanremote-relay/tunnel.log 2>/dev/null || echo 0) echo "════════ 隧道长时稳定性 · $LABEL · ${MINUTES} 分钟 ════════" | tee "$OUT" echo " 参数: $(grep -oE '\-\-protocol [a-z0-9]+|--ha-connections [0-9]+' /etc/systemd/system/lanremote-tunnel.service | tr '\n' ' ')" | tee -a "$OUT" echo " MTU: $(cat /sys/class/net/wlan0/mtu)" | tee -a "$OUT" echo " 开始: $(date '+%H:%M:%S') 共 $ROUNDS 轮" | tee -a "$OUT" minc=999; maxc=0; sumc=0; nz=0 okA=0; totA=0; timesA=() declare -a timeline for r in $(seq 1 "$ROUNDS"); 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}') n=${n:-0} [ "$n" -lt "$minc" ] && minc="$n" [ "$n" -gt "$maxc" ] && maxc="$n" sumc=$((sumc + n)) # 每 3 轮(30 秒)打一次公网 if [ $((r % 3)) -eq 0 ]; then out=$(curl -s -o /dev/null -w '%{http_code} %{time_total}' --max-time 25 \ -H "User-Agent: $UA" "$BASE/v1/health") c=$(echo "$out" | awk '{print $1}') ms=$(echo "$out" | awk '{printf "%d", $2*1000}') totA=$((totA + 1)) if [ "$c" = "200" ]; then okA=$((okA + 1)); timesA+=("$ms") else timeline+=("$(date '+%H:%M:%S') HTTP $c (连接数 $n)") printf " [%s] ✗ HTTP %s 连接数 %s\n" "$(date '+%H:%M:%S')" "$c" "$n" | tee -a "$OUT" fi # 连接数掉到配置值以下也要记 if [ "$n" -lt 10 ]; then printf " [%s] ! 连接数只有 %s\n" "$(date '+%H:%M:%S')" "$n" | tee -a "$OUT" fi fi sleep 10 done echo | tee -a "$OUT" echo "════════ 结果 ════════" | tee -a "$OUT" echo " 连接数: 最低 $minc 最高 $maxc 平均 $((sumc / ROUNDS))(配置 10)" | tee -a "$OUT" pct=$((okA * 100 / (totA > 0 ? totA : 1))) echo " 公网可用率: $okA/$totA = ${pct}%" | 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 echo | tee -a "$OUT" echo " 这段时间的隧道事件:" | tee -a "$OUT" for kw in 'Registered tunnel connection' 'Lost connection' 'Failed to dial' 'i/o timeout' 'no recent network activity'; do c=$(tail -n +$((MARK+1)) /root/lanremote-relay/tunnel.log 2>/dev/null | grep -c "$kw" || echo 0) printf " %-34s %s 次\n" "$kw" "$c" | tee -a "$OUT" done echo | tee -a "$OUT" echo " 掉线/重连时间线(最后 12 条):" | tee -a "$OUT" tail -n +$((MARK+1)) /root/lanremote-relay/tunnel.log 2>/dev/null \ | grep -E 'Lost connection|Registered tunnel connection' | tail -12 \ | sed 's/^/ /' | tee -a "$OUT" echo | tee -a "$OUT" echo " 期间有没有 HTTP 失败:" | tee -a "$OUT" if [ "${#timeline[@]}" -gt 0 ]; then printf ' %s\n' "${timeline[@]}" | tee -a "$OUT" else echo " 没有" | tee -a "$OUT" fi echo | tee -a "$OUT" echo " watchdog 最近 5 行:" | tee -a "$OUT" tail -5 /root/lanremote-relay/watchdog.log 2>/dev/null | sed 's/^/ /' | tee -a "$OUT" echo | tee -a "$OUT" echo " 存档: $OUT" | tee -a "$OUT"