#!/bin/bash # 配比 A/B v2:QUIC 拨号成功率只有 72%(UDP 被限制),HTTP/2 是 100%。 # 所以应该把连接数往 HTTP/2 倾斜。这里做受控对照确认。 # # v1 的两个 bug: # 1. df=$((df + $(grep -c ... || echo 0))) # —— grep -c 没匹配时会输出 "0" 且返回非 0, # 配合 || echo 0 就变成 "0\n0",算术表达式直接语法错误。 # 改成先取值再判断。 # 2. 端口按 20241/20242 写死 —— 但当时两个服务都没显式 --metrics, # 主实例一停,副实例就抢到 20241,读数全反。 # 现在已经显式钉死端口,并且这里改成**按服务名查端口**。 set -u BASE=https://relay.xxmxxs.top UA='LanRemote/1.8.2' MAIN=lanremote-tunnel H2=lanremote-tunnel-h2 MAINF=/etc/systemd/system/$MAIN.service H2F=/etc/systemd/system/$H2.service BAK=/root/ratio.bak.$(date +%s) cp -a "$MAINF" "$BAK.main" cp -a "$H2F" "$BAK.h2" N=40 # 从服务配置读它绑的 metrics 端口 port_of() { systemctl cat "$1" 2>/dev/null \ | grep -oE '\-\-metrics[[:space:]]+[0-9.]+:[0-9]+' | head -1 \ | grep -oE '[0-9]+$' } MAIN_PORT=$(port_of "$MAIN") H2_PORT=$(port_of "$H2") echo " 端口: $MAIN=$MAIN_PORT $H2=$H2_PORT" # 计数器:grep -c 的结果安全转成整数 gcount() { local n n=$(grep -c "$2" "$1" 2>/dev/null) case "$n" in ''|*[!0-9]*) echo 0 ;; *) echo "$n" ;; esac } read_conns() { local port="$1" v v=$(curl -s --max-time 4 "http://127.0.0.1:$port/metrics" 2>/dev/null \ | grep '^cloudflared_tunnel_ha_connections' | awk '{print $2}') case "$v" in ''|*[!0-9]*) echo "X" ;; *) echo "$v" ;; esac } set_conns() { local q="$1" h="$2" cp -a "$BAK.main" "$MAINF" cp -a "$BAK.h2" "$H2F" if [ "$q" = "0" ]; then systemctl stop "$MAIN" 2>/dev/null || true else sed -i "s/--ha-connections [0-9]*/--ha-connections $q/" "$MAINF" systemctl daemon-reload systemctl restart "$MAIN" fi if [ "$h" = "0" ]; then systemctl stop "$H2" 2>/dev/null || true else sed -i "s/--ha-connections [0-9]*/--ha-connections $h/" "$H2F" systemctl daemon-reload systemctl restart "$H2" fi # 确保停掉的那个不会被拉起来 systemctl daemon-reload } wait_total() { local want="$1" limit="$2" t0 t1 a b t0=$(date +%s) while true; do a=$(read_conns "$MAIN_PORT"); [ "$a" = "X" ] && a=0 b=$(read_conns "$H2_PORT"); [ "$b" = "X" ] && b=0 t1=$(date +%s) if [ $((a + b)) -ge "$want" ] || [ $((t1 - t0)) -ge "$limit" ]; then break fi sleep 3 done echo "$a $b $((t1 - t0))" } measure() { local label="$1" local ok=0 times=() for i in $(seq 1 "$N"); do local out c ms 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}') if [ "$c" = "200" ]; then ok=$((ok + 1)); times+=("$ms"); fi done local pct=$((ok * 100 / N)) local stats="无数据" if [ "${#times[@]}" -gt 0 ]; then 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]}') fi printf " 可用率 %d%% (%d/%d) %s ms\n" "$pct" "$ok" "$N" "$stats" printf '%s|%s|%s\n' "$label" "$pct" "$stats" >> /tmp/ratio2.txt } run_group() { local label="$1" q="$2" h="$3" echo "════════ $label(quic=$q http2=$h)════════" set_conns "$q" "$h" local res a b s res=$(wait_total $((q + h)) 150) 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)) (期望 $q/$h) 用时 ${s}s" local df=0 for f in /root/lanremote-relay/tunnel.log /root/lanremote-relay/tunnel-h2.log; do [ -f "$f" ] && df=$((df + $(gcount "$f" 'Failed to dial'))) done echo " 累计 Failed to dial: $df" sleep 8 measure "$label" echo } rm -f /tmp/ratio2.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 "════════ 汇总(按可用率排序)════════" sort -t'|' -k2 -rn /tmp/ratio2.txt | while IFS='|' read -r label pct stats; do printf " %-16s %3s%% %s\n" "$label" "$pct" "$stats" done BEST=$(sort -t'|' -k2 -rn /tmp/ratio2.txt | head -1 | cut -d'|' -f1) echo echo " → 最好: $BEST" # 恢复 cp -a "$BAK.main" "$MAINF" cp -a "$BAK.h2" "$H2F" systemctl daemon-reload case "$BEST" in "A quic5+h2 5") sed -i 's/--ha-connections [0-9]*/--ha-connections 5/' "$MAINF"; sed -i 's/--ha-connections [0-9]*/--ha-connections 5/' "$H2F" ;; "B quic3+h2 7") sed -i 's/--ha-connections [0-9]*/--ha-connections 3/' "$MAINF"; sed -i 's/--ha-connections [0-9]*/--ha-connections 7/' "$H2F" ;; "C quic0+h2 10") sed -i 's/--ha-connections [0-9]*/--ha-connections 10/' "$H2F" ;; *) sed -i 's/--ha-connections [0-9]*/--ha-connections 8/' "$MAINF"; sed -i 's/--ha-connections [0-9]*/--ha-connections 2/' "$H2F" ;; esac systemctl daemon-reload systemctl restart "$MAIN" "$H2" sleep 25 echo " 当前: quic=$(read_conns "$MAIN_PORT") http2=$(read_conns "$H2_PORT")" echo " 备份: $BAK.main $BAK.h2"