mirror of
https://gitee.com/xmz7891/ykxmz.git
synced 2026-10-18 11:20:43 +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 走的是另一个分支。查了半天才发现是验证方法错了。
179 lines
6.6 KiB
Bash
179 lines
6.6 KiB
Bash
#!/bin/bash
|
||
# quic+6 vs http2+4:用**真实长轮询**对照,方法完全一致。
|
||
#
|
||
# 为什么必须用长轮询测:
|
||
# 之前用 /v1/health 那种"每次新建连接"的方式测,
|
||
# 量到的是冷启动开销,和真实业务(复用连接的长轮询)差很多。
|
||
# 而且那种方式会看到 18 秒的尾巴 —— 长轮询完全没有。
|
||
#
|
||
# 为什么这次结果可信:
|
||
# 上一轮 A/B 里 quic 那组因为**两次探针用了同一个配对码**,
|
||
# 第二次注册被"一个码只能一台设备"规则拒掉,token 拿到空的,
|
||
# 8 次全 401 —— 那一轮数据作废。这次每个探针都用唯一的新码。
|
||
#
|
||
# 为什么值得测 QUIC:
|
||
# 刚才查出来:隧道连接 30 分钟 0 掉线、0 重连,很稳;
|
||
# 但请求级偶发 000(10 分钟 6 次)。
|
||
# 这是 HTTP/2 over TCP 的**队头阻塞** ——
|
||
# 一条 TCP 上丢一个包,那条连接上所有流一起卡。
|
||
# QUIC 每个流独立恢复,理论上正好治这个。
|
||
set -u
|
||
|
||
PUB=https://relay.xxmxxs.top
|
||
UA='LanRemote/1.8.1'
|
||
SVC=/etc/systemd/system/lanremote-tunnel.service
|
||
BACKUP=/root/lanremote-tunnel.service.bak.q.$(date +%s)
|
||
cp -a "$SVC" "$BACKUP"
|
||
ROUNDS=${1:-10}
|
||
|
||
set_params() {
|
||
local proto="$1" conns="$2"
|
||
if grep -q -- '--protocol' "$SVC"; then
|
||
sed -i "s/--protocol [a-z0-9]*/--protocol $proto/" "$SVC"
|
||
else
|
||
sed -i "s|\(ExecStart=.*cloudflared tunnel\)|\1 --protocol $proto|" "$SVC"
|
||
fi
|
||
if grep -q -- '--ha-connections' "$SVC"; then
|
||
sed -i "s/--ha-connections [0-9]*/--ha-connections $conns/" "$SVC"
|
||
else
|
||
sed -i "s|\(ExecStart=.*cloudflared tunnel\)|\1 --ha-connections $conns|" "$SVC"
|
||
fi
|
||
systemctl daemon-reload
|
||
systemctl restart lanremote-tunnel
|
||
}
|
||
|
||
wait_ready() {
|
||
local want="$1"
|
||
for i in $(seq 1 30); do
|
||
sleep 5
|
||
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:-0}" -ge "$want" ] && return 0
|
||
done
|
||
return 1
|
||
}
|
||
|
||
new_probe() {
|
||
# 每次都用全新的 deviceId + 全新的配对码,避免被"一码一机"拒掉
|
||
local stamp
|
||
stamp=$(date +%s%N | cut -c1-13)
|
||
local dev="qprobe-${stamp}"
|
||
local code
|
||
code=$(printf "%06d" $(( (stamp / 7) % 1000000 )))
|
||
local reg
|
||
reg=$(curl -s --max-time 30 -X POST "$PUB/v1/agent/register" \
|
||
-H 'Content-Type: application/json' -H "User-Agent: $UA" \
|
||
-d "{\"deviceId\":\"$dev\",\"code\":\"$code\",\"name\":\"qprobe\",\"version\":\"1.8.1\"}")
|
||
local tok
|
||
tok=$(echo "$reg" | python3 -c "import sys,json; print(json.load(sys.stdin).get('token',''))" 2>/dev/null)
|
||
PROBE_DEV="$dev"
|
||
PROBE_TOK="$tok"
|
||
PROBE_CODE="$code"
|
||
}
|
||
|
||
cleanup_probe() {
|
||
local key
|
||
key=$(cat /root/lanremote-relay/data/admin_key.txt 2>/dev/null)
|
||
[ -n "${PROBE_DEV:-}" ] && curl -s --max-time 20 -X POST \
|
||
"http://127.0.0.1:8080/v1/admin/delete" -H "X-Admin: $key" \
|
||
-H 'Content-Type: application/json' \
|
||
-d "{\"deviceId\":\"$PROBE_DEV\"}" > /dev/null 2>&1
|
||
}
|
||
|
||
run_round() {
|
||
local label="$1" proto="$2" conns="$3"
|
||
|
||
echo "════════ $label ════════"
|
||
set_params "$proto" "$conns"
|
||
if wait_ready "$conns"; then
|
||
echo " 连接就绪($(curl -s --max-time 4 http://127.0.0.1:20241/metrics 2>/dev/null | grep '^cloudflared_tunnel_ha_connections' | awk '{print $2}') 条)"
|
||
else
|
||
echo " ! 连接没建齐,仍然继续测"
|
||
fi
|
||
echo " 落点:"
|
||
curl -s --max-time 5 http://127.0.0.1:20241/metrics 2>/dev/null \
|
||
| grep 'server_locations.*} 1' | sed 's/^/ /'
|
||
sleep 15
|
||
|
||
new_probe
|
||
if [ -z "${PROBE_TOK:-}" ]; then
|
||
echo " [失败] 探针注册没拿到 token,这轮作废"
|
||
echo "$label|REGFAIL|0|0|0" >> /tmp/qab.txt
|
||
return 1
|
||
fi
|
||
echo " 探针 code=$PROBE_CODE token=${#PROBE_TOK} 字符"
|
||
|
||
local mark
|
||
mark=$(wc -l < /root/lanremote-relay/tunnel.log 2>/dev/null || echo 0)
|
||
local ok=0 fail=0 times=() fails=""
|
||
for i in $(seq 1 "$ROUNDS"); do
|
||
out=$(curl -s -o /dev/null -w '%{http_code} %{time_total}' --max-time 100 \
|
||
-X POST "$PUB/v1/agent/poll" -H "X-Token: $PROBE_TOK" \
|
||
-H "User-Agent: $UA")
|
||
code=$(echo "$out" | awk '{print $1}')
|
||
ms=$(echo "$out" | awk '{printf "%d", $2*1000}')
|
||
if [ "$code" = "200" ]; then
|
||
ok=$((ok+1)); times+=("$ms")
|
||
printf " %2d: 200 %6dms\n" "$i" "$ms"
|
||
else
|
||
fail=$((fail+1)); fails="$fails ${i}:${code}"
|
||
printf " %2d: %-4s **失败**\n" "$i" "$code"
|
||
fi
|
||
done
|
||
|
||
local stats
|
||
if [ "${#times[@]}" -gt 0 ]; then
|
||
stats=$(printf '%s\n' "${times[@]}" | sort -n | awk '{a[NR]=$1} END {
|
||
printf "中位 %d P90 %d 最大 %d", a[int(NR/2)+1], a[int(NR*0.9)+1], a[NR]}')
|
||
else
|
||
stats="无数据"
|
||
fi
|
||
|
||
local reconn
|
||
reconn=$(tail -n +$((mark+1)) /root/lanremote-relay/tunnel.log 2>/dev/null \
|
||
| grep -c 'Registered tunnel connection' || echo 0)
|
||
|
||
echo " == $ok/$ROUNDS 成功 耗时: $stats ms 本轮重连 $reconn 次"
|
||
echo " 失败:$fails"
|
||
echo "$label|$ok|$ROUNDS|$((ok*100/ROUNDS))|$stats|$reconn" >> /tmp/qab.txt
|
||
cleanup_probe
|
||
echo
|
||
}
|
||
|
||
rm -f /tmp/qab.txt
|
||
|
||
# 先基线,再候选 —— 同一网络条件下先后测,尽量公平
|
||
run_round "http2+4" http2 4 || true
|
||
run_round "quic+6" quic 6 || true
|
||
|
||
echo "════════ 汇总 ════════"
|
||
printf " %-10s %-10s %-8s %-32s %s\n" "配置" "成功" "可用率" "耗时" "本轮重连"
|
||
while IFS='|' read -r label ok total pct stats reconn; do
|
||
if [ "$ok" = "REGFAIL" ]; then
|
||
printf " %-10s 探针注册失败,作废\n" "$label"
|
||
else
|
||
printf " %-10s %-10s %-8s %-32s %s\n" "$label" "$ok/$total" "${pct}%" "$stats" "$reconn"
|
||
fi
|
||
done < /tmp/qab.txt
|
||
|
||
echo
|
||
echo "════════ 决策 ════════"
|
||
B_OK=$(grep '^http2+4' /tmp/qab.txt | cut -d'|' -f4)
|
||
Q_OK=$(grep '^quic+6' /tmp/qab.txt | cut -d'|' -f4)
|
||
B_REC=$(grep '^http2+4' /tmp/qab.txt | cut -d'|' -f6)
|
||
Q_REC=$(grep '^quic+6' /tmp/qab.txt | cut -d'|' -f6)
|
||
echo " 基线: 可用率 ${B_OK:-?}% 重连 ${B_REC:-?}"
|
||
echo " 候选: 可用率 ${Q_OK:-?}% 重连 ${Q_REC:-?}"
|
||
if [ "${Q_OK:-0}" -ge "${B_OK:-0}" ] && [ "${Q_OK:-0}" -ge 90 ]; then
|
||
echo " → 采用 quic+6"
|
||
else
|
||
echo " → 保留 http2+4"
|
||
cp -a "$BACKUP" "$SVC"
|
||
systemctl daemon-reload
|
||
systemctl restart lanremote-tunnel
|
||
fi
|
||
sleep 15
|
||
echo
|
||
echo " 最终参数: $(grep -oE '\-\-protocol [a-z0-9]+|--ha-connections [0-9]+' "$SVC" | tr '\n' ' ')"
|
||
echo " 备份: $BACKUP"
|