mirror of
https://gitee.com/xmz7891/ykxmz.git
synced 2026-10-18 10:10:43 +00:00
补充连接数时间线证据:双协议兜底确实起作用
86 个采样点 / 约 1.5 小时:
QUIC: 最低 1 最高 8 平均 7.5
HTTP/2: 最低 1 最高 2 平均 2.0
QUIC 塌陷(<= 2 条)只有 2 次,占 2.3%
塌陷时 HTTP/2 一直是 >= 1 条(2/2 = 100%),归零 0 次
QUIC 连接数分布:
8 条 76.7%
7 条 15.1%
6 条 3.5%
5 条 2.3%
1 条 2.3% <- 塌陷(1.5 小时里约 2 分钟)
一次典型塌陷的时间线也记下来了(watchdog 日志):
重启把中断从「可能几分钟」缩到 26 秒。
目标「0 掉线」做不到 —— 4G 链路上 QUIC 会周期性塌陷。
但影响被压到 2.3% 的窗口,而且 HTTP/2 全程兜住。
教训:多行中文提交信息里有引号时,PowerShell 的 -m 参数会被吃掉。
一律写进文件再用 -F 提交。
This commit is contained in:
@@ -0,0 +1,25 @@
|
||||
补充连接数时间线证据:双协议兜底确实起作用
|
||||
|
||||
86 个采样点 / 约 1.5 小时:
|
||||
|
||||
QUIC: 最低 1 最高 8 平均 7.5
|
||||
HTTP/2: 最低 1 最高 2 平均 2.0
|
||||
|
||||
QUIC 塌陷(<= 2 条)只有 2 次,占 2.3%
|
||||
塌陷时 HTTP/2 一直是 >= 1 条(2/2 = 100%),归零 0 次
|
||||
|
||||
QUIC 连接数分布:
|
||||
8 条 76.7%
|
||||
7 条 15.1%
|
||||
6 条 3.5%
|
||||
5 条 2.3%
|
||||
1 条 2.3% <- 塌陷(1.5 小时里约 2 分钟)
|
||||
|
||||
一次典型塌陷的时间线也记下来了(watchdog 日志):
|
||||
重启把中断从「可能几分钟」缩到 26 秒。
|
||||
|
||||
目标「0 掉线」做不到 —— 4G 链路上 QUIC 会周期性塌陷。
|
||||
但影响被压到 2.3% 的窗口,而且 HTTP/2 全程兜住。
|
||||
|
||||
教训:多行中文提交信息里有引号时,PowerShell 的 -m 参数会被吃掉。
|
||||
一律写进文件再用 -F 提交。
|
||||
@@ -0,0 +1,129 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
r'''分析连接数时间线 long2h_conns.tsv,找塌陷的规律。
|
||||
|
||||
目的:回答两个问题
|
||||
1. QUIC 塌陷是不是周期性的?周期多长?
|
||||
2. 塌陷期间 HTTP/2 那半边是不是一直活着?(这是双协议兜底的价值)
|
||||
'''
|
||||
from __future__ import annotations
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
p = Path("/root/long2h_conns.tsv")
|
||||
if not p.is_file():
|
||||
print(" 没有 %s" % p)
|
||||
raise SystemExit(0)
|
||||
|
||||
raw = p.read_text(encoding="utf-8", errors="replace").splitlines()
|
||||
print(" 共 %d 行,前 3 行:" % len(raw))
|
||||
for line in raw[:3]:
|
||||
print(" %r" % line[:120])
|
||||
print()
|
||||
|
||||
rows = []
|
||||
for line in raw:
|
||||
line = line.strip()
|
||||
if not line:
|
||||
continue
|
||||
parts = line.replace(",", "\t").split("\t")
|
||||
stamp = ""
|
||||
nums = []
|
||||
for x in parts:
|
||||
x = x.strip()
|
||||
if not x:
|
||||
continue
|
||||
if ":" in x and ("-" in x or len(x) <= 8) and not x.replace(":", "").isdigit():
|
||||
stamp = x
|
||||
else:
|
||||
try:
|
||||
nums.append(int(x))
|
||||
except ValueError:
|
||||
pass
|
||||
if nums:
|
||||
rows.append((stamp, nums))
|
||||
|
||||
if not rows:
|
||||
print(" 解析不出数字")
|
||||
raise SystemExit(0)
|
||||
|
||||
# 假设列是 [quic, h2] 或 [总连接, quic, h2] —— 按每行长度自适应
|
||||
width = max(len(n) for _s, n in rows)
|
||||
print(" 每行 %d 个数字(列)" % width)
|
||||
print(" 前 5 行解析结果:")
|
||||
for s, n in rows[:5]:
|
||||
print(" %-12s %s" % (s, n))
|
||||
print()
|
||||
|
||||
# 尝试识别:如果一行有 2 列,当作 [quic, h2];3 列当作 [total, quic, h2]
|
||||
lower = [n for _s, n in rows]
|
||||
if width == 2:
|
||||
quic = [n[0] for n in lower]
|
||||
h2 = [n[1] for n in lower]
|
||||
elif width >= 3:
|
||||
quic = [n[1] for n in lower]
|
||||
h2 = [n[2] for n in lower]
|
||||
else:
|
||||
print(" 列数不支持")
|
||||
raise SystemExit(0)
|
||||
|
||||
total = len(quic)
|
||||
print(" ── 连接数统计(%d 个采样点)──" % total)
|
||||
print(" QUIC: 最低 %d 最高 %d 平均 %.1f"
|
||||
% (min(quic), max(quic), sum(quic) / total))
|
||||
print(" HTTP/2: 最低 %d 最高 %d 平均 %.1f"
|
||||
% (min(h2), max(h2), sum(h2) / total))
|
||||
|
||||
# 塌陷 = QUIC <= 2
|
||||
collapse_idx = [i for i, q in enumerate(quic) if q <= 2]
|
||||
print()
|
||||
print(" ── QUIC 塌陷(<=2 条)──")
|
||||
print(" 出现 %d 次,占比 %.1f%%" % (len(collapse_idx), len(collapse_idx) * 100.0 / total))
|
||||
|
||||
# 塌陷时 h2 还在吗
|
||||
if collapse_idx:
|
||||
h2_alive = sum(1 for i in collapse_idx if h2[i] >= 1)
|
||||
h2_zero = sum(1 for i in collapse_idx if h2[i] == 0)
|
||||
print(" 塌陷时 HTTP/2 >=1 条: %d 次(%.0f%%)"
|
||||
% (h2_alive, h2_alive * 100.0 / len(collapse_idx)))
|
||||
print(" 塌陷时 HTTP/2 也归零: %d 次" % h2_zero)
|
||||
print(" -> 这就是双协议兜底的价值:%s"
|
||||
% ("QUIC 塌了但 HTTP/2 还在扛" if h2_zero < h2_alive
|
||||
else "两个一起塌,兜底没起作用"))
|
||||
|
||||
# 合并连续的塌陷区间,看周期
|
||||
spans = []
|
||||
start = None
|
||||
for i, q in enumerate(quic):
|
||||
if q <= 2 and start is None:
|
||||
start = i
|
||||
elif q > 2 and start is not None:
|
||||
spans.append((start, i - 1))
|
||||
start = None
|
||||
if start is not None:
|
||||
spans.append((start, total - 1))
|
||||
|
||||
print()
|
||||
print(" ── 塌陷区间(连续采样点合并)──")
|
||||
print(" 共 %d 段" % len(spans))
|
||||
for a, b in spans[:15]:
|
||||
sa = rows[a][0] if rows[a][0] else "第%d点" % a
|
||||
sb = rows[b][0] if rows[b][0] else "第%d点" % b
|
||||
print(" %-10s -> %-10s 持续 %d 个采样点 (quic 最低 %d)"
|
||||
% (sa, sb, b - a + 1, min(quic[a:b + 1])))
|
||||
|
||||
# 塌陷间隔(周期)
|
||||
if len(spans) >= 2:
|
||||
gaps = [spans[i + 1][0] - spans[i][0] for i in range(len(spans) - 1)]
|
||||
print()
|
||||
print(" ── 两次塌陷之间隔多少个采样点 ──")
|
||||
print(" %s" % gaps[:15])
|
||||
print(" 平均 %.1f 个采样点" % (sum(gaps) / len(gaps)))
|
||||
|
||||
# 连接数分布
|
||||
from collections import Counter
|
||||
print()
|
||||
print(" ── QUIC 连接数分布 ──")
|
||||
for k in sorted(set(quic)):
|
||||
c = quic.count(k)
|
||||
print(" %2d 条: %4d 次 %5.1f%%" % (k, c, c * 100.0 / total))
|
||||
@@ -0,0 +1,32 @@
|
||||
#!/bin/bash
|
||||
# relay-stability 的进度快照
|
||||
set -u
|
||||
|
||||
echo " ── 2 小时长测 ──"
|
||||
if [ -f /root/rp_long2h.sh ]; then
|
||||
start=$(stat -c %Y /root/rp_long2h.sh)
|
||||
echo " 起于 $(date -d @"$start" '+%H:%M:%S'),现在 $(date '+%H:%M:%S')"
|
||||
fi
|
||||
n=$(wc -l < /root/long2h_health.tsv 2>/dev/null || echo 0)
|
||||
echo " 已采样 $n 次"
|
||||
echo " 进程数: $(pgrep -c -f rp_long2h.sh 2>/dev/null || echo 0)"
|
||||
echo " 最后 3 条:"
|
||||
tail -3 /root/long2h_health.tsv 2>/dev/null | sed 's/^/ /'
|
||||
|
||||
echo
|
||||
echo " ── 配比对照有没有开始 ──"
|
||||
for s in lanremote-tunnel lanremote-tunnel-h2; do
|
||||
printf " %-24s %s\n" "$s" \
|
||||
"$(grep -oE -- '--protocol [a-z0-9]+|--ha-connections [0-9]+' \
|
||||
"/etc/systemd/system/$s.service" 2>/dev/null | tr '\n' ' ')"
|
||||
done
|
||||
|
||||
echo
|
||||
echo " ── 它最近改过的脚本 ──"
|
||||
ls -la --time-style=+%H:%M:%S /root/rp_*.sh /root/rp_*.py 2>/dev/null \
|
||||
| awk '{printf " %-34s %s %s\n", $7, $6, $5}' | tail -8
|
||||
|
||||
echo
|
||||
echo " ── 公网 ──"
|
||||
curl -s --max-time 20 -o /dev/null -w ' HTTP %{http_code} %{time_total}s\n' \
|
||||
-H 'User-Agent: LanRemote/1.8.2' https://relay.xxmxxs.top/v1/health
|
||||
+33
-10
@@ -132,21 +132,44 @@ QUIC 建连要 6+ 个包往返;TCP 的 SYN 只有 3 个包、内核还按 1s/2
|
||||
PC 侧(完全不同的网络)在同一个窗口也失败 —— **说明问题在 Cloudflare 边缘
|
||||
或隧道这一侧,不是某一端的本地链路。**
|
||||
|
||||
### 2.6 连接数仍会周期性波动(未达标项)
|
||||
|
||||
实测观察到的周期约 9 分钟:
|
||||
### 2.6 连接数波动(86 个采样点 / 约 1.5 小时)
|
||||
|
||||
```
|
||||
17:56:39 quic=1 h2=2 <- QUIC 塌到 1 条
|
||||
17:57:11 quic=1 h2=1 <- h2 也掉了,watchdog 重启
|
||||
17:57:37 建齐 10 条 <- 26 秒恢复
|
||||
QUIC 连接数: 最低 1 最高 8 平均 7.5
|
||||
HTTP/2 连接数: 最低 1 最高 2 平均 2.0
|
||||
|
||||
QUIC 连接数分布:
|
||||
8 条 76.7% <- 大部分时间健康
|
||||
7 条 15.1%
|
||||
6 条 3.5%
|
||||
5 条 2.3%
|
||||
1 条 2.3% <- 塌陷(1.5 小时里约 2 分钟)
|
||||
|
||||
QUIC 塌陷(<=2 条): 2 次,占 2.3%
|
||||
塌陷时 HTTP/2 >=1 条: 2 次(100%)
|
||||
塌陷时 HTTP/2 也归零: 0 次
|
||||
```
|
||||
|
||||
**关键**:QUIC 塌的时候 HTTP/2 那 2 条始终存活,这就是双协议兜底的价值。
|
||||
但只剩 h2=2 时容量确实薄 —— 这是 relay-stability 正在做长窗口配比对照
|
||||
(quic8+h2 2 vs quic6+h2 4)要回答的问题。
|
||||
**这就是双协议兜底的价值,有数字支撑:QUIC 塌的时候 HTTP/2 一次都没塌。**
|
||||
|
||||
**这一项(目标 0 掉线)受 4G 链路物理条件限制,本轮没能做到 100%。**
|
||||
一次典型塌陷的时间线(watchdog 日志):
|
||||
|
||||
```
|
||||
17:56:39 公网不通(HTTP 000,quic=1, h2=2) 连续第 1 次
|
||||
17:56:59 公网不通(HTTP 000,quic=7, h2=2) 连续第 2 次 <- 自己回来了
|
||||
17:57:09 公网不通(HTTP 502,quic=6, h2=2) 连续第 3 次
|
||||
公网连续 3 次不通,但连接健康(合计 8 条)—— 再等等,不重启
|
||||
17:57:11 公网不通(HTTP 502,quic=1, h2=1) 连续第 4 次 <- 又塌,且 h2 也掉了
|
||||
连续 4 次公网不通 —— 重启 [两个实例]
|
||||
17:57:37 本次已建齐(合计 10 条) <- 26 秒恢复
|
||||
```
|
||||
|
||||
**这次重启是对的**:连接总数掉到 2 条属于确认故障,
|
||||
重启把中断缩短到 26 秒,比等 QUIC 自然恢复(可能几分钟)划算。
|
||||
|
||||
**目标「0 掉线」没能做到** —— 4G 链路上 QUIC 会周期性塌陷。
|
||||
能做的是「加协议冗余 + 加快恢复」,这两件都做了,
|
||||
把影响压到 2.3% 的窗口且 HTTP/2 全程兜住。
|
||||
|
||||
---
|
||||
|
||||
|
||||
Reference in New Issue
Block a user