#!/bin/bash # 配比 A/B:既然 UDP 被限制(QUIC 拨号只有 72% 成功, # 而 HTTP/2/TCP 是 100%),就该把连接数往 HTTP/2 倾斜。 # # 对照四组(都连同一个具名隧道,Cloudflare 会把请求分摊到所有连接): # A. quic 5 + http2 5 现状 # B. quic 3 + http2 7 往 TCP 倾斜 # C. quic 0 + http2 10 纯 HTTP/2(把 quic 实例停掉) # D. quic 8 + http2 2 反向验证(应该更差,用来确认假设) # # 每组测:总连接数、拨号失败数、60 次公网可用率、延迟分布 set -u BASE=https://relay.xxmxxs.top UA='LanRemote/1.8.2' MAIN=/etc/systemd/system/lanremote-tunnel.service H2=/etc/systemd/system/lanremote-tunnel-h2.service BAK_MAIN=/root/tunnel.main.bak.$(date +%s) BAK_H2=/root/tunnel.h2.bak.$(date +%s) cp -a "$MAIN" "$BAK_MAIN" cp -a "$H2" "$BAK_H2" N=60 echo "════════ 0. 先看有没有 IPv6(有的话可能绕开 UDP 限制)════════" ip -6 addr show scope global 2>/dev/null | grep -c 'inet6' | sed 's/^/ wlan0 全局 IPv6 地址数: /' echo " 到 Cloudflare 的 IPv6 连通性:" if ping6 -c 2 -W 3 2606:4700::1111 > /dev/null 2>&1; then echo " IPv6 通(但 QUIC 仍走 UDP,未必有帮助)" else echo " IPv6 不通 -> --edge-ip-version 6 没法用" fi set_conns() { local q="$1" h="$2" if [ "$q" = "0" ]; then systemctl stop lanremote-tunnel 2>/dev/null || true # 停掉服务避免它自己起来 systemctl stop lanremote-tunnel.socket 2>/dev/null || true else cp -a "$BAK_MAIN" "$MAIN" sed -i "s/--ha-connections [0-9]*/--ha-connections $q/" "$MAIN" systemctl daemon-reload systemctl restart lanremote-tunnel fi cp -a "$BAK_H2" "$H2" sed -i "s/--ha-connections [0-9]*/--ha-connections $h/" "$H2" systemctl daemon-reload systemctl restart lanremote-tunnel-h2 } read_conns() { local port="$1" curl -s --max-time 4 "http://127.0.0.1:$port/metrics" 2>/dev/null \ | grep '^cloudflared_tunnel_ha_connections' | awk '{print $2}' } wait_total() { local want="$1" limit="$2" t0 t1 a b t0=$(date +%s) while true; do a=$(read_conns 20241); b=$(read_conns 20242) a=${a:-0}; b=${b:-0} t1=$(date +%s) [ $((a + b)) -ge "$want" ] || [ $((t1 - t0)) -ge "$limit" ] && break sleep 3 done echo "$a $b $((t1 - t0))" } measure() { local label="$1" local ok=0 times=() for i in $(seq 1 "$N"); do 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}') [ "$c" = "200" ] && { ok=$((ok+1)); times+=("$ms"); } done local pct=$((ok * 100 / N)) local stats="无数据" [ "${#times[@]}" -gt 0 ] && stats=$(printf '%s\n' "${times[@]}" | sort -n | awk '{a[NR]=$1} END { printf "中位 %d P90 %d P99 %d 最大 %d", a[int(NR/2)+1], a[int(NR*0.9)+1], a[int(NR*0.99)+1], a[NR]}') printf " 可用率 %d%% (%d/%d) %s ms\n" "$pct" "$ok" "$N" "$stats" echo "${label}|${pct}|${stats}" >> /tmp/ratio.txt } run_group() { local label="$1" q="$2" h="$3" echo "════════ $label(quic=$q http2=$h)════════" local mk; mk=$(date +%s) set_conns "$q" "$h" local res; res=$(wait_total $((q + h)) 150) local a b s a=$(echo "$res" | awk '{print $1}'); b=$(echo "$res" | awk '{print $2}'); s=$(echo "$res" | awk '{print $3}') echo " 连接: quic=$a http2=$b 合计=$((a + b)) 用时 ${s}s" # 拨号失败(两个日志合计,本轮内) local df=0 for f in /root/lanremote-relay/tunnel.log /root/lanremote-relay/tunnel-h2.log; do [ -f "$f" ] && df=$((df + $(grep -c 'Failed to dial' "$f" 2>/dev/null || echo 0))) done echo " 日志里累计 Failed to dial: $df" sleep 10 measure "$label" echo } rm -f /tmp/ratio.txt run_group "A quic5+h2 5" 5 5 run_group "B quic3+h2 7" 3 7 run_group "C quic0+h2 10" 0 10 run_group "D quic8+h2 2" 8 2 echo "════════ 汇总 ════════" printf " %-16s %-10s %s\n" "配置" "可用率" "延迟" while IFS='|' read -r label pct stats; do printf " %-16s %-10s %s\n" "$label" "${pct}%" "$stats" done < /tmp/ratio.txt echo BEST=$(sort -t'|' -k2 -rn /tmp/ratio.txt | head -1) BL=$(echo "$BEST" | cut -d'|' -f1) echo " → 可用率最高: $BL($(echo "$BEST" | cut -d'|' -f2)%)" # 恢复成最优配比 case "$BL" in "A quic5+h2 5") set_conns 5 5 ;; "B quic3+h2 7") set_conns 3 7 ;; "C quic0+h2 10") set_conns 0 10 ;; *) set_conns 8 2 ;; esac sleep 10 echo " 当前: quic=$(read_conns 20241) http2=$(read_conns 20242)" echo " 备份: $BAK_MAIN $BAK_H2"