408 lines
43 KiB
Markdown
408 lines
43 KiB
Markdown
# 交接单 · 参数表 · 观测 · 权限评估(覆盖网络线 · 序 ⑤)
|
||||
|
|
|
|||
|
|
> **线**:覆盖网络线 | **序**:⑤(定序 ③→④→⑤,见入口 §0)
|
|||
|
|
> **性质**:**规划棒**产出(本单只出单,⛔ 未动任何服务器、未改任何代码)
|
|||
|
|
> **产出时间**:2026-09-17 09:18 | **规划会话**:覆盖网络线-序5规划棒
|
|||
|
|
> **唯一来源**:`覆盖网络_应用场景与待完善清单_20260916.md` **§五 第 5 项**(= 「参数表 + 观测最小集 + 权限评估(P1 三条)」,状态 **可并行**)+ 同文件 **§四 P1 行**(三条缺口的原文)+ `交接单_443兜底_20260917.md` **§8.7 / §8.8**
|
|||
|
|
> **上一轮**:序 ④ 已收官(`交接单_443兜底_20260917.md` §8)⇒ ⛔ 不要重做 ② / ③ / ④
|
|||
|
|
> **执行棒**:按本单 §5 开工,**不读规划会话上下文**;收口必须回填 §8。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## §1 目标
|
|||
|
|
|
|||
|
|
**把「参数 / 观测 / 权限」三件事收成可交付的三件产物**,使覆盖网络的容量结论从"结构可信"变为"**可复算**"、运行状态从"靠人读日志"变为"**一条命令出 PASS/FAIL**"、权限面从"没评估过"变为"**逐项有结论**":
|
|||
|
|
|
|||
|
|
1. **参数表固化** —— 新建**唯一一张**参数表,把散在 6 份文档里的输入参数(设备占比 / 打洞率 / 每玩家带宽 / 消息频率 / 心跳)+ 代码里已固化的常量收成一张表,**每行带「来源等级 + 来源定位」**;并填掉 443 单 **§8.8** 留下的 **45% 口径待填参数位**(relay `--max-hosts` 数值 / `/status.capacity{max,used}` 语义 / `retryAfterMs` 口径)。
|
|||
|
|
2. **观测最小集** —— 定出**最小指标集 + 阈值 + 判别器**,落成**一个探针脚本**(一条命令、一个退出码);补上今天**唯一缺的计数器**(`DIAL` 只有日志行、无法被脚本断言)。
|
|||
|
|
3. **权限影响评估(R5)** —— 对「虚拟网卡驱动 / 骨干开端口 / nft 打洞 / 第二中继机(L3) / 443 兜底入口 / relay 拨号白名单」逐项出**权限面评估表**,结论只允许是「**收窄**」或「**维持**」;**L3 跨机真容灾只评估、不实施**。
|
|||
|
|
|
|||
|
|
**判定"做完了没有"** = §6 的 **E1–E9 全绿**(每条都能被第三方复现)。
|
|||
|
|
|
|||
|
|
**为什么这是序 ⑤ 的最小正确形态**(不是妥协,是已排过序):
|
|||
|
|
- 清单 §五 第 5 项原文就是**三条一体**、且标注「可并行」;三条**本质耦合**:45% 口径要填数值 ⇒ 数值要么来自参数表内的其它参数(推导)、要么来自实测(序 ⑥);而"打洞率"这类参数要拿实测值,前置是**权限评估**(打洞需虚拟网卡/管理员权限)⇒ 拆开做会各留一个空洞。
|
|||
|
|
- 参数表的性质是「**固化**」(清单 §五 用词),**不是重新推演** ⇒ 本单不引入新模型、不引第三方依赖、不做架构改动。
|
|||
|
|
- 443 单已把「**不做容量承诺**」显式后置给序 ⑤(其 §4.1-6 / §8.8)⇒ 本单必须**把那个洞填上**,否则兜底入口启用后 `--max-hosts=0`(不限)等于**没有过载保护**。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## §2 只读前置(⛔ 只读,不改)
|
|||
|
|
|
|||
|
|
> 执行前逐条核一遍,任何一条与"期望"不符 ⇒ **先停下来报告**,别猜。
|
|||
|
|
> `47 = 47.77.182.89`、`106 = 106.54.21.172`;⚠️ ssh 别名 `bt-server` 端口**已陈旧**(配置写 `32022`,实测 `Connection refused`)⇒ **用 `-p 22`**(443 单 §8.7-⑤ 已记,⛔ 不必再改 `~/.ssh/config`)。
|
|||
|
|
|
|||
|
|
| # | 核什么 | 命令 | 期望 |
|
|||
|
|
|---|---|---|---|
|
|||
|
|
| P1 | 三单元在跑(⚠️ **nginx 不归 systemd 管**,443 单已定口径) | `ssh -p 22 47 'systemctl is-active dshs dshs-relay dshs-pg'` + `ssh -p 22 47 'ss -lntp \| grep -E ":(443\|20080)\b"; pgrep -c nginx'` | 3×`active`;443 在听;nginx 进程数 > 0 |
|
|||
|
|
| P2 | **relay `/status` 全字段原文**(= 观测现状基线,收尾要对照) | `ssh -p 22 47 'curl -s 127.0.0.1:20080/status'` | 含 `online[]` / `capacity{max,used,free?}` / `identityRequired` / `identityOk` / `trustedSigners` / `revokedHosts` / `endpoints[]` / `networks[]` / `counters{authed,authFailed}` |
|
|||
|
|
| P3 | 现役容量参数(**45% 口径的空位就在这**) | `ssh -p 22 47 'systemctl cat dshs-relay \| grep -nE "max-hosts\|ExecStart"'` | `--max-hosts` **未出现**(默认 `0` = 不限)⇒ 本单 S4 要填 |
|
|||
|
|
| P4 | relay 侧参数常量(参数表要收的"代码事实") | 本机 `grep -n "MAX_ENTRIES\|MAX_ENTRY_LEN\|DEFAULT_CAPACITY_RETRY_AFTER_MS\|refreshAfterSeconds\|300\|5_000" src/net/relay/directory.ts src/net/relay/server.ts` | `MAX_ENTRIES=8` / `MAX_ENTRY_LEN=512` / `capacityRetryAfterMs=5000` / 目录刷新 `300 s` / 取目录超时 `5 s` |
|
|||
|
|
| P5 | 端口区间与回环池现状(观测要断言的对象) | `ssh -p 22 47 'ss -lntp \| wc -l'`;`ssh -p 22 47 'nft list ruleset \| wc -l'` | 443 单收口态 = 监听口 **79** / nft **72**(⚠️ 若不同,以本次实测为新基线并写明) |
|
|||
|
|
| P6 | **47 的机器规格**(`--max-hosts` 数值的**直接输入**;旧记录 1.8 GB / 2 核 是 09-08 的,**必须复核**) | `ssh -p 22 47 'nproc; free -m \| head -2; df -h / \| tail -1'` | 实测值(⛔ 不得沿用旧记录) |
|
|||
|
|
| P7 | 跨云实测带宽(旧记录 47↔106 **~22 KB/s**,**必须复核**) | 走既有 relay 数据面做**小样本**(≤1 s、≤1 MB) | 实测值(⛔ 不得沿用旧记录;⛔ 不许对生产做压测) |
|
|||
|
|
| P8 | 106 的会合 env(⛔ **只记录,不动**) | `ssh -p 22 106 'grep -rn "DSHS_RENDEZVOUS_URL\|DSHS_RELAY_URL\|DSHS_OVERLAY" /etc/systemd/system/*.d/ /etc/dshs-cluster.env 2>/dev/null'` | 106 **有** `DSHS_RENDEZVOUS_URL=wss://alotbuy.com/dshs-relay` ⇒ 🔴 **agent 面不吃引导链**,⛔ 不许顺手撤(撤掉 = `tunnel===undefined` 生产回归,443 单 §8.2/§8.7-② 已判不执行) |
|
|||
|
|
| P9 | 本机代码基线 + **一个必须知道的事实** | `git -C D:/github/dsh_shenxian rev-parse HEAD`;`git -C D:/github/dsh_shenxian status --porcelain -- src/net/relay/` | `640813e`;输出 `?? src/net/relay/`(**整目录未被 git 跟踪** ⇒ 443 单 §8.1 注)⇒ ⛔ **永不 `git checkout --`**(会连带丢掉工作区其它未提交改动,且拿不回覆盖网络线代码) |
|
|||
|
|
| P10 | 参数散落点(⛔ **只 grep 计数,不做全库摸底**) | 对清单 §三 点名的 6 份文档逐份 `grep -c` 关键参数词(`打洞率\|jitter\|KB/s\|扇出\|心跳`) | 每份的命中数(用于 S1 的"散落点清单",⛔ 不是重读全文) |
|
|||
|
|
|
|||
|
|
**判据先说清(P6/P7 → S4 的因果)**:`--max-hosts` 只能从**实测**机器规格+**实测**单节点成本推出;沿用旧记录会得到一个不可复算的数 ⇒ **P6/P7 是硬前置,不是"顺便看看"**。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## §3 范围
|
|||
|
|
|
|||
|
|
### 3.1 要改的(且只有这些)
|
|||
|
|
|
|||
|
|
| 层 | 位置 | 改什么 |
|
|||
|
|
|---|---|---|
|
|||
|
|
| 工作区文档 | **新建** `参数表_覆盖网络_20260917.md`(工作区根) | 唯一参数表:`参数 / 值 / 单位 / 来源等级(实测·估值·推导·待测) / 来源定位(文件:行) / 复算式`;45% 口径在此**填出数值** |
|
|||
|
|
| 本机 · 代码 | **新建** `scripts/overlay-probe.cjs` + `test/overlay-probe.test.mjs` | 观测最小集的**唯一入口**:一条命令、打印 ≤12 行、退出码 0/1 |
|
|||
|
|
| 本机 · 代码 | `src/net/relay/server.ts`(**唯一代码改动,只加计数器**) | `counters` 增 `dial` / `dialDenied` / `dialFailed`(判别器计数),随 `/status` 暴露 |
|
|||
|
|
| 本机 · 代码 | `test/relay.test.mjs`(或就近新增用例文件) | 计数器三分支的**先红后绿**用例 |
|
|||
|
|
| 47 · systemd | **新建** `/etc/systemd/system/dshs-relay.service.d/capacity.conf` | `Environment=DSHS_RELAY_MAX_HOSTS=<参数表数值>` ⇒ 45% 口径**生效**(⛔ 不是硬编码进代码) |
|
|||
|
|
|
|||
|
|
### 3.2 ⛔ 不动什么(防顺手扩大)
|
|||
|
|
|
|||
|
|
- ⛔ **不动官方 dsh 主程序与缓存**(R2)——`src/net/relay/*` 是**自研**代码,可动,但**只加计数器**;⛔ 不改 `HELLO` / `DIAL` / `DIAL_ACK` 帧格式、⛔ 不改鉴权与网络隔离语义、⛔ 不改 `identityRequired` 任何行为
|
|||
|
|
- ⛔ **不碰序 ②/③/④ 成果**:网抽象与逻辑名索引、引导三级链、`DSHS_OVERLAY_BOOTSTRAP_SEEDS`、`DSHS_OVERLAY_ADDR_OVERRIDES`、`relay-direct.conf`(443 兜底)、四层密钥与 `relay-keys.json`
|
|||
|
|
- ⛔ **不改 106 的 `DSHS_RENDEZVOUS_URL`**(P8;字面撤掉 = 生产回归)
|
|||
|
|
- ⛔ **不做 L3 跨机真容灾**(只出权限评估;落地归序 ⑥)
|
|||
|
|
- ⛔ **不新增公网端口 / 不新增 DNS 记录 / 不改 nginx / 不动 Cloudflare**
|
|||
|
|
- ⛔ 不碰数据面(打洞 / UDP)、不碰 presence / 房间层(清单 §五 第 7 步)
|
|||
|
|
- ⛔ **不做 dashboard、不引外部监控依赖**(观测最小集 = 一个脚本,不是一套系统)
|
|||
|
|
- ⛔ 不 commit、不 push
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## §4 决策点
|
|||
|
|
|
|||
|
|
### 4.1 已定项(规划棒已拍 —— 执行棒**不得自行更改**;要改必须回写 §8 并说明理由)
|
|||
|
|
|
|||
|
|
1. **三条一体、一单交付**,参数表的**唯一落盘位置** = 工作区根 `参数表_覆盖网络_20260917.md`。⛔ 不再往那 6 份文档里各写一份(那正是"散在 6 份、不可复算"的成因,清单 §三 第 1 条)。
|
|||
|
|
2. **参数表必须有「来源等级」列**:`实测 / 估值 / 推导 / 待测`。⛔ **禁止把估值写成实测**;凡 `待测` 项,**值留空**并写明「由序 ⑥ 用 3–5 台真机换掉」。
|
|||
|
|
3. **45% 口径填「单台中继的 `--max-hosts`」,⛔ 不填"全网 45%"**。理由:`--max-hosts` 是**每实例**参数,填一个与实例无关的全网数字**不可执行**;"1000 台的 45%"只作**校验上界**使用。
|
|||
|
|
4. **观测最小集 = 「一条命令出 PASS/FAIL」**。指标 ≤12 条,每条一个阈值 + 一个退出码;⛔ 阈值**不许是脚本里的魔数**,必须能在参数表里找到。
|
|||
|
|
5. **判别器计数必须补**(`dial` / `dialDenied` / `dialFailed`)—— 这是本单**唯一**的代码改动。依据:443 单 §12 的教训原文「**静默失效靠判别器定位**」,而今天判别器**只有日志行**(`DIAL manager -> w-106:21000 ok`),脚本无法断言 ⇒ 观测最小集缺了最关键的一条。
|
|||
|
|
6. **L3 跨机真容灾:只出权限评估,⛔ 不实施;落地归序 ⑥**。理由:做出 L3 需要"换机或第二公网 IP",而现在全网只有 **2 个节点**,单点风险已由序 ④ 的 443 兜底 + CF 双路部分对冲;而**序 ⑥ 本来就要起 3–5 台真机**,第二中继机在那个批次里落地最省事(同一批采购/配置/验收)⇒ **没有理由现在单独为它花一台机器或一个公网 IP**。
|
|||
|
|
7. **权限评估的判据形态固定**为 6 列:`对象 / 是否扩大权限面 / 扩大到哪一类(入站面·权限位·凭据外发·可见面)/ 是否已可收窄 / 证据(代码行或命令原文)/ 结论(收窄·维持)`。⛔ **结论列只允许「收窄」或「维持」**;若某项确需扩大 ⇒ **停下报告**(命中 R5),⛔ 不得自行执行。
|
|||
|
|
|
|||
|
|
### 4.2 交给执行棒自决(⛔ **不上升为提问**)
|
|||
|
|
|
|||
|
|
参数表的表结构细节与行序 · 探针脚本的文件名/输出格式/退出码约定 · 计数器命名与埋点行位置 · `--max-hosts` 的推导公式与最终取值(只要满足 §6 的 **E3** 约束)· `capacity.conf` 的备份命名 · 单测用例划分 · 参数散落点的 grep 词表 · 探测样本大小。
|
|||
|
|
|
|||
|
|
### 4.3 真需要用户拍板的(**命中才问,且一轮只问这一句**)
|
|||
|
|
|
|||
|
|
**本轮为空。**
|
|||
|
|
|
|||
|
|
- L3 跨机真容灾已按 §4.1-6 **自决后置到序 ⑥**(现在做要新增机器/公网 IP = 资源承诺;而序 ⑥ 本来就要多台 ⇒ 合批明显更优,**上抛门槛不成立**)。
|
|||
|
|
- 其余全部落在 §1 的**边界内自决清单**(参数推导 / 观测实现 / 权限评估为**产出**而非动作)。
|
|||
|
|
- ⇒ 若将来要**提前**做 L3(例如你打算换掉 47),那时唯一缺口 = **第二台机器或第二个公网 IP**,属资源承诺,届时才需要你出手。
|
|||
|
|
|
|||
|
|
### 4.4 技术实现裁决顺序
|
|||
|
|
|
|||
|
|
按 `dsh-decision-method §4.4`;规则冲突按下序取首个命中项:`R8(开发环境服务器 ⇒ 该动就动,动手前一句话说明)` → `§1 边界内自决清单(部署/重启/改配置/技术选型)` → `§3 其余红线(R5/R7/R9/R10 永远是硬约束)`。⛔ 冲突 ≠ 门禁。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## §5 步骤(S0–S7,每步自带一次可执行的验证)
|
|||
|
|
|
|||
|
|
### S0 · 只读取证(⛔ 不改任何东西)
|
|||
|
|
|
|||
|
|
跑完 §2 的 P1–P10,产出"现状快照"(命令 + 原文输出 + 判定)。**任何一条与期望不符 ⇒ 停下报告**。
|
|||
|
|
额外取三件(本单设计的必要输入):
|
|||
|
|
- **47 规格实测 + 跨云带宽实测**(P6/P7)⇒ S4 的 `--max-hosts` 推导输入;
|
|||
|
|
- **`/status` 全字段原文**(P2)⇒ 既是"观测现状基线",也是 E8 的对照基准;
|
|||
|
|
- **6 份文档的参数散落点计数**(P10)⇒ S1 的收口清单(⛔ 只计数,不重读全文)。
|
|||
|
|
|
|||
|
|
### S1 · 参数表落盘(工作区根 `参数表_覆盖网络_20260917.md`)
|
|||
|
|
|
|||
|
|
收三类行:
|
|||
|
|
- **输入参数**(清单 §三点名的 5 类):设备占比 / 打洞率 / 每玩家带宽 / 消息频率 / 心跳;
|
|||
|
|
- **代码已固化的常量**:目录刷新 `300 s` / 取目录超时 `5 s` / `MAX_ENTRIES=8` / `MAX_ENTRY_LEN=512` / `capacityRetryAfterMs=5000` / 实例端口区间(`w-47` 20000+、`w-106` 21000+)/ dialer 回环池 64 口(`127.0.0.1:25000..26099`);
|
|||
|
|
- **本单新增**:`--max-hosts`(含**推导式 + 分母口径**)、观测阈值(每条指标一个)。
|
|||
|
|
|
|||
|
|
**硬要求**:每行必须有**来源等级 + 来源定位**;`待测` 行必须在表末**单独汇总计数**。
|
|||
|
|
|
|||
|
|
**验证**:抽样 3 行按"来源定位"回原文复核 ⇒ 逐字对得上;`--max-hosts` 行按表内公式**手算一遍**能得同值。
|
|||
|
|
|
|||
|
|
### S2 · 观测最小集落成探针(本机代码 `scripts/overlay-probe.cjs`)
|
|||
|
|
|
|||
|
|
最小指标集(≤12 条,全部来自既有 `/status` + 本机/远端只读命令):
|
|||
|
|
在册节点数 · `capacity{max,used,free}` · `identityRequired` / `identityOk` · `trustedSigners` · `revokedHosts` · `counters.authed` / `authFailed` · **`counters.dial` / `dialDenied` / `dialFailed`(S3 新增)** · 端点表 `endpoints[]` · 双实例探活(`w-47:19100` / `w-106:19000`)· 门户 `200` · 监听口数 · `nft` 行数。
|
|||
|
|
**每条一个阈值 → PASS/FAIL;退出码 = 全绿 0 / 任一红 1**(可被 automation 直接消费)。⛔ 阈值从参数表读,⛔ 不硬编码。
|
|||
|
|
|
|||
|
|
**验证**:47 上跑一次 ⇒ 全绿、打印 ≤12 行、`exit 0`;**反证**:把某阈值临时调紧 ⇒ 变红、`exit 1`(证明确实在读阈值而不是恒绿)。
|
|||
|
|
|
|||
|
|
### S3 · 判别器计数(本机代码 `src/net/relay/server.ts` —— 本单**唯一**代码改动)
|
|||
|
|
|
|||
|
|
`counters` 增 `dial` / `dialDenied` / `dialFailed`;埋点 = `DIAL` 帧处理路径的三个分支(放行 / 白名单或同网校验拒绝 / 目标端点不可达)。加**先红后绿**单测。
|
|||
|
|
⚠️ `npm test` 必须 **Node 22**;⛔ 不改帧格式、不改校验顺序。
|
|||
|
|
|
|||
|
|
**验证**:本机单测通过;47 上重启 `dshs-relay` 后制造一次成功拨号 ⇒ `counters.dial` +1 且 `/status` 可见。
|
|||
|
|
|
|||
|
|
### S4 · 45% 口径填值 + 设值(47)
|
|||
|
|
|
|||
|
|
按 S1 的推导式(输入 = P6 实测规格 + P7 实测量 + 参数表内的单节点成本)算出 `--max-hosts`,写进**新建 drop-in** `dshs-relay.service.d/capacity.conf`(⛔ 不改 `dialers.conf`、⛔ 不改主单元)。设值前后各取一次 `/status`。
|
|||
|
|
|
|||
|
|
**硬约束(防自锁)**:新值必须 **`> used × 4`** 且 **≥ 参数表下限**;不满足 ⇒ **不设值**,改为在 §8 写明"参数表已填数值但因 X 不设值"。
|
|||
|
|
|
|||
|
|
**验证**:`curl -s 127.0.0.1:20080/status` ⇒ `capacity.max` = 设定值、`free = max - used`;`online[]` 未变;`identityOk` 未退化。
|
|||
|
|
|
|||
|
|
### S5 · 权限影响评估(**只有产出,无动作**)
|
|||
|
|
|
|||
|
|
按 §4.1-7 的 6 列逐项评估:
|
|||
|
|
① 虚拟网卡驱动(打洞所需)② 骨干节点开端口 ③ `nft` 打洞规则 ④ **第二中继机(L3 跨机真容灾)** ⑤ 443 兜底入口(**复核**是否真的零扩大)⑥ relay 拨号白名单 `dialers`(R5 引入)⑦ 每机独立密钥与信任根保管。
|
|||
|
|
每条给**证据列**(代码行 / 命令原文)。⛔ 不许出现"我认为"。
|
|||
|
|
|
|||
|
|
**验证**:评估表每条有证据;**结论列只出现「收窄」或「维持」**;L3 行**明确写「只评估不实施 + 归序 ⑥」**。
|
|||
|
|
|
|||
|
|
### S6 · 端到端复验 + 不退化检查
|
|||
|
|
|
|||
|
|
① `/status` 全字段对照 S0;② `online[]` 两台在、双实例面 `200`;③ 门户 `curl -H "Host: alotbuy.com" 127.0.0.1:3080/` = `200`;④ 监听口数 / `nft` 行数 与 S0 逐字一致;⑤ `npm test` 全绿;⑥ 探针全绿。
|
|||
|
|
|
|||
|
|
> 🔴 **计数器读数纪律(443 单 §8.6 的教训,必须照做)**:`authed` / `authFailed` / `identityOk` / `dial*` 都是**累计值** ⇒ "逐字一致"**物理上不成立**。必须**逐条归因增量**:每个增量都要能指名到"我做的哪一次动作"。⚠️ **101 探针本身会污染 `authFailed`** —— 读数前先扣掉自己打的探针次数。
|
|||
|
|
|
|||
|
|
### S7 · 回写
|
|||
|
|
|
|||
|
|
① `参数表_覆盖网络_20260917.md` 落盘,并在**入口 §1 的文档表登记一行**;②本单 §8 回填(含指纹);③把入口 §2「🎯 本轮动作」**推进到下一棒(序 ⑥ · 3–5 台最小形态)**;④⛔ 不 commit / 不 push。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## §6 验收(判据清单)
|
|||
|
|
|
|||
|
|
| # | 判据 | 命令 | 期望 |
|
|||
|
|
|---|---|---|---|
|
|||
|
|
| **E1** | 参数表落盘且**每行有来源等级 + 来源定位** | `grep -c "^|" 参数表_覆盖网络_20260917.md`;抽样 3 行按定位回原文复核 | 行数与 `待测` 汇总计数自洽;抽样 3 行**逐字对得上** |
|
|||
|
|
| **E2** | **可复算**(这是"结构可信 → 数字可信"的判据) | 任取 2 行按表内公式**独立手算** | 手算值 = 表内值 |
|
|||
|
|
| **E3** | 45% 口径已填数值且**生效** | `ssh -p 22 47 'curl -s 127.0.0.1:20080/status' \| python -c "import sys,json;c=json.load(sys.stdin)['capacity'];print(c)"` | `max > 0`、`max` = 参数表值、`free = max - used`、`max > used×4` |
|
|||
|
|
| **E4** | 观测探针可用 + **非恒绿** | `node scripts/overlay-probe.cjs; echo $?` ⇒ 再调紧一阈值复跑 | 首次 `exit 0` 全绿;调紧后 `exit 1` 且**指名**哪条红 |
|
|||
|
|
| **E5** | 判别器计数存在且可增 | `/status` 取 `counters.dial`;制造一次成功拨号 + 一次白名单拒绝 | 两个数分别 +1,`/status` 可见 |
|
|||
|
|
| **E6** | 观测阈值**无脚本魔数** | `grep -nE "[0-9]{3,}" scripts/overlay-probe.cjs` | 每个命中项都能在参数表里找到同名阈值(⛔ 无孤值) |
|
|||
|
|
| **E7** | 权限评估表完整 | 通读 §5-S5 产出 | 每条有证据列;结论 ∈ {收窄, 维持};L3 行写"只评估不实施 + 归序 ⑥" |
|
|||
|
|
| **E8** | 零退化 | S0 快照 vs 收口:`/status` 全字段 + 双实例面 + 门户 + `npm test` | 除**已归因增量**外逐字一致;`npm test` 全绿(写清 a/b/c 计数) |
|
|||
|
|
| **E9** | 零新增暴露面 | `ssh -p 22 47 'ss -lntp \| wc -l'`;`ssh -p 22 47 'nft list ruleset \| wc -l'`;`ss -lntp \| grep -c 20080` | 与 S0 逐字一致(443 单收口态 = **79 / 72**);relay 仍**只绑 `127.0.0.1`** |
|
|||
|
|
|
|||
|
|
> **判定**:E1–E9 全绿 = 本单完工。任一红 ⇒ 按 §7 该项回滚,并在 §8 写清"卡在哪 + 已做到哪一步 + 什么条件一出现必须回头解决"。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## §7 回滚
|
|||
|
|
|
|||
|
|
| 项 | 回滚 |
|
|||
|
|
|---|---|
|
|||
|
|
| S4 `capacity.conf` | 删该 drop-in → `daemon-reload` → `systemctl restart dshs-relay`(回到 `max=0` = 不限;⚠️ 重启会重建 relay 会话,`online[]` 需复验) |
|
|||
|
|
| S3 计数器代码 | 47 侧 = 恢复铺前备份 `/opt/dshs/lib/net/relay/server.js.bak-<时间戳>-pre-p5obs`(**铺前必须先备份**);本机 = 靠**备份副本**(⛔ **禁止 `git checkout --`**:`src/net/relay/` 不在 git 里,且会连带丢掉工作区其它未提交改动 —— 443 单 §8.1 注) |
|
|||
|
|
| S2 探针 | 独立新增文件,删掉即可;⛔ **不改 `state.py`**(避免影响别人的"第一信号") |
|
|||
|
|
| S1 参数表 | 新增文档,回退即可;若已登记进入口 §1 表,记得同步撤行 |
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## §8 回报格式(执行棒按此格式收口)
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
## §8 执行回报(执行棒 · 2026-09-17 HH:MM)
|
|||
|
|
1. S0 快照:P1–P10 逐条 = 命令原文 + 输出 + 判定(不符的先说);含 47 规格与跨云带宽**实测值**
|
|||
|
|
2. 参数表:行数 / 待测行数 / `--max-hosts` 推导式 + 取值 + 分母口径(原文摘录)
|
|||
|
|
3. 落盘清单:新建/改动的**每个文件绝对路径** + 备份文件名 + 改前改后指纹(md5 / hash-object)
|
|||
|
|
4. E1–E9:逐条命令原文 + 原文输出 + 绿/红
|
|||
|
|
5. 观测:探针输出原文(≤12 行)+ 退出码 + **调紧反证**(哪条变红)
|
|||
|
|
6. 权限评估:6 列表逐条(结论只能是 收窄/维持)+ L3 行的"只评估不实施"原文
|
|||
|
|
7. 不退化:S0 对照 / 双实例面 / 门户 / `npm test` 计数(a/b/c)+ **计数器增量的逐条归因**
|
|||
|
|
8. 未过项 / 遗留:逐条写"卡在哪(证据)+ 已做到哪一步 + 什么条件一出现必须回头解决"
|
|||
|
|
9. 指纹:本单回填后 `md5sum`(⚠️ 别把全文件 md5 写进正文 —— 自指即失效,用 `sed '/^## §9 指纹/,$d' | md5sum` 口径)
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 附 A · 本规划棒已核实的事实(执行棒**不必重复探索**)
|
|||
|
|
|
|||
|
|
| 事实 | 依据 |
|
|||
|
|
|---|---|
|
|||
|
|
| 序 ⑤ 的原文口径 = 「参数表 + 观测最小集 + 权限评估(P1 三条)」,状态 **可并行** | `覆盖网络_应用场景与待完善清单_20260916.md` **§五 第 5 行** |
|
|||
|
|
| 三条缺口的原文:「**参数表是空的**(libp2p 默认值可直接固化)· **观测最小指标集与阈值缺失** · **权限面评估缺失 = 命中 R5**(虚拟网卡驱动需管理员权限 / 骨干开端口 / nft 打洞)」 | 同上 **§四 P1 行**(第 85 行) |
|
|||
|
|
| "不可复算"的根因 = 参数**散在 6 份文档、无统一表** | 同上 **§三 第 1 条**(第 65 行) |
|
|||
|
|
| 序 ⑥ 的口径 = 「**3–5 台最小形态跑通**(把 3 个关键估值换成实测)」,依 `2/3/4` | 同上 §五 第 6 行 ⇒ **L3 归它是合批,不是推迟** |
|
|||
|
|
| relay 容量/准入机制**已存在**:`--max-hosts`(`DSHS_RELAY_MAX_HOSTS`,默认 `0` = 不限)+ `/status.capacity{max,used,free}` + 满载 `at-capacity` + `retryAfterMs`(默认 **5000 ms**) | `src/net/relay/main.ts:64/82`、`src/net/relay/server.ts:62/102/104/367/368/502-504/757-759` |
|
|||
|
|
| 客户端侧排队语义**已实现**(不消耗退避、不累计 attempts) | `src/net/relay/client.ts:532/881-896` |
|
|||
|
|
| `/status` 的 **counters 只有 `authed` / `authFailed`** ⇒ **`DIAL` 无计数**(判别器只能读日志) | `src/net/relay/server.ts:276-278 / 347-348 / 510-512`(本次实测 grep) |
|
|||
|
|
| `DIAL` 的隔离语义 = **同网 + 本网白名单**,跨网"能不能拨"都走不到(结构性隔离) | `src/net/relay/server.ts:22 / 108 / 261-265` |
|
|||
|
|
| 45% 口径的待填位置(由 443 单显式后置给序 ⑤) | `交接单_443兜底_20260917.md` **§4.1-6 / §8.8** |
|
|||
|
|
| 443 单带回的四条遗留(本单与它们的对应关系见下) | 同上 **§8.7** |
|
|||
|
|
| 判别器教训原文:「**静默失效靠判别器定位**」(relay 有没有 `DIAL`) | 入口 §0 + `交接单_relay落地R2-R4_20260916.md` §12 |
|
|||
|
|
|
|||
|
|
**§8.7 四条遗留 → 本单的对应关系**(⛔ 不许漏):
|
|||
|
|
|
|||
|
|
| 遗留 | 本单处理 |
|
|||
|
|
|---|---|
|
|||
|
|
| ① D2 字面判据不可满足(CF 泛解析) | **不在本单范围**(未做灰云记录)⇒ 若要"解析层也不经 CF"才回头,登记为**序 ⑥ 后**候选项 |
|
|||
|
|
| ② 106 的 agent 面不吃引导链 | **本单只记录、⛔ 不动手**(P8);若要 106 agent 面也能用兜底 ⇒ 需改 `worker/agent.ts`/`relay-tunnel.ts`,**归序 ⑥** |
|
|||
|
|
| ③ 「同源优先」修法(已补) | 已闭环;⚠️ 其**遗留条件** = "若将来 `relays[]` 引入非首位更优的显式优先级语义(**序 ⑤ 参数表可能引入**)⇒ 需重新定义同源优先与它的先后关系" ⇒ **本单必须回答这一条**(在参数表里写明:`relays[]` 顺序语义 = **主入口首位**,本单**不引入**优先级新语义) |
|
|||
|
|
| ④ 引导链缓存两支无"答出者"信息(切兜底有 ≤300 s 收敛期) | **本单把 `refreshAfterSeconds=300` 收进参数表并写明该收敛期**(作为已知边界,⛔ 不改缓存结构) |
|
|||
|
|
|
|||
|
|
## 附 B · 硬约束复述(防走偏)
|
|||
|
|
|
|||
|
|
- ⛔ **本轮只出单**:不改服务器、不改代码、不 commit、不 push、不做 presence。
|
|||
|
|
- ✅ **只做正向迭代(R11)**:本单任何一步若让任一维度**净变差** ⇒ 立即停下复盘;拿不出正向做法 ⇒ 停止执行。
|
|||
|
|
- ✅ **权限只准收窄(R5)**:本单**零新增公网端口、零新增入站面、零凭据外发**;权限评估是**产出**不是动作;若某项确需扩大 ⇒ **先停下报告**,⛔ 不得自行执行。
|
|||
|
|
- ⛔ **R7**:只做 §3.1 列出的改动;执行中发现别的"小问题"**先报告、后动手**。
|
|||
|
|
- ⚠️ **curl 判据必须 `--http1.1`**(门户 `http2 on`,否则假 404)。
|
|||
|
|
- ⚠️ **47 的 lib = `/opt/dshs/lib/`、106 = `/opt/dshs-cluster/lib/`**;**部署 = 本机 build 后 scp**;`npm test` 必须 **Node 22**。
|
|||
|
|
- 🔴 **`--max-hosts` 设值必须满足 `max > used × 4`**(防把自己锁在门外);不满足 ⇒ **不设值**并写清原因。
|
|||
|
|
- 📌 **参数表里 `待测` 项一个都不许编数** —— 编出来的数会让整张表失去"可复算"的资格。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## §8 执行回报(执行棒 · 2026-09-17 09:55)
|
|||
|
|
|
|||
|
|
**判定:E1–E9 = **8 绿 + 1 部分绿**(E5 的"在 47 上受控制造一次真实拨号"未做到 —— 卡点、已做到哪一步、回头条件见 8.7-①)。三条硬约束全部守住(见 8.7-④)。**
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 8.1 S0 快照(P1–P10:命令原文 + 输出 + 判定)
|
|||
|
|
|
|||
|
|
| # | 命令(原文) | 输出(原文摘要) | 判定 |
|
|||
|
|
|---|---|---|---|
|
|||
|
|
| P1 | `ssh -p 22 bt-server 'systemctl is-active dshs dshs-relay dshs-pg'` + `ss -lntp \| grep -E ":(443\|20080)\b"; pgrep -c nginx` | `active`×3;`LISTEN 127.0.0.1:20080`(node)/ `LISTEN 0.0.0.0:443`(nginx);`nginx_pid=4` | ✅ |
|
|||
|
|
| P2 | `ssh -p 22 bt-server 'curl -s 127.0.0.1:20080/status'` | 全字段见 8.2 表;⚠️ **两处与期望不符**(见 8.2) | ⚠️ 已纠偏 |
|
|||
|
|
| P3 | `systemctl cat dshs-relay \| grep -nE "max-hosts\|ExecStart"` | `ExecStart=… --base 19000 --span 3000 --max-hosts 0` ⇒ ⚠️ **`--max-hosts` 并非"未出现"**,是**显式写在 ExecStart 里** | ⚠️ 改变 S4 做法 |
|
|||
|
|
| P4 | `grep -n "MAX_ENTRIES\|…" src/net/relay/{directory,server}.ts` | `directory.ts:60` 300 / `:63` 8 / `:64` 512 / `:521` 5000;`server.ts:52/54/56/58/60/63/69/71/73/76` | ✅ 与期望一致 |
|
|||
|
|
| P5 | `ss -lntp \| wc -l`;`nft list ruleset \| wc -l` | **79** / **72** | ✅ 与 443 单收口态**逐字一致** |
|
|||
|
|
| P6 | `nproc; free -m \| head -2; df -h / \| tail -1; hostname` | **2 核**;mem total **1870** / used 868 / **available 1002** MB;`/dev/vda3 40G 15G 23G 39%`;`iZrj99af19cibck1ge93tqZ` | ✅ 实测(⛔ 未沿用 09-08 旧记录) |
|
|||
|
|
| P7 | ①`/status` 读 `rttMs`;②`curl -w` 打 relay 回环口(6 样本);③`head -c 1048576 /dev/zero \| curl -X POST --data-binary @- http://127.0.0.1:44133/` | ① w-106 **rttMs=336** / manager **7**;② **TTFB 0.676–1.083 s**;③ `code=405 up=131072 total=0.6849` ⇒ **上行下界 ≈ 192 KB/s** | ⚠️ **部分**(稳态吞吐取不到,见 8.7-②) |
|
|||
|
|
| P8 | `ssh -p 22 test106 'grep -rn "DSHS_RENDEZVOUS_URL\|…" /etc/systemd/system/*.d/ /etc/dshs-cluster.env'` | ⚠️ **指定路径零命中**;全局搜得真身在 **`/etc/dshs-worker.env`**:`DSHS_RENDEZVOUS_URL=wss://alotbuy.com/dshs-relay` | ⚠️ 位置纠偏(结论不变) |
|
|||
|
|
| P9 | `git rev-parse HEAD`;`git status --porcelain -- src/net/relay/` | `640813e84e5e48c56ca39d765d7b195884e58ebc`;`?? src/net/relay/` | ✅;⛔ 全程**未** `git checkout --` |
|
|||
|
|
| P10 | 7 份文档逐份 `grep -c "打洞率\|jitter\|KB/s\|扇出\|心跳"` | 调研 19 / 千台 18 / 瓶颈 9 / 游戏 7 / 清单 7 / 百台 2 / 骨干 2 = **64 处** | ✅ 只计数、未重读全文 |
|
|||
|
|
|
|||
|
|
**P8 附注(只记录、⛔ 未动手)**:`/etc/dshs-worker.env` 的四个副本里,`.bak-20260916-1617` 仍是 `ssh://[email protected]:32022`,现行与另两个 `.bak-r4` / `.bak-r6` 已是 `wss://alotbuy.com/dshs-relay` ⇒ 「106 的 agent 面不吃引导链」这条**前提成立**,⛔ 未撤。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 8.2 P2 的两处**事实纠偏**(都不是阻塞,但都会误导下一棒)
|
|||
|
|
|
|||
|
|
| # | 期望(交接单 §2) | 实测 | 影响 |
|
|||
|
|
|---|---|---|---|
|
|||
|
|
| ① | `counters` 只有 `authed/authFailed` | 实测**还有一个**:`refused / dropped / streamsOpened / protocolErrors / backpressurePauses` + 序③ 的 `identityOk / identityRequired / trustedSigners / revokedHosts`(共 11 项 + 本次新增 3 项) | ⛔ 附A 那句"只有 authed/authFailed"作废;**`DIAL` 仍无计数**这条结论**依然成立**(新增前确实没有 `dial*`) |
|
|||
|
|
| ② | `capacity{max,used,free?}` | `max=0` 时**只有 `{max,used}`**,`free` **字段不存在**(不是 `null`、不是 `0`);`free` 仅当 `max>0` 才出现(`server.ts:502-506`);拒绝载荷里恒为 `0`(`:761`) | ⇒ **E3 的 `free = max - used` 只在设值后才能判**(已写进参数表 §5.5) |
|
|||
|
|
|
|||
|
|
**P3 的连带纠正(S4 做法因此改变)**:`main.ts:64` 用 `DSHS_RELAY_MAX_HOSTS` 作**默认**、`:82` 由 CLI `--max-hosts` **覆盖** ⇒ 主单元里那句显式的 `--max-hosts 0` 会把 drop-in 的 `Environment=` **静默吃掉**。故 `capacity.conf` **重写 `ExecStart`**(`ExecStart=` 清空 + 完整命令)—— 仍是"新建 drop-in、⛔ 不改主单元、⛔ 不硬编码进代码",且**避免了本项目最忌讳的静默失效**。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 8.3 落盘清单(绝对路径 + 备份 + 改前/改后指纹)
|
|||
|
|
|
|||
|
|
| # | 位置 | 动作 | 备份 | 改前 → 改后 |
|
|||
|
|
|---|---|---|---|---|
|
|||
|
|
| 1 | `E:\ProgramData\AI技能\aliyun-dsh-server\参数表_覆盖网络_20260917.md` | **新建** | — | — → 155 行(`md5sum` 见 8.9) |
|
|||
|
|
| 2 | `D:\github\dsh_shenxian\scripts\overlay-probe.cjs` | **新建** | — | — → `0cd76d986273e04631510aa7d215d16c`(`git hash-object` `98b91d8280147f025792301f56b95582e9b901e5`) |
|
|||
|
|
| 3 | `D:\github\dsh_shenxian\test\relay.test.mjs` | **改**(新增 T20) | — | `git hash-object` 改前未存 → `846460b5b6d6a3957abe29c63fce67e0a2e77f9d` |
|
|||
|
|
| 4 | `D:\github\dsh_shenxian\src\net\relay\server.ts` | **改**(只加计数) | — | `7f95fe5f6b1865102d12a0917c4b4f9b7ecf2035` → `dc062c83ac0167f40d0e5d2c09f568b4`(`git hash-object`) |
|
|||
|
|
| 5 | `D:\github\dsh_shenxian\lib\net\relay\server.js`(build 产物) | **改** | — | `64d814e7d68163752247d4a190b3b538` → `623374d948e37c87db3401f00ebf4dbe` |
|
|||
|
|
| 6 | 47 `/opt/dsh-relay/lib/net/relay/server.js`(**relay 真身**) | **改** | `server.js.bak-20260917-pre-p5obs`(`64d814e7…`) | 同 5 |
|
|||
|
|
| 7 | 47 `/opt/dshs/lib/net/relay/server.js` | **改**(保双副本对账) | 同上 | 同 5 |
|
|||
|
|
| 8 | 106 `/opt/dshs-cluster/lib/net/relay/server.js` | **改**(保 29/29 对账口径) | `server.js.bak-20260917-pre-p5obs`(`64d814e7…`) | 同 5 |
|
|||
|
|
| 9 | 47 `/etc/systemd/system/dshs-relay.service.d/capacity.conf` | **新建** | — | — → `a48df38f859adc3e8589d85bfd8a9ff1` |
|
|||
|
|
|
|||
|
|
> ⚠️ **§7 回滚表的一处纠偏**:relay 运行的代码在 **`/opt/dsh-relay/lib/`**(主单元 ExecStart 指它),⛔ **不是** `/opt/dshs/lib/`。据此本次**两处都备份、都铺**(`/opt/dshs/lib` 只为双副本对账与 Manager 侧一致)。106 的副本 worker 永远不加载(worker 不跑 `RelayServer`),铺它是为了不破坏"29/29 hash 全同"这条既有对账口径。
|
|||
|
|
> **临时产物**(⛔ 未删,留给复核):`_中间产物_待清理/seq5/capacity.conf`(下发源)、`_中间产物_待清理/参数表_覆盖网络_调紧反证.md`(E4 反证用)。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 8.4 E1–E9 逐条(命令原文 + 原文输出 + 绿/红)
|
|||
|
|
|
|||
|
|
| # | 命令(原文) | 输出(原文) | 结果 |
|
|||
|
|
|---|---|---|---|
|
|||
|
|
| **E1** | `grep -c "^\|" 参数表_覆盖网络_20260917.md`;`grep -cE "^\|.*\| \*\*待测\*\* \|" 参数表_覆盖网络_20260917.md` | `155`;`4` | ✅(155 行;`待测` **数据行 4** = §7 汇总的 4,自洽。⚠️ 全文 `**待测**` 字面命中 6 次 = 4 数据行 + §0 图例行 + §7 说明行,⛔ 不是 6 项待测) |
|
|||
|
|
| **E2** | 按表内公式**独立手算**(`RELAY_MAX_HOSTS` + `HALF_OPEN_MS`) | `floor(1002/2)=501`;`floor(262144/4)=65536`;`min=501`;`floor(501×0.45)=floor(225.45)=225` ✅;`max(3000, 15×1000×2.5)=37500` ✅ | ✅ 手算值 = 表内值 |
|
|||
|
|
| **E3** | `ssh -p 22 bt-server 'curl -s 127.0.0.1:20080/status'` | `"capacity": {"max": 225,"used": 2,"free": 223}` | ✅ `max=225` > `used×4=8`;`free = max-used` |
|
|||
|
|
| **E4** | `node scripts/overlay-probe.cjs; echo $?` ⇒ 再 `--table <调紧副本>` | 首次 **12 行全 PASS / `exit=0`**;调紧后 `FAIL OBS-02 capacity max=225 … (阈值 max=9999…)` + stderr `❌ 1 项红:OBS-02` / `exit=1` | ✅ 非恒绿,且**指名**红项 |
|
|||
|
|
| **E5** | `/status` 取 `counters.dial`;`test/relay.test.mjs` T20 三分支 | 47 实测三个字段**已存在**:`"dial": 0, "dialDenied": 0, "dialFailed": 0`;T20 **先红后绿**(加计数前 `counters.dial` = `undefined` ⇒ `AssertionError`;加完 20/20 通过) | ⚠️ **部分绿**(47 上未能受控制造真实拨号,见 8.7-①) |
|
|||
|
|
| **E6** | `grep -nE "[0-9]{3,}" scripts/overlay-probe.cjs` | **零命中**(命中数 `0`) | ✅ 比判据更严:脚本里**连标识符名与注释里都没有**像阈值的数字 |
|
|||
|
|
| **E7** | 通读 §5-S5 产出(本单 → 参数表 §8) | 7 条(① 虚拟网卡驱动 ② 骨干开端口 ③ nft 打洞 ④ 第二中继机 ⑤ 443 兜底入口 ⑥ 拨号白名单 ⑦ 每机密钥与信任根);**结论列只出现「维持」**(全部 7 条都是"不扩大",其中 5 条还标了"已收窄"证据);④ 明写「只评估不实施 + 归序⑥」 | ✅ |
|
|||
|
|
| **E8** | S0 对照 + 双实例面 + 门户 + `npm test` | `listen=79 / nft=72` **逐字一致**;`online[]` = `manager` + `w-106` 两台在;实例面 `20000→401`、`w-106:40147→401`;门户 `200`;`npm test` = **tests 138 / pass 137 / fail 0 / cancelled 0 / skipped 1 / todo 0** | ✅(`skipped 1` 为既有条件跳过,非本次引入;计数器增量逐条归因见 8.6) |
|
|||
|
|
| **E9** | `ss -lntp \| wc -l`;`nft list ruleset \| wc -l`;`ss -lntp \| grep 20080` | `79` / `72`;`LISTEN 0 511 127.0.0.1:20080` **只有回环一条** | ✅ 零新增暴露面 |
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 8.5 观测(探针输出原文 + 退出码 + 调紧反证)
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
PASS OBS-01 在册节点 used=2 (阈值 ≥ 2)
|
|||
|
|
PASS OBS-02 capacity max=225 used=2 free=223 (阈值 max=225, free=max-used)
|
|||
|
|
PASS OBS-03 identityRequired=true trustedSigners=1 (阈值 ≥ 1)
|
|||
|
|
PASS OBS-04 identityOk=2 (阈值 ≥ 2)
|
|||
|
|
PASS OBS-05 revokedHosts=0 (阈值 ≤ 0)
|
|||
|
|
PASS OBS-06 判别器 dial=0 dialDenied=0 dialFailed=0 (必须都是 number)
|
|||
|
|
PASS OBS-07 authFailed=0 authed=2 (阈值 ≤ 50)
|
|||
|
|
PASS OBS-08 端点表 2 条 / 离线 0 条
|
|||
|
|
PASS OBS-09 实例面 本机:20000=401 w-106:40147=401 (阈值 ∈ {200,401})
|
|||
|
|
PASS OBS-10 门户=200 (阈值 = 200)
|
|||
|
|
PASS OBS-11 监听口=79(阈值 79) nft=72(阈值 72) relay 口绑定回环=1/1 条
|
|||
|
|
PASS OBS-12 relay RSS=72040KB (阈值 ≤ 800000KB)
|
|||
|
|
exit=0
|
|||
|
|
```
|
|||
|
|
**调紧反证**:把 `RELAY_MAX_HOSTS` 改成 `9999`(副本表,⛔ 未改正式表)⇒ `FAIL OBS-02`,stderr `❌ 1 项红:OBS-02`,`exit=1`。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 8.6 不退化(S0 对照 / 双实例面 / 门户 / `npm test` + **计数器增量逐条归因**)
|
|||
|
|
|
|||
|
|
| 项 | S0(09:20) | 收口(09:5x) | 归因 |
|
|||
|
|
|---|---|---|---|
|
|||
|
|
| `capacity` | `{max:0, used:2}` | `{max:225, used:2, free:223}` | **我**:S4 设值(可归因、预期内) |
|
|||
|
|
| `counters.authed` / `authFailed` | `2 / 3` | `2 / 0` | **我**:`restart dshs-relay` **清零累计值**;重启后 manager + w-106 各认证一次 ⇒ `authed=2`;`authFailed=0`(⛔ 本次**没有**打过任何错误密钥;旧值 3 是历史累计) |
|
|||
|
|
| `counters.dial/dialDenied/dialFailed` | 字段不存在 | `0 / 0 / 0` | **我**:S3 新增字段 + 部署。⚠️ 全 0 是**真实读数**(生产此刻确实没有拨号流量,见 8.7-①) |
|
|||
|
|
| `identityOk` / `identityRequired` / `trustedSigners` / `revokedHosts` | `2 / true / 1 / 0` | `2 / true / 1 / 0` | **零变化** ⇒ 序③ 成果未退化 |
|
|||
|
|
| `online[]` | manager + w-106 | manager + w-106(sessionId 已换) | **我**:重启重建会话(R5/T8 的既定行为,无需人工介入) |
|
|||
|
|
| `endpoints[].localPort` | 44911 / 44133 | 42563 / 40147 | **我**:重启后重分配(回环落点口号**本来就是会话期量**,⛔ 不是退化) |
|
|||
|
|
| 监听口数 / nft 行数 | 79 / 72 | 79 / 72 | 逐字一致 |
|
|||
|
|
| 门户 / 双实例面 | 200 / 401 | 200 / 401 | 未退化 |
|
|||
|
|
| `npm test` | — | 138 / 137 pass / **0 fail** / 1 skipped | 未退化(T20 已计入) |
|
|||
|
|
|
|||
|
|
> ⚠️ 按 §5 S6 的**计数器读数纪律**:`authed` 的"逐字一致"**物理上不成立**(重启即清零)—— 上表已逐条点名到"哪一次动作"。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 8.7 未过项 / 遗留(逐条:卡在哪 + 已做到哪一步 + 什么条件一出现必须回头解决)
|
|||
|
|
|
|||
|
|
**① E5 的"47 上受控制造一次真实拨号"—— 未做到**
|
|||
|
|
- **卡在哪**:`DIAL` 只在**拨号方白名单**里的会话发出时才会被处理(`server.ts:747 / :975`),而白名单**只有 `manager` 一个**(`dialers.conf` = `DSHS_RELAY_MAX_HOSTS`… 原文 `ops:manager`)。要让 47 上产生真实 `DIAL`,唯一路径是**一条通过鉴权的业务请求**去访问 w-106 的实例面;而实测无 session 的 `curl -H "Host: …" 127.0.0.1:3080/` 在**鉴权层**就被挡(`w-106.alotbuy.com` ⇒ **404**,连实例路由都没进),35 s 观察 `dial` 恒 `0`、relay 日志 `DIAL` **0 条**(库里有 3 个 w-106 实例、1 个 w-47 实例 ⇒ 一旦有人真实访问必然触发)。
|
|||
|
|
- **已做到哪一步**:① 三个字段**已在 47 的 `/status` 可见**(`0/0/0`);② 三分支的**可得性**在 `test/relay.test.mjs` **T20** 上先红后绿全证(放行 `dial+1` / 白名单拒绝 `dialDenied+1` / 目标不可达与请求非法 `dialFailed+2`),而 T20 跑的就是**部署到 47 的同一份构建产物**(md5 `623374d948e37c87db3401f00ebf4dbe`,三处一致)。
|
|||
|
|
- **⛔ 为什么没硬做**:为一个计数器去 ① 往控制面库插临时 session(= 冒充真实用户去访问**正在运行的**用户实例,可能触发 launch / 文件面刷新)或 ② 把第二个 hostId 加进 `dialers` 白名单(= **扩大权限面**,命中 R5 必须停下报告)—— 两者都越出本单 §3.1 的范围,且风险**大于**这条判据本身的价值。
|
|||
|
|
- **什么条件一出现必须回头解决**:**下一次有真实用户访问 w-106 实例**时,回看 `/status.counters.dial` 应从 0 变正数;若**仍为 0**,说明拨号路径**根本没被走到**(正是 `RemoteSpawner.translateEndpoint` 那类静默失效的指纹),届时按判别器口径立即排查。
|
|||
|
|
|
|||
|
|
**② P7 的"跨云稳态带宽"—— 仍为 `待测`**
|
|||
|
|
- **卡在哪**:relay 的两个面(agent 19000 / 实例 21000)在**无凭据**时只回 24 B / 68 B 的 401/404;`/client.js`、`/assets/` 均 404 ⇒ **拿不到大响应就测不出稳态吞吐**。
|
|||
|
|
- **已做到哪一步**:拿到 **RTT 336 ms**、**TTFB 0.676–1.083 s**、**上行下界 ≥ 192 KB/s**(1 MB 样本被 405 截断到 131072 B / 0.685 s)⇒ **旧记录 `22 KB/s` 判为不可用**(差 ≈ 9×,⛔ 已写进参数表 §0 作废)。
|
|||
|
|
- **什么条件一出现必须回头解决**:两端有**可控载荷**(序⑥ 的真机批次天然满足)⇒ 换出稳态值并**重算 §5.2**。
|
|||
|
|
|
|||
|
|
**③ 三项"顺手发现、⛔ 未动手"(R7:先报告后动手)**
|
|||
|
|
- `~/.ssh/config` 的 `bt-server` 端口陈旧(`32022`)—— 本次全程 `-p 22`,**未改配置**。
|
|||
|
|
- **`src/net/relay/` 整目录未被 git 跟踪**(`?? src/net/relay/`)⇒ 覆盖网络线代码只在工作区+部署产物里;**未做任何 git 动作**(⛔ 未 commit / 未 push)。
|
|||
|
|
- 附A 那句「`/status` counters 只有 `authed/authFailed`」**已勘误**(见 8.2-①);`--max-hosts` "未出现"**已勘误**(见 8.2-P3)。两条都属"上一棒文档的既有结论",⛔ 本轮只记录、只纠正,未扩大改动。
|
|||
|
|
|
|||
|
|
**④ 三条硬约束守持证据**
|
|||
|
|
- ① `--max-hosts`:`225 > used×4 = 8` ✅(不满足才"不设值",本次满足)⇒ **已设值**,且写明**分母口径 = 每台中继**。
|
|||
|
|
- ② 参数表 `待测` 项:**4 项值列全部留空**(`grep -n` 逐行可见 `| |` 空值),⛔ 一个都没编数。
|
|||
|
|
- ③ ⛔ **全程未执行 `git checkout --`**(`grep -c` 校验:本次会话的命令记录里零次)。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 8.8 45% 口径(**已填值** + 生效证据)
|
|||
|
|
|
|||
|
|
- **数值**:`RELAY_MAX_HOSTS = 225`(`floor(min(floor(1002/2), floor(262144/4)) × 0.45) = floor(501 × 0.45) = 225`)。
|
|||
|
|
- **分母口径**:**每台中继的在册会话数上限**(⛔ 不是"全网 45%");`1000 × 45% = 450` 只作**校验**。
|
|||
|
|
- **生效证据**:`capacity {max:225, used:2, free:223}` ✅;`systemctl show -p ExecStart dshs-relay` 原文含 `--max-hosts 225` ✅。
|
|||
|
|
- **校验③ 的结论(新信息)**:`450 > 225` ⇒ **单台中继盖不住千台的 L3 层,需 ≥ 2 台中继** —— 与 `覆盖网络_骨干层方案_20260916.md`「多中心骨干」**同向**;落地归**序⑥**(交接单 §4.1-6 已判 L3 只评估不实施)。
|
|||
|
|
- **回头条件(写死)**:`MEM_PER_HOST_MB` 或 `WAN_STEADY_THROUGHPUT` 一旦换成实测 ⇒ **必须重算本值并重新下发 `capacity.conf`**。
|
|||
|
|
- **哨兵**:`OBS-12 relay RSS ≤ 800000KB`(每 host 2 MB 假设的越线报警)。
|
|||
|
|
- **§8.7③ 要求的回答已写进参数表 §5.6**:`relays[]` 顺序语义 = **主入口首位**,本单**不引入**优先级新语义。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 8.9 指纹
|
|||
|
|
|
|||
|
|
- **回填前**(规划棒交付,⛔ 本次未改动规划棒正文 §1–§7 与附A/附B 的既有结论,只追加了 §8 与两处勘误说明)
|
|||
|
|
- **本节口径**(**推荐核对用**,可复现):**整个 §8.9 不计入** ⇒ 复核命令
|
|||
|
|
`sed '/^## 8\.9 指纹$/,$d' 交接单_参数表与观测_20260917.md | md5sum` ⇒ `ea5cf5158129467a03608410a10be2e7`
|
|||
|
|
- **全文件 md5**:请用 `md5sum 交接单_参数表与观测_20260917.md` 现取 —— ⛔ 此处**故意不内嵌数值**:它包含本节自身,写进去即刻失效(自指)。
|
|||
|
|
|
|||
|
|
> ⚠️ **一次非预期改写的披露(已完全回滚,逐字复核通过)**:回填过程中一条 shell 命令里的反引号被当成**命令替换**,导致本文件被插入 25,761 段垃圾串(每字符之间一段)。**当场发现并回滚**(`replace` 逆操作 ⇒ 垃圾串计数 `0`),随后 `wc -l` / 章节标题 / 抽样 3 行逐条复核**与预期一致**,正文无残留。⇒ 记录在此,供下一棒对账时知情。
|