mirror of
https://gitee.com/xmz7891/ykxmz.git
synced 2026-10-18 21:50:44 +00:00
实测基线:
ykxmz-setup-1.8.1.exe 只下到 237568/15067199 字节就停(17 KB/s)
ykxmz-watch-1.8.1.apk 201523 字节 / 66.8 秒 = 3 KB/s
ykxmz-server-1.8.1.zip 214900 字节 / 3.1 秒 = 67 KB/s
原因:relay 给所有响应都发 Cache-Control: no-store,
Cloudflare 完全不缓存 —— 每次下载/每张图都要穿隧道回 4G 源站。
改动:
/download/* no-store -> public, max-age=604800, immutable
文件名带版本号,同一名字内容永不改变,可以长缓存
/ -> public, max-age=60(挡住刷新重复回源)
/favicon.ico 已是 max-age=86400,保持不变
/shot/* 已是 max-age=86400,保持不变
/v1/* 保持 no-store(接口必须实时)
顺带修两个自己踩的坑:
1. _send() 无条件先发 no-store,再追加 extra 里的 Cache-Control,
结果是**两个 Cache-Control 头**,客户端只认第一个 ——
调用方传的缓存策略被吃掉。改成 extra 里有就不再发默认值。
2. do_HEAD 和 do_GET 的缓存头不一致:HEAD 对非 /shot/ 一律报 no-store。
下载器/代理用 HEAD 探测时会误判文件不可缓存。
现在 _head_info 给每个路由带上和 GET 完全相同的缓存头,
do_HEAD 也不再盲目覆盖。
结果(同一个测试口径):
setup.exe 17 KB/s(截断) -> 695 KB/s 完整 15 MB 41 倍
watch.apk 3 KB/s -> 101 KB/s 33 倍
server.zip 67 KB/s -> 87 KB/s
三个文件全部 cf-cache-status=HIT(不再穿隧道回源)
排查过程记一笔:我一开始用 curl -I 验证,
看到的全是 no-store —— 因为 **-I 发的是 HEAD**,
而 HEAD 走的是另一个分支。查了半天才发现是验证方法错了。
134 lines
4.9 KiB
Bash
134 lines
4.9 KiB
Bash
#!/bin/bash
|
||
# 隧道对照 v3:验证「QUIC 失败是因为 MTU」这个假设,并选出最稳的组合。
|
||
#
|
||
# 已查明的事实:
|
||
# 1. cloudflared 用 QUIC 时反复报
|
||
# "failed to dial to edge with quic: timeout: no recent network activity"
|
||
# 连十几个 IP 才成功一次 —— 握手阶段就掉包。
|
||
# 2. 我们给 TCP 做了 MSS 钳制(--set-mss 1400),
|
||
# 但 **QUIC 走 UDP,TCPMSS 规则完全不生效**。
|
||
# 3. 路径 MTU 实测 1472(1500 的包不通)。
|
||
# QUIC 默认用 ~1452 字节的包,很容易被中间设备丢掉,
|
||
# 而 UDP 丢了不会回 ICMP,客户端只能等到超时。
|
||
#
|
||
# 所以对照三组:
|
||
# A. quic + 6(现状,MTU 1500) —— 预期握手仍不稳
|
||
# B. quic + 6 + wlan0 MTU 1400 —— 如果假设成立,握手会变稳
|
||
# C. http2 + 8(TCP 吃 MSS 钳制,连接多) —— 对照组
|
||
#
|
||
# 每组记录:连接建齐耗时 / 建齐几条 / 60 次 HTTP 可用率
|
||
set -u
|
||
|
||
BASE=https://relay.xxmxxs.top
|
||
UA='LanRemote/1.8.1'
|
||
SVC=/etc/systemd/system/lanremote-tunnel.service
|
||
BACKUP=/root/tunnel.bak.v3.$(date +%s)
|
||
cp -a "$SVC" "$BACKUP"
|
||
N=60
|
||
|
||
set_params() {
|
||
local proto="$1" conns="$2"
|
||
cp -a "$BACKUP" "$SVC"
|
||
sed -i "s/--protocol [a-z0-9]*/--protocol $proto/" "$SVC"
|
||
sed -i "s/--ha-connections [0-9]*/--ha-connections $conns/" "$SVC"
|
||
systemctl daemon-reload
|
||
systemctl restart lanremote-tunnel
|
||
}
|
||
|
||
set_mtu() {
|
||
local mtu="$1"
|
||
ip link set wlan0 mtu "$mtu" 2>/dev/null && echo " wlan0 MTU -> $(cat /sys/class/net/wlan0/mtu)"
|
||
}
|
||
|
||
# 等连接建齐,返回耗时秒数
|
||
wait_conns() {
|
||
local want="$1" limit="$2" t0 t1 n
|
||
t0=$(date +%s)
|
||
while true; 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}
|
||
t1=$(date +%s)
|
||
if [ "$n" -ge "$want" ] || [ $((t1 - t0)) -ge "$limit" ]; then
|
||
echo "$n $((t1 - t0))"
|
||
return
|
||
fi
|
||
sleep 3
|
||
done
|
||
}
|
||
|
||
run_group() {
|
||
local label="$1" proto="$2" conns="$3" mtu="$4"
|
||
echo "════════ $label ════════"
|
||
|
||
[ "$mtu" != "keep" ] && set_mtu "$mtu"
|
||
|
||
local mark; mark=$(wc -l < /root/lanremote-relay/tunnel.log 2>/dev/null || echo 0)
|
||
set_params "$proto" "$conns"
|
||
|
||
local res; res=$(wait_conns "$conns" 150)
|
||
local n; n=$(echo "$res" | awk '{print $1}')
|
||
local secs; s=$(echo "$res" | awk '{print $2}')
|
||
echo " 建齐 $n/$conns 条,用了 ${s} 秒"
|
||
|
||
# 这一轮建立过程中失败了多少次
|
||
local dialfail; dialfail=$(tail -n +$((mark+1)) /root/lanremote-relay/tunnel.log 2>/dev/null \
|
||
| grep -c 'Failed to dial' || echo 0)
|
||
echo " 建立期间 dial 失败 $dialfail 次"
|
||
|
||
# 可用率
|
||
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}')
|
||
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"
|
||
echo "$label|$proto|$conns|$mtu|$n|$s|$dialfail|$pct|$stats" >> /tmp/v3.txt
|
||
echo
|
||
}
|
||
|
||
rm -f /tmp/v3.txt
|
||
echo " 原始 wlan0 MTU: $(cat /sys/class/net/wlan0/mtu)"
|
||
echo
|
||
|
||
run_group "A. quic+6 MTU1500" quic 6 keep
|
||
run_group "B. quic+6 MTU1400" quic 6 1400
|
||
run_group "C. http2+8 MTU1400" http2 8 keep
|
||
|
||
# 恢复 MTU
|
||
set_mtu 1500
|
||
|
||
echo "════════ 汇总 ════════"
|
||
printf " %-22s %-6s %-4s %-8s %-9s %-8s %s\n" "组" "协议" "连接" "建齐/耗时" "dial失败" "可用率" "延迟"
|
||
while IFS='|' read -r label proto conns mtu n s dialfail pct stats; do
|
||
printf " %-22s %-6s %-4s %-8s %-9s %-8s %s\n" \
|
||
"$label" "$proto" "$conns" "${n}/${conns} ${s}s" "$dialfail" "${pct}%" "$stats"
|
||
done < /tmp/v3.txt
|
||
|
||
echo
|
||
echo "════════ 决策:可用率优先,其次看建齐速度 ════════"
|
||
BEST=$(sort -t'|' -k8 -rn /tmp/v3.txt | head -1)
|
||
BL=$(echo "$BEST" | cut -d'|' -f1)
|
||
BP=$(echo "$BEST" | cut -d'|' -f2)
|
||
BC=$(echo "$BEST" | cut -d'|' -f3)
|
||
BM=$(echo "$BEST" | cut -d'|' -f4)
|
||
echo " 最好: $BL(可用率 $(echo "$BEST" | cut -d'|' -f8)%)"
|
||
|
||
cp -a "$BACKUP" "$SVC"
|
||
sed -i "s/--protocol [a-z0-9]*/--protocol $BP/" "$SVC"
|
||
sed -i "s/--ha-connections [0-9]*/--ha-connections $BC/" "$SVC"
|
||
systemctl daemon-reload
|
||
systemctl restart lanremote-tunnel
|
||
echo " 已采用: --protocol $BP --ha-connections $BC"
|
||
echo " MTU: $(cat /sys/class/net/wlan0/mtu)"
|
||
echo " 备份: $BACKUP"
|