#!/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))