阶段二十一:网络可达性 UDP 探测与 Globalping 配额整改
阶段状态:进行中
计划状态:已完成
当前工作包:P21-10 阶段归档与 P22 启动准备(等待用户指令)
📌 结论摘要
网络态势里的“代理出口可用性”已改为“节点网络 UDP 直连可达性”。R4 订阅组不再承担 AgentMeshOS 生产代理,常规监测不再读取订阅、不再建立 Hysteria2 会话,而由 101、102 分别对在线节点做 Tailnet 路径探测:任一来源拿到直连就判绿色,两个来源都不是直连才判红色,详情逐源显示直连、Peer Relay、DERP 及实际中继节点。
Globalping 保持自动运行,但把单轮探针降到 5,Edge 改为 10 分钟、五台节点改为每小时全量检查,并把自动、手动接口、主机与入口刷新统一记入额度台账。360T7 的直连列表原先并未包含五台节点公网 IP,本轮已补齐并核验运行时集合命中与真实流量计数。
P21 另挂一个并行子计划:节点网络路径视图与双节点诊断计划。它把 Edge、DERP、Peer Relay、公网 IP、TCP、UDP、Tailnet 隧道和两节点诊断整理成可读的路径视图。用户已于 2026-11-01 确认执行,PV-0 至 PV-7 已完成代码、发布、生产回读、按节点汇总与控制面韧性评估。
🗂️ 目录
🧾 计划状态
| 项目 | 状态 | 说明 |
|---|---|---|
| 阶段状态 | 进行中 | P21-0 至 P21-9 全部闭环;24 小时双源观察与 360T7 整机重启复验均已完成,仅剩阶段归档 |
| 计划状态 | 已完成 | 网络态势、双源探针、每小时 Globalping 全量、告警链、生产回读与重启复验全部完成 |
| 当前工作包 | P21-10 阶段归档与 P22 启动准备(等待用户指令) |
P21 实施工作已全部结束;阶段滚动需用户确认 P22 启动 |
| 与 P20 的关系 | P20 已临时收口 | OfficeSummer 离线复验保留为可重启项 |
🎯 目标、成果与验收契约
| 编号 | 验收要求 | 本轮结果 |
|---|---|---|
| A1 | 101、102 独立输出每个节点的直连或非直连结果与实际路线 | 已达成,两份快照各覆盖 9 个在线节点 |
| A2 | 任一来源直连则绿色,全部非直连才红色 | 已达成,API 汇总逻辑与单测覆盖 |
| A3 | 页面不以内部编号作为主文案,DERP 显示实际节点名称 | 已达成,详情显示“DERP,经 MM”等 |
| A4 | 新探针不读 R4 订阅、不建代理会话 | 已达成,代码路径不含订阅与代理调用 |
| A5 | 双源探测有明确资源与并发上限 | 已达成,单来源并发 2、每 5 分钟一轮、锁文件互斥 |
| A6 | 自动与手动 Globalping 调用全部进入统一台账 | 已达成,单次实测写入 1 条 5 tests 记录 |
| A7 | 正常基线不超过约 40 tests/小时 | 已达到设计口径:常规 8 tests/次、Edge 3 tests/次 |
| A8 | 五台节点 IP 在保存配置与运行时直连集合一致 | 已达成,持久文件与运行时集合双向核验 |
| A9 | R4 退出自动监测后仍保留手动诊断 | 手动入口保留,自动 timer 停用留待用户确认 |
| A10 | 文档与代码门禁全部通过 | 本轮执行并在收尾复核 |
🧱 技术栈与架构选型
| 层 | 选型 | 理由 |
|---|---|---|
| 探测面 | 101、102 上的 systemd timer + tailscale ping |
复用现有 Tailnet 数据面,零新增依赖 |
| 数据面 | 原子写 JSON 快照 + 既有节点通道发布到 RR | 与现有快照消费方式一致,便于回读与回退 |
| 汇总面 | API Gateway 只读投影 | 逐源保留原始结果,避免“合并来源”丢失证据 |
| 展示面 | Console 现有网络态势模块 | 保持页面结构与交互习惯,减少改造面 |
| 配额面 | Globalping 调用统一 JSONL 台账 | 自动与手动同账,可按用途拆分核对 |
不引入 Nomad 新 Job、数据库或独立调度服务;探测只读节点登记与 Tailscale 状态。
🧩 分布式底座接入声明
| 约束 | 落实方式 |
|---|---|
| 单用户、无审批前置 | 探针由 timer 直接运行,无批准单或租约 |
| 节点登记权威 | 目标节点来自 /usr/local/lib/agentmeshos/node-registry.json |
| 控制面边界 | RR 仍是唯一汇总与展示上游,101、102 只产出本机快照 |
| 凭据边界 | 探针不读取订阅、不接触代理凭据 |
| 失败关闭 | 快照缺失或过期时页面不沿用旧绿色结论 |
📊 执行记录与证据
2026-11-02 d02/DD 公网 IP 更新与回测
用户提供并确认 d02、DD 更换公网 IPv4 后,本次先通过公网 SSH 回读两台主机的 hostname、Tailnet 地址、物理网卡地址和默认路由,确认新地址确实落在对应 VPS;随后更新 AliDNS 权威 A 记录、101/RR 的公网 SSH 入口和 DD 异机副本脚本默认地址。DNS 计划 dry-run 只包含两条 A 记录更新,apply 后权威 DNS dns17.hichina.com、dns18.hichina.com 和公共递归解析均返回新地址。
| 节点 | 新地址归属 | Globalping ICMP | Globalping TCP 443 | HTTPS 健康 | 公网 SSH | 101 Tailnet UDP | 102 Tailnet UDP |
|---|---|---|---|---|---|---|---|
| d02 | 主机名 d02-dedirock,物理网卡已回读新地址 |
17/20 成功,15% 丢包 | 12/12 成功 | https://d02.yohan.fun/__edge/health 返回 200 |
返回 d02-dedirock 与正确 Tailnet 地址 |
直连,约 177 ms | 直连,约 184 ms |
| DD | 主机名 dedirock-171060537,物理网卡已回读新地址 |
23/25 成功,8% 丢包 | 14/15 成功 | https://dd.yohan.fun/__edge/health 返回 200 |
返回 dedirock-171060537 与正确 Tailnet 地址 |
直连,约 212 ms | 直连,约 211 ms |
d02 首次回测时发现 Nginx 因启动阶段无法解析 cloud-origin.yohan.fun 而处于 failed;权威 DNS 和 d02 本机解析恢复后,执行 nginx -t、受控重启并确认 443 监听,最终 HTTPS 健康回读通过。该故障不是新 IP 归属错误,而是地址切换时暴露的 Nginx 启动依赖问题;未写入 /etc/hosts,没有用硬编码 IP 绕过 DNS。
2026-11-02 网络态势节点红色聚合根因
d02、DD 新 IP 回测后,网络态势实时分布图仍将节点标红。回读 RR 的同一轮拓扑采集证据显示:两台节点的 Tailnet 直连、公网 SSH 和各自 Edge 健康链路均为 healthy,但 DERP region 901/902 检查为 derp_connection_failed;拓扑采集器原先把 DERP 检查结果加入节点总状态,因此可选的 DERP 故障污染了节点主状态。DD 另外存在独立的 public-cloud 业务链路失败,但该链路不应改变 DD 主机状态。
修复口径:节点主状态只聚合核心管理路径(Tailnet 与必要公网 SSH);DERP、Peer Relay 和业务网站继续作为独立检查/链路显示。这样不会硬编码绿色,也不会丢失 DERP 或 Cloudreve 的真实故障,只避免“单项能力失败 = 整台主机失败”的错误聚合。该修复补充了 operational_node_status 回归测试;后续发布后必须回读 d02、DD、dog 的节点颜色、独立 DERP/业务链路状态和实时检查时间。
2026-11-02 RR 中国方向公网 TCP 多端口复核
历史记录显示,2026-11-01 曾从中国方向观测到 RR 公网 TCP 443、47522、80、8888、32118、39120 同时失败;但 Memory 也保留了 2026-10-30 同一路径 443 与 47522 均 6/6 open 的反例。因此该问题应定义为“按时间和观测来源变化的选择性/间歇性公网 TCP 故障”,不能把历史窗口固化成 RR 永久 TCP 封禁。
本次从 Globalping 中国方向对 RR 当前公网地址做了多端口实测:
| TCP 端口 | 用途 | 结果 |
|---|---|---|
| 80 | 公网 HTTP/重定向入口 | 9/9 成功 |
| 443 | 公网 HTTPS 入口 | 8/9 成功,约 11% 丢包 |
| 47522 | RR 真实 SSH 运维入口 | 9/9 成功 |
结论:当前 RR 的公网 TCP 通路已恢复可用,但 443 存在轻微丢包;这不能推翻历史故障,只说明历史故障不是永久状态。后续公网入口判断必须同时记录观测来源、端口、时间和测量 ID,不再用单次 443 结果代表“所有 TCP 正常”或“所有 TCP 都被封”。
2026-11-02 23:15 多轮复核(消除单轮噪声)
对同一地址连续复测,确认上一轮 11% 属于单次探针噪声,不是持续性故障:
| 轮次 | 端口 | 结果 | 丢包 | 观测时间 |
|---|---|---|---|---|
| 第 1 轮 | 443 | 4/4 成功 | 0% | 2026-11-02 23:15 CST |
| 第 2 轮 | 443 | 4/4 成功 | 0% | 2026-11-02 23:15 CST |
| 第 3 轮 | 443 | 4/4 成功 | 0% | 2026-11-02 23:15 CST |
| 交叉验证 | 80 | 4/4 成功 | 0% | 2026-11-02 23:15 CST |
| 交叉验证 | 47522(SSH) | 4/4 成功 | 0% | 2026-11-02 23:15 CST |
结论:RR 公网 443 当前连续三轮全通;历史窗口内的故障仍按“时间与来源相关的间歇性阻断”记录,不用本次结果覆盖历史,也不用历史结果否定当前。
2026-11-02 Cloudreve 公网链路超时根因与修复
public-cloud 长时间显示超时,但 DD 本机 Cloudreve 容器正常、端口 5212 返回 200。根因不在 Cloudreve,而在 MM 的 Edge Nginx 回源写法:
| 层 | 证据 | 说明 |
|---|---|---|
| 配置 | proxy_pass http://cloud-origin.yohan.fun:5212; 直接写域名 |
Nginx 只在加载配置时解析一次,之后固定使用旧地址 |
| 进程 | 回源 Nginx 主进程启动于 2026-10-27 06:44 | DD 换 IP 后进程未重载,仍连接旧地址 |
| DNS | MM 当前解析 cloud-origin.yohan.fun 已指向 DD 新地址 |
名称解析本身正确 |
| 直连 | MM 直连 DD 新地址 5212 返回 200,耗时 56 ms | 网络与业务均正常 |
| 现象 | MM 本机访问 cloud.yohan.fun 15 秒 0 字节 |
与“旧 upstream 握手无响应”一致 |
修复:Edge Nginx 模板改为 resolver + 变量写法,域名在每次建连时重新解析,TTL 15 秒,仅 IPv4。契约测试新增负向回归,禁止再生成静态域名 proxy_pass。部署到 MM 后的实测:
| 检查项 | 结果 |
|---|---|
MM 本机 https://cloud.yohan.fun/status.php |
200,0.22 秒 |
公网 https://cloud.yohan.fun/status.php |
200,4.4 秒 |
公网 https://www.threedogs.vip/ |
200(修复前 504) |
拓扑快照 public-cloud 链路 |
healthy |
该问题与 dog 历史故障同源:域名回源被静态解析后,换 IP 不会自动生效。后续所有 Edge 候选机上线、换 IP 或重建站点后,必须确认回源使用动态解析,不能靠重启 Nginx 或写 hosts 绕过。
2026-11-02 DERP 901 恢复确认
DERP 901 的失败不是 derper 进程故障,而是资格控制器要求“连续两次健康观测”才重新准入。补做一次 DD 的正式探测后,recovery_count 由 1 升到 2,控制器自动把 region 901 写回 DERP Map 并重启 Headscale;RR 与 101 两端 tailscale debug derp 901 均成功建立 DERP 连接,902 同样正常。整个过程没有手改 Map 文件。
| 环节 | 实测结果 |
|---|---|
| 101 探针 | 9 个在线节点:6 直连、3 DERP、0 无响应 |
| 102 探针 | 9 个在线节点:6 直连、3 DERP、0 无响应 |
| 双源一致项 | RR、dog、Home、NAS、Summer 均为直连 |
| 双源差异项 | MM、d02、DD 两个来源都只能走 DERP |
| 快照落地 | RR 同时存在 tailnet-udp-v1.json 与 tailnet-udp-102-v1.json |
| Globalping 台账 | 单次自动 Edge 检查写入 1 条请求、5 tests,坏行 0 |
| 360T7 持久配置 | direct_ip 21 条、格式异常 0,五台节点 IP 均在列 |
| 360T7 运行时 | 五台 IP 在 inet passwall psw_white_static 全部命中 |
| 直连真实流量 | 直连返回规则已有累计包计数,说明分流规则实际生效 |
| 退役探针告警 | 旧 SearXNG stale-check 告警已由正式恢复事件关闭;当前告警中心未处理数量为 0 |
| 告警中心历史展示 | 后端按告警数据库全量统计未读/处置状态,页面区分当前待处理与历史未读,保留最近 100 条展示 |
| Tailnet unit | 101、102 探针服务均以 ConditionFileIsExecutable=/usr/bin/tailscale 重新部署,unit verify 与真实运行通过 |
360T7 直连规则返工与复验
这次返工包含两个错误,必须一起纠正:一是把错误的配置对象当成“直连列表”,二是第一次追加时原文件末尾没有换行,导致两条 IP 粘连、nft 规则语法错误、PassWall 重载失败。第二点已当场回滚重写,下面是重做后的四层证据。
| 层次 | 证据 | 结论 |
|---|---|---|
| LuCI 源码 | client/rule_list.lua 用 /usr/share/passwall/rules/ 拼路径,direct_list 页读写 direct_ip 文件 |
“直连列表”就是该文件,不是 UCI 对象 |
| 持久文件 | direct_ip 共 21 条,五台节点公网 IP 逐条命中,位于 overlay/ubifs 持久分区 |
规则来源可持久化 |
| 运行时集合 | 重启 PassWall 重建后,五台 IP 在 inet passwall psw_white_static 逐条命中 |
文件内容进入运行时 |
| 真实流量 | 对 MM 执行 3 次 tailscale ping,直连返回规则计数合计 +14 包 |
节点流量确实走直连而不是 PassWall |
曾用过的错误对象:
| 曾用对象 | 实际含义 | 为什么不能用 |
|---|---|---|
psw_vps |
PassWall 自身的节点或负载均衡集合 | 与用户维护的直连列表无关 |
passwall.Direct.ip_list |
分流模式(shunt)的分流规则 | 不是 LuCI“直连列表”页保存的对象 |
inet fw4 里的 psw_white_static |
表名查错 | 真实集合在 inet passwall 表 |
🔍 根因与防护
本轮最主要的方法性错误不是命令本身,而是取证对象没有先建立映射:先把 psw_vps 当直连列表,再把 passwall.Direct.ip_list 当直连列表,还用 inet fw4 去查只存在于 inet passwall 的集合,于是连续得出“未命中”的错误结论。
防护不变量:
- 判断任何集合成员前,先确认界面名称对应的持久对象与运行时对象。
- 区间集合禁止用字符串包含代替语义判断。
- 任何“未命中/不存在”结论至少需要保存配置、运行时状态和一次反例检查。
- 用户指出结论反常时,旧结论立即降级为未验证,必须改变取证路径。
- 面向用户先给业务含义和影响,内部字段与编号只作为二级证据。
🛠️ 工作包状态
| 工作包 | 状态 | 说明 |
|---|---|---|
| P21-0 规则与备份 | 完成 | 全局规则更新、Memory 回读、两条防复发机制入库 |
| P21-1 探测契约 | 完成 | 快照结构、路线枚举、二态规则与单测 |
| P21-2 双源探测 | 完成 | 101、102 均产出可复现快照 |
| P21-3 API 与 Console | 完成 | 逐源分行、DERP 名称、台账展示 |
| P21-4 Globalping 配额与台账 | 完成 | 5 probes、10 分钟 Edge、五台节点每小时全量、统一台账;设计预测约 80–100 tests/小时 |
| P21-5 360T7 直连闭环 | 完成 | 用户于 2026-11-02 重启路由器。重启后只读回读:/usr/share/passwall/rules/direct_ip 21 条,运行时 inet passwall psw_white_static 五台节点 IP 用 nft get element 逐条判定全部命中(该集合 flags interval,不能用字符串 grep 判断成员) |
| P21-6 影子观察 | 完成 | 2026-11-01 11:34 至 2026-11-02 11:34 连续运行;101/102 timer active,快照持续更新,无 stale、服务失败或资源堆积。11:45 101 视角 dog 瞬时超时,11:48 Tailnet 即时复核恢复 |
| P21-7 R4 退役 | 完成 | 101、102 的 R4 探针 timer 与 RR 的计划器、告警 timer 已停用并撤销开机自启;手动诊断入口保留 |
| P21-8 文档与发布 | 完成 | 文档、代码、退役探针告警修复、Tailnet unit 条件修复、提交推送、生产回读和运行态复验完成 |
| P21-9 告警中心历史展示治理 | 完成 | 告警统计改为数据库全量,页面明确区分当前待处理与历史未读;生产容器已运行提交 7e040d20 |
🔁 回退方案
| 层 | 回退动作 |
|---|---|
| 探测 | 停用 agentmeshos-tailnet-udp-probe*.timer,恢复 R4 timer |
| 展示 | 回退 Console 与 API Gateway 上一完整镜像 |
| 配额 | 恢复上一版 collector 单元与参数 |
| 360T7 | 用 temp/p21-360t7/direct_ip.bak-* 覆盖并重启 PassWall |
任何回退都保留 last-known-good 快照,不用旧绿色结果冒充当前可用。
⚠️ 未决项
| 未决项 | 建议 | 状态 |
|---|---|---|
| R4 自动探针停用 | 已完成停用与开机自启撤销,页面不依赖 R4 结果 | 完成 |
| 24 小时影子观察 | 已完成:2026-11-01 11:34 至 2026-11-02 11:34 连续运行;101/102 timer active,快照持续更新,无 stale、服务失败或资源堆积 | 已关闭;短时路径抖动按节点网络动态变化记录,不作为探针停摆 |
| 360T7 整机重启复验 | 用户已重启;重启后持久文件 21 条、运行时区间集合五台 IP 全部命中 | 完成 |