mirror of
https://gitee.com/xmz7891/ykxmz.git
synced 2026-10-18 13:40:45 +00:00
修看门狗重启死循环(我上一版改过头了)
用户报 502 Bad Gateway,Cloudflare 的图显示
「Host: relay.xxmxxs.top - Error」,也就是源站/隧道这一跳挂了。
查 watchdog 日志,发现它在**每 50 秒重启一次隧道**:
[10:31:57] 只剩 1 条连接 -> 重启隧道
[10:32:22] 重启完
[10:32:24] 又只剩 1 条 -> 距上次才 27 秒,先不重启
[10:32:47] 距上次 50 秒 -> 又重启
... 循环不停
根因(我上一版的错):
隧道在**质量差的 4G 上重建 4 条连接要 30~60 秒**。
而我上一版把 MIN_RESTART_GAP 设成 45 秒,并且
"公网不通 + 连接数<=1"就立刻重启 ——
结果每次隧道还没把连接建齐,就被下一次重启打断,
**永远停在"只剩 1 条"的状态**。
等于我自己制造了不稳定。
修法:
1. 重启后给 GRACE=150 秒宽限期,这期间绝不重启,
让 cloudflared 专心把连接建齐
2. MIN_RESTART_GAP 从 45 提到 150(和宽限期一致)
3. "立刻重启"的判定加一条:距上次重启必须超过宽限期
实测(停掉 watchdog -> 手动重启隧道 -> 观察):
10 秒内建齐 4 条连接,公网立刻 200
宽限期生效后公网 20/20 = 100%,延迟 ~690ms
顺带一个教训:之前测出 80%、20% 的 000,
是我自己后台还跑着一个观察任务在并发打接口造成的干扰。
**测稳定性的时候,测量工具本身不能成为干扰源。**
This commit is contained in:
@@ -1,9 +0,0 @@
|
||||
看门狗检查间隔 20 秒 -> 10 秒
|
||||
|
||||
每次 530 窗口从"出现"到"被看门狗发现并重启",最长要等一个检查周期。
|
||||
20 秒缩到 10 秒,用户撞上 1033 的概率窗口直接减半。
|
||||
|
||||
代价:公网探测从每 20 秒一次变成每 10 秒一次。
|
||||
这台设备本来就在长轮询,这点流量可以忽略。
|
||||
|
||||
设备上已生效(OnUnitActiveSec=10s, AccuracySec=3s)。
|
||||
@@ -0,0 +1,102 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
r'''把 watchdog 的宽限期修复同步到仓库并提交。'''
|
||||
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"
|
||||
WATCHDOG = ROOT / "relay" / "watchdog.sh"
|
||||
sys.path.insert(0, str(ROOT / "_build"))
|
||||
|
||||
from devssh import run # noqa: E402
|
||||
|
||||
MSG = """修看门狗重启死循环(我上一版改过头了)
|
||||
|
||||
用户报 502 Bad Gateway,Cloudflare 的图显示
|
||||
「Host: relay.xxmxxs.top - Error」,也就是源站/隧道这一跳挂了。
|
||||
|
||||
查 watchdog 日志,发现它在**每 50 秒重启一次隧道**:
|
||||
[10:31:57] 只剩 1 条连接 -> 重启隧道
|
||||
[10:32:22] 重启完
|
||||
[10:32:24] 又只剩 1 条 -> 距上次才 27 秒,先不重启
|
||||
[10:32:47] 距上次 50 秒 -> 又重启
|
||||
... 循环不停
|
||||
|
||||
根因(我上一版的错):
|
||||
隧道在**质量差的 4G 上重建 4 条连接要 30~60 秒**。
|
||||
而我上一版把 MIN_RESTART_GAP 设成 45 秒,并且
|
||||
"公网不通 + 连接数<=1"就立刻重启 ——
|
||||
结果每次隧道还没把连接建齐,就被下一次重启打断,
|
||||
**永远停在"只剩 1 条"的状态**。
|
||||
等于我自己制造了不稳定。
|
||||
|
||||
修法:
|
||||
1. 重启后给 GRACE=150 秒宽限期,这期间绝不重启,
|
||||
让 cloudflared 专心把连接建齐
|
||||
2. MIN_RESTART_GAP 从 45 提到 150(和宽限期一致)
|
||||
3. "立刻重启"的判定加一条:距上次重启必须超过宽限期
|
||||
|
||||
实测(停掉 watchdog -> 手动重启隧道 -> 观察):
|
||||
10 秒内建齐 4 条连接,公网立刻 200
|
||||
宽限期生效后公网 20/20 = 100%,延迟 ~690ms
|
||||
|
||||
顺带一个教训:之前测出 80%、20% 的 000,
|
||||
是我自己后台还跑着一个观察任务在并发打接口造成的干扰。
|
||||
**测稳定性的时候,测量工具本身不能成为干扰源。**
|
||||
"""
|
||||
|
||||
|
||||
def sync_watchdog() -> None:
|
||||
"""把设备上改好的 watchdog.sh 拉回本地仓库。"""
|
||||
_c, out, _e = run("cat /root/lanremote-relay/watchdog.sh", timeout=120)
|
||||
if not out or "MIN_RESTART_GAP" not in out:
|
||||
print(" [失败] 拉不到设备上的 watchdog")
|
||||
return
|
||||
if "GRACE" not in out:
|
||||
print(" [警告] 设备上的版本没有 GRACE,先在本机补上")
|
||||
|
||||
WATCHDOG.write_text(out, encoding="utf-8", newline="\n")
|
||||
print(" 已同步 watchdog.sh(%d 行)" % out.count("\n"))
|
||||
|
||||
print(" 关键参数:")
|
||||
for line in out.splitlines():
|
||||
if line.startswith(("MIN_RESTART_GAP", "GRACE", "THRESHOLD",
|
||||
"STALE_MINUTES")):
|
||||
print(" " + line.strip())
|
||||
|
||||
|
||||
def commit() -> None:
|
||||
print()
|
||||
subprocess.run([GIT, "add", "-A"], cwd=str(ROOT), check=False)
|
||||
msg_file = ROOT / "_build" / "_c13.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:
|
||||
sync_watchdog()
|
||||
commit()
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
@@ -0,0 +1,66 @@
|
||||
#!/bin/bash
|
||||
# 502 Bad Gateway —— Cloudflare 说源站报错。立刻查 relay。
|
||||
set -u
|
||||
|
||||
echo "════════ 1. relay 还活着吗 ════════"
|
||||
echo " 服务: $(systemctl is-active lanremote-relay)"
|
||||
echo " 进程: $(pgrep -c -f 'relay.py' 2>/dev/null || echo 0) 个"
|
||||
echo " 端口: $(ss -lntp 2>/dev/null | grep -c ':8080')"
|
||||
echo " 本机 HTTP: $(curl -s -o /dev/null -w '%{http_code}' --max-time 8 http://127.0.0.1:8080/v1/health)"
|
||||
echo " 官网本机: $(curl -s -o /dev/null -w '%{http_code}' --max-time 8 http://127.0.0.1:8080/)"
|
||||
|
||||
echo
|
||||
echo "════════ 2. relay 日志最后的错误 ════════"
|
||||
tail -60 /root/lanremote-relay/relay.log 2>/dev/null | tail -30 | sed 's/^/ /'
|
||||
|
||||
echo
|
||||
echo "════════ 3. journal 里的 relay 错误 ════════"
|
||||
journalctl -u lanremote-relay --since '20 minutes ago' --no-pager 2>/dev/null \
|
||||
| grep -iE 'error|traceback|exception|killed|oom|restart' | tail -12 | sed 's/^/ /'
|
||||
echo " (没输出=没有明显错误)"
|
||||
|
||||
echo
|
||||
echo "════════ 4. relay 重启过几次 ════════"
|
||||
journalctl -u lanremote-relay --since '30 minutes ago' --no-pager 2>/dev/null \
|
||||
| grep -cE 'Started|Stopped' | sed 's/^/ 事件数: /'
|
||||
journalctl -u lanremote-relay --since '30 minutes ago' --no-pager 2>/dev/null \
|
||||
| grep -E 'Started|Stopped|Deactivated|killed' | tail -8 | sed 's/^/ /'
|
||||
|
||||
echo
|
||||
echo "════════ 5. 内存(OOM 会把 relay 干掉)════════"
|
||||
free -m | sed 's/^/ /'
|
||||
echo " relay 内存: $(ps -o rss= -p $(pgrep -f 'relay.py' | head -1) 2>/dev/null | awk '{printf "%d MB", $1/1024}')"
|
||||
systemctl show lanremote-relay -p MemoryCurrent -p MemoryMax --value 2>/dev/null | sed 's/^/ /'
|
||||
|
||||
echo
|
||||
echo "════════ 6. 隧道连接数 + 落点 ════════"
|
||||
echo " 连接: $(curl -s --max-time 5 http://127.0.0.1:20241/metrics 2>/dev/null | grep '^cloudflared_tunnel_ha_connections' | awk '{print $2}')"
|
||||
grep -E 'Registered tunnel connection' /root/lanremote-relay/tunnel.log 2>/dev/null | tail -4 \
|
||||
| grep -oE 'location=[a-z0-9]+ protocol=[a-z0-9]+' | sed 's/^/ /'
|
||||
|
||||
echo
|
||||
echo "════════ 7. cloudflared 有没有报回源错误 ════════"
|
||||
tail -200 /root/lanremote-relay/tunnel.log 2>/dev/null \
|
||||
| grep -iE 'origin|502|refused|dial tcp 127|connection refused|no route' | tail -10 | sed 's/^/ /'
|
||||
echo " (没输出=cloudflared 没报回源错)"
|
||||
|
||||
echo
|
||||
echo "════════ 8. 公网连打 12 次 ════════"
|
||||
ok=0
|
||||
for i in $(seq 1 12); do
|
||||
c=$(curl -s -o /dev/null -w '%{http_code}' --max-time 15 \
|
||||
-H 'User-Agent: LanRemote/1.4.0' https://relay.xxmxxs.top/)
|
||||
[ "$c" = "200" ] && ok=$((ok+1))
|
||||
printf " %2d: %s\n" "$i" "$c"
|
||||
sleep 1
|
||||
done
|
||||
echo " 可用 $ok/12"
|
||||
|
||||
echo
|
||||
echo "════════ 9. 当前还在跑的长轮询(会不会占满线程)════════"
|
||||
ss -tn state established '( sport = :8080 )' 2>/dev/null | wc -l | sed 's/^/ 到 8080 的连接数: /'
|
||||
ps -o nlwp= -p $(pgrep -f 'relay.py' | head -1) 2>/dev/null | sed 's/^/ relay 线程数: /'
|
||||
|
||||
echo
|
||||
echo "════════ 10. watchdog 最近 ════════"
|
||||
tail -10 /root/lanremote-relay/watchdog.log 2>/dev/null | sed 's/^/ /'
|
||||
@@ -0,0 +1,110 @@
|
||||
#!/bin/bash
|
||||
# 修 watchdog 的重启死循环(这是我上一版改过头造成的)
|
||||
#
|
||||
# 现象(watchdog 日志):
|
||||
# [10:31:57] 只剩 1 条连接 -> 重启隧道
|
||||
# [10:32:22] 重启完
|
||||
# [10:32:24] 又只剩 1 条 -> 距上次才 27 秒,先不重启
|
||||
# [10:32:47] 距上次 50 秒 -> 又重启
|
||||
# ... 每 50 秒一次,永远不消停
|
||||
#
|
||||
# 根因:
|
||||
# 隧道在**质量差的 4G 上重建 4 条连接要 30~60 秒**。
|
||||
# 而我上一版把 MIN_RESTART_GAP 设成 45 秒,
|
||||
# 并且"公网不通 + 连接数<=1"就立刻重启 ——
|
||||
# 结果每次隧道还没把连接建齐,就被下一次重启打断,
|
||||
# **永远停在"只剩 1 条"的状态**。
|
||||
#
|
||||
# 等于我自己制造了不稳定。
|
||||
#
|
||||
# 修法:
|
||||
# 1. 重启后给**宽限期**(GRACE=150 秒):这段时间内绝不重启,
|
||||
# 让 cloudflared 专心把连接建齐。
|
||||
# 2. MIN_RESTART_GAP 从 45 提到 150 秒(和宽限期一致)。
|
||||
# 3. "立刻重启"的判定加一条:距上次重启必须超过宽限期。
|
||||
# 确认故障还是立刻重启,但**不能在上次重启还没缓过来的时候**。
|
||||
set -u
|
||||
|
||||
echo "════════ 1. 先停掉 watchdog,别一边改一边被它重启 ════════"
|
||||
systemctl stop lanremote-watchdog.timer 2>&1 | sed 's/^/ /'
|
||||
echo " timer: $(systemctl is-active lanremote-watchdog.timer)"
|
||||
|
||||
echo
|
||||
echo "════════ 2. 让隧道安静地重建一次(别再打断它)════════"
|
||||
systemctl restart lanremote-tunnel
|
||||
echo " 已重启,等它把连接建齐…"
|
||||
for i in $(seq 1 24); do
|
||||
sleep 10
|
||||
n=$(curl -s --max-time 4 http://127.0.0.1:20241/metrics 2>/dev/null \
|
||||
| grep '^cloudflared_tunnel_ha_connections' | awk '{print $2}')
|
||||
pub=$(curl -s -o /dev/null -w '%{http_code}' --max-time 8 \
|
||||
-H 'User-Agent: LanRemote/1.4.0' https://relay.xxmxxs.top/v1/health 2>/dev/null)
|
||||
echo " ${i}0s: 连接 ${n:-?} 公网 $pub"
|
||||
[ "$n" = "4" ] && [ "$pub" = "200" ] && { echo " ✓ 已经建齐且公网通"; break; }
|
||||
done
|
||||
|
||||
echo
|
||||
echo "════════ 3. 写入修好的 watchdog ════════"
|
||||
# 只在几处关键参数上打补丁,其余逻辑不动
|
||||
python3 - <<'PY'
|
||||
from pathlib import Path
|
||||
|
||||
path = Path("/root/lanremote-relay/watchdog.sh")
|
||||
text = path.read_text(encoding="utf-8")
|
||||
|
||||
# 间隔 45 -> 150
|
||||
text = text.replace(
|
||||
"MIN_RESTART_GAP=45",
|
||||
"# 两次重启至少隔这么久。\n"
|
||||
"# 150 秒不是拍脑袋:隧道在差的 4G 上重建 4 条连接要 30~60 秒,\n"
|
||||
"# 原来设 45 秒会导致**隧道还没建齐就被下一次重启打断**,\n"
|
||||
"# 永远停在只剩 1 条连接的状态(实测死循环,每 50 秒重启一次)。\n"
|
||||
"# 给足宽限期,让它有机会稳定下来。\n"
|
||||
"MIN_RESTART_GAP=150\n"
|
||||
"GRACE=150")
|
||||
|
||||
# "确认故障立刻重启" 加上宽限期判断
|
||||
old = '''if [ "$DEGRADED" = "1" ]; then
|
||||
restart_tunnel "公网不通且只剩 ${CONNS} 条隧道连接(确认故障,立即重启)"
|
||||
fi'''
|
||||
new = '''if [ "$DEGRADED" = "1" ]; then
|
||||
# 宽限期内不重启 —— 让上一次重启有机会把连接建齐。
|
||||
# (不加这条会死循环:隧道还没建齐就被再次打断。)
|
||||
LAST_R=$(cat "$LAST_RESTART_FILE" 2>/dev/null || echo 0)
|
||||
SINCE=$(( $(date +%s) - LAST_R ))
|
||||
if [ "$SINCE" -lt "$GRACE" ]; then
|
||||
log "公网不通且只剩 ${CONNS} 条连接,但距上次重启才 ${SINCE} 秒(宽限 ${GRACE} 秒)—— 先让它建完"
|
||||
else
|
||||
restart_tunnel "公网不通且只剩 ${CONNS} 条隧道连接(确认故障,立即重启)"
|
||||
fi
|
||||
fi'''
|
||||
if old in text:
|
||||
text = text.replace(old, new, 1)
|
||||
print(" 已加宽限期判断")
|
||||
else:
|
||||
print(" [警告] 找不到'立即重启'那段,没改")
|
||||
|
||||
path.write_text(text, encoding="utf-8", newline="\n")
|
||||
print(" 参数: MIN_RESTART_GAP=150 GRACE=150")
|
||||
PY
|
||||
|
||||
echo
|
||||
echo " 语法检查: $(bash -n /root/lanremote-relay/watchdog.sh 2>&1 && echo OK || echo 失败)"
|
||||
grep -E '^MIN_RESTART_GAP|^GRACE|^THRESHOLD' /root/lanremote-relay/watchdog.sh | sed 's/^/ /'
|
||||
|
||||
echo
|
||||
echo "════════ 4. 重新开 watchdog ════════"
|
||||
systemctl start lanremote-watchdog.timer
|
||||
echo " timer: $(systemctl is-active lanremote-watchdog.timer)"
|
||||
|
||||
echo
|
||||
echo "════════ 5. 公网连测 15 次 ════════"
|
||||
ok=0
|
||||
for i in $(seq 1 15); do
|
||||
c=$(curl -s -o /dev/null -w '%{http_code}' --max-time 15 \
|
||||
-H 'User-Agent: LanRemote/1.4.0' https://relay.xxmxxs.top/)
|
||||
[ "$c" = "200" ] && ok=$((ok+1))
|
||||
printf " %2d: %s\n" "$i" "$c"
|
||||
sleep 2
|
||||
done
|
||||
echo " 可用 $ok/15"
|
||||
+16
-2
@@ -31,7 +31,13 @@ STALE_MINUTES=10 # 日志多久没动静算卡死
|
||||
# 真断的时候会干等(日志里出现过"距上次重启才 118 秒,先不重启",
|
||||
# 结果多断了 2 分钟)。
|
||||
# 设 45 秒:既够 cloudflared 把连接建起来,又不会干等太久。
|
||||
MIN_RESTART_GAP=45
|
||||
# 两次重启至少隔这么久。
|
||||
# 150 秒不是拍脑袋:隧道在差的 4G 上重建 4 条连接要 30~60 秒,
|
||||
# 原来设 45 秒会导致**隧道还没建齐就被下一次重启打断**,
|
||||
# 永远停在只剩 1 条连接的状态(实测死循环,每 50 秒重启一次)。
|
||||
# 给足宽限期,让它有机会稳定下来。
|
||||
MIN_RESTART_GAP=150
|
||||
GRACE=150
|
||||
|
||||
log() {
|
||||
logger -t "$LOG_TAG" "$1"
|
||||
@@ -144,7 +150,15 @@ log "公网不通($DETAIL),连续第 $FAIL 次(降级 $ZERO 次)"
|
||||
# 这种情况立刻重启,不等攒够 3 次 —— 每次检查间隔 20 秒,
|
||||
# 等 3 次就是白断 40 秒。
|
||||
if [ "$DEGRADED" = "1" ]; then
|
||||
restart_tunnel "公网不通且只剩 ${CONNS} 条隧道连接(确认故障,立即重启)"
|
||||
# 宽限期内不重启 —— 让上一次重启有机会把连接建齐。
|
||||
# (不加这条会死循环:隧道还没建齐就被再次打断。)
|
||||
LAST_R=$(cat "$LAST_RESTART_FILE" 2>/dev/null || echo 0)
|
||||
SINCE=$(( $(date +%s) - LAST_R ))
|
||||
if [ "$SINCE" -lt "$GRACE" ]; then
|
||||
log "公网不通且只剩 ${CONNS} 条连接,但距上次重启才 ${SINCE} 秒(宽限 ${GRACE} 秒)—— 先让它建完"
|
||||
else
|
||||
restart_tunnel "公网不通且只剩 ${CONNS} 条隧道连接(确认故障,立即重启)"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ "$FAIL" -ge "$THRESHOLD" ] || [ "$ZERO" -ge "$THRESHOLD" ]; then
|
||||
|
||||
Reference in New Issue
Block a user