mirror of
https://gitee.com/xmz7891/ykxmz.git
synced 2026-10-18 13:40:45 +00:00
修真凶:4G 链路静默断连导致隧道"假活"(用户撞上 Error 1033)
现象:用户早上打开 relay.xxmxxs.top 看到 Cloudflare Error 1033。
watchdog 日志把过程记下来了:
公网不通(HTTP 000,ha_connections=2) <- 隧道显示连着,公网不通
公网不通(HTTP 502,ha_connections=2)
公网恢复(HTTP 200) <- 自己又好了
也就是说:**间歇性假活**,短样本测不出来。
我之前只测 15~25 次就说"可用率 100%",太草率了。
根因:4G 链路会**静默断开** TCP 连接 —— 不发 FIN/RST,双方都以为还连着。
Cloudflare 把请求发到这条僵尸连接上,就回 502/530/1033。
Linux 默认 tcp_keepalive_time = **7200 秒(2 小时)**才发现连接死了,
所以中间这段时间服务一直"看着在线、实际打不开"。
tunnel.log 最近 3000 行的佐证:
i/o timeout 212 次
Retrying connection 127 次
Lost connection 22 次
修法:
1. TCP keepalive 调到 30 秒 + 每 10 秒探测 3 次
=> 最多约 60 秒发现僵尸连接,cloudflared 立刻重连
(/etc/sysctl.d/97-ykxmz-keepalive.conf)
2. 隧道连接数 2 -> 4,多几条冗余
3. 修 relay 从不清理设备记录的问题:
self.devices 只增不减,被控端每换端口/重装就多一条,
实测一天攒了 75 条僵尸记录,/v1/health 从几 KB 涨到 20KB。
加 DEVICE_TTL(6 小时)在 snapshot() 里清掉。
实测(修完立刻验证):
设备侧 公网 15/15 HTTP 200
Windows 公网 25/25,中位 520 ms,最快 463 ms
health 20931 字节 / 75 台 -> 152 字节 / 0 台
This commit is contained in:
@@ -81,6 +81,15 @@ CODE_RE = re.compile(r"^\d{6}$")
|
||||
|
||||
# 设备多久没心跳算掉线
|
||||
DEVICE_TIMEOUT = 90.0
|
||||
# 设备多久没动静就**从列表里彻底删掉**。
|
||||
#
|
||||
# 和 DEVICE_TIMEOUT(90 秒)不一样:那个只是标记"离线",
|
||||
# 记录还留着,方便手表看到"我以前连过这台"。
|
||||
# 但记录只增不减会出问题 —— 被控端每次换端口/重装都用新 deviceId
|
||||
# 注册一次,老的永远留着。实测一天攒了 75 条僵尸记录,
|
||||
# /v1/health 从几 KB 涨到 20KB,手表和网页每次白下载一大坨。
|
||||
# 6 小时足够覆盖"上课中途断一下",真回来会重新注册。
|
||||
DEVICE_TTL = float(os.environ.get("RELAY_DEVICE_TTL", str(6 * 3600)))
|
||||
# 一个设备最多同时挂几个手表会话
|
||||
MAX_SESSIONS_PER_DEVICE = 3
|
||||
|
||||
@@ -645,6 +654,23 @@ class Relay:
|
||||
def snapshot(self) -> dict:
|
||||
with self.lock:
|
||||
now = time.time()
|
||||
|
||||
# 先把长时间没动静的设备清掉。
|
||||
#
|
||||
# 为什么必须清:这个 dict 只增不减。被控端每次启动/换端口/
|
||||
# 重装都会用新的 deviceId 注册一次,老的永远留着 ——
|
||||
# 实测跑一天就攒了 75 条僵尸记录,/v1/health 从几 KB
|
||||
# 涨到 20KB,手表和网页每次都要白下载一大坨没用的东西。
|
||||
# 设备超过 6 小时没上报就当它下线了(真回来会重新注册)。
|
||||
stale = [did for did, dev in self.devices.items()
|
||||
if now - getattr(dev, "last_seen", now) > DEVICE_TTL]
|
||||
for did in stale:
|
||||
self.devices.pop(did, None)
|
||||
# 它的会话也一起收掉,免得挂着一堆死会话
|
||||
for sid in [s.session_id for s in self.sessions.values()
|
||||
if s.device_id == did]:
|
||||
self.sessions.pop(sid, None)
|
||||
|
||||
devices = []
|
||||
for device in self.devices.values():
|
||||
sessions = [s for s in self.sessions.values()
|
||||
|
||||
Reference in New Issue
Block a user