mirror of
https://gitee.com/xmz7891/ykxmz.git
synced 2026-10-18 17:10:43 +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:
@@ -0,0 +1,93 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
r'''提交这轮修复,顺便看看有没有现成的手表截图能放到官网上。'''
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
ROOT = Path(r"C:\Users\shu\Desktop\deepseekagent\LanRemote")
|
||||
GIT = r"C:\Program Files\Git\bin\git.exe"
|
||||
|
||||
MSG = """修真凶: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 台
|
||||
"""
|
||||
|
||||
|
||||
def commit() -> None:
|
||||
subprocess.run([GIT, "add", "-A"], cwd=str(ROOT), check=False)
|
||||
msg_file = ROOT / "_build" / "_cmsg6.txt"
|
||||
msg_file.write_bytes(MSG.encode("utf-8"))
|
||||
r = subprocess.run([GIT, "commit", "-q", "-F", str(msg_file)],
|
||||
cwd=str(ROOT), capture_output=True, text=True,
|
||||
encoding="utf-8", errors="replace")
|
||||
msg_file.unlink(missing_ok=True)
|
||||
print(" commit exit=%s" % r.returncode)
|
||||
show = subprocess.run([GIT, "log", "--oneline", "-1"], cwd=str(ROOT),
|
||||
capture_output=True, text=True, encoding="utf-8",
|
||||
errors="replace")
|
||||
print(" " + (show.stdout or "").strip())
|
||||
env = dict(os.environ)
|
||||
env["GIT_SSH_COMMAND"] = r'"C:\Program Files\Git\usr\bin\ssh.exe"'
|
||||
push = subprocess.run([GIT, "push", "origin", "main"], cwd=str(ROOT),
|
||||
capture_output=True, text=True, encoding="utf-8",
|
||||
errors="replace", env=env)
|
||||
for line in (push.stderr or push.stdout or "").strip().splitlines()[-2:]:
|
||||
print(" " + line)
|
||||
|
||||
|
||||
def main() -> int:
|
||||
commit()
|
||||
|
||||
print()
|
||||
print(" 官网现在有什么图可用:")
|
||||
for folder in ("_tests/shots", "android", "windows", "docs", "_build"):
|
||||
base = ROOT / folder
|
||||
if not base.is_dir():
|
||||
continue
|
||||
pics = [p for p in base.rglob("*")
|
||||
if p.suffix.lower() in (".png", ".jpg", ".jpeg", ".webp")
|
||||
and p.is_file() and p.stat().st_size > 3000]
|
||||
if pics:
|
||||
print(" %s/ (%d 张)" % (folder, len(pics)))
|
||||
for p in sorted(pics)[:8]:
|
||||
print(" %-46s %6.1f KB"
|
||||
% (p.name, p.stat().st_size / 1024))
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
Reference in New Issue
Block a user