代码
- 内容分发块级寻址:新增 src/net/relay/content/{chunker,store,runtime,source,peer,crypto}.ts
- 组密钥(C 档)确定性加密:AES-256-GCM,块 id β′ = sha256(密文) 前 32 hex;双 epoch 过渡窗口
- 实例生命周期:三处 teardown() 不再杀实例(local/remote/leased-spawner);启动认领 + TCP 探活判孤儿
- 骨干选路:jitter 选路 + endpoint-target;relay client/server/wire/identity/directory/rendezvous/switcher 调整
- 工作台 src/web/server.ts、src/worker/relay-tunnel.ts 装配与候选链观测
脚本与测试
- scripts/overlay-{probe,keyring,jitter}.cjs 更新
- 探针新增 OBS-21(每连接候选数)/ OBS-22(teardown 静态守卫 + 认领面)/ OBS-23(组密钥加密)
- 新增 test/{orchestrator-teardown,orchestrator-rehydrate,overlay-content,overlay-jitter}.test.mjs;relay 两例更新
文档
- 新增交接单:覆盖网络-序24-内容分发块级寻址 / 序25-实例逐步拉起 / 序26-骨干稳定选路与加密
- INDEX.md、交接单/README.md、skills/dsh-auto-handoff-chain/SKILL.md 同步
验收(零回归,2026-09-18 08:0x 复核)
- npm test 201 tests / 200 pass / 0 fail / 1 skipped
- overlay-failover-drill --scene all --table 12 PASS / 0 SKIP / 0 FAIL
- overlay-probe --table 23 PASS / 0 SKIP / 0 FAIL (rc=0)
178 lines
12 KiB
Markdown
178 lines
12 KiB
Markdown
# 交接单 · 骨干节点落地(稳定高效选路 + 传输可加密)
|
||
|
||
- **序号**:覆盖网络线 **序 ㉖ · 规划棒**
|
||
- **立单**:2026-09-17 20:3x
|
||
- **用户拍板**:**「入口 §4 骨干节点的服务范围:按照连接稳定高效的方式 数据安全可加密传输」**(2026-09-17 20:2x)
|
||
- **上游依据**:`覆盖网络_骨干层方案_20260916.md` **§7(原 A/B 待拍板)**/**§8 落地顺序**/`覆盖网络_瓶颈落地方案_20260916.md` **§4(jitter 是一等指标)**/`覆盖网络_补遗与参考方案_20260916.md`(45% 设计 / 55% 余量口径)
|
||
- **状态**:**待执行**
|
||
|
||
---
|
||
|
||
## §0 摘要 + 我把用户口径翻译成的两条硬判据
|
||
|
||
用户**没有按 A/B 选**,而是给了一句**目标导向**的话:**「按照连接稳定高效的方式 数据安全可加密传输」**。
|
||
|
||
⇒ **我的解读(已定项,可推翻)**:用户要的不是"服务范围"这个二元选择,而是**两条可验证的工程质量判据**:
|
||
|
||
| 口径 | 翻译成机器判据 | 与 A/B 的关系 |
|
||
|---|---|---|
|
||
| **连接稳定高效** | **选路按 jitter 排序**(⛔ 不按 RTT)+ 每连接保 2–3 条候选路径 + 中继利用率留 **30%+** 余量 + 骨干间心跳 ≤10 成员全互联 | **与 A/B 正交** —— 无论自用还是全网,这条都要满足 |
|
||
| **数据安全可加密传输** | ① 传输层加密(**wss/TLS 已在**,⛔ 不新造)② **内容/信令完整性由签名与哈希兜住**(本线已有 relay 签名目录 + 密钥体系)③ **对外只暴露"转发能力",⛔ 不暴露"看到谁连谁"的元数据** | **B 档的最大缺点正是"骨干会看到流量元数据"** ⇒ 用户这句**恰好把 B 档的最大代价按住了** |
|
||
|
||
✅ **因此我的判定(可推翻):按 "A 起步、口径按 B 的质量标准建设" 落地** —— 即 **§7 原倾向 A→B 渐进 与用户口径并不冲突**:
|
||
- **可见范围**仍取 **A**(只服务自己名下设备):无计费/合规纠纷、权限面不变(⛔ 不命中 R5)、元数据暴露面最小 —— **这直接满足"数据安全"**;
|
||
- **质量与冗余**按 **B 的标准**建设(多中心骨干、jitter 选路、30%+ 余量):**这直接满足"稳定高效"**;
|
||
- **"可加密"** ⇒ 做成**能力就位**(TLS + 签名 + 内容哈希),**⛔ 不在本单引入端到端加密**(见 §7)。
|
||
|
||
---
|
||
|
||
## §1 目标(可判定"做完了没有")
|
||
|
||
| # | 判据 | 期望 | 怎么测 |
|
||
|---|---|---|---|
|
||
| **E1** | **选路按 jitter**(⛔ 不按 RTT) | 两候选路径中 jitter 更低者被选中,**即使其 RTT 更高** | 夹具:候选 A(RTT 20ms/jitter 15ms) vs B(RTT 30ms/jitter 2ms) ⇒ 断言选 **B** |
|
||
| **E2** | **jitter 可观测** | 每连接有 jitter 直方图 + 超阈值自动切路径并**告警** | 判别器计数 + 直方图落盘 |
|
||
| **E3** | **路径多样性** | 每连接维护 **2–3 条**候选(直连 / 就近中继 / 备用中继) | `/status` 可查候选数 ≥ 2 |
|
||
| **E4** | **利用率留余量** | 中继利用率 ≤ **70%**(留 30%+) | `used / capacity` 可查、超限**拒绝新接入**(⛔ 不打满) |
|
||
| **E5** | **骨干互认只校验不自行批准** | 控制面签发资格;骨干间只验签 | 未签名骨干接入 ⇒ 被拒并**点名** |
|
||
| **E6** | **元数据最小化**(A 档) | 骨干**只知"转发给谁",不知"谁在连谁"**;跨用户**不可见** | 断言跨用户 0 命中(与内容分发的 `E5` 同族) |
|
||
| **E7** | 零回归 | `npm test` **176/175/0/1**、`--scene all --table` **12P/0S/0F**、`overlay-probe --table` **16P/0F/0S** | 三件套跑同值 |
|
||
|
||
---
|
||
|
||
## §2 只读前置(执行前**必须**先核实的 5 条)
|
||
|
||
| # | 要核实什么 | 命令 | 期望 |
|
||
|---|---|---|---|
|
||
| **P1** | 现行 relay 是否**已**做到"只绑回环 + 443 兜底" | `ss -lntp` + relay ExecStart | 已实测:两台 relay 均**只绑 `127.0.0.1:20080`**、106 复用既有 443 ⇒ **零新增公网口**(⛔ 本单不许破坏这条) |
|
||
| **P2** | 现行选路是**按什么排序** | 读 `src/net/relay/switcher.ts` / `directory.ts` | ⚠️ 预判:**按健康度/冷却**,**⛔ 不是按 jitter** ⇒ 这是本单的主要缺口 |
|
||
| **P3** | jitter 现测值 | `scripts/overlay-jitter.cjs` | 已有脚本;序⑥ 实测 `p95(\|ΔRTT\|)` = **3 ms**(达标)⇒ **本单把"点测"变成"持续采样 + 参与选路"** |
|
||
| **P4** | 骨干"资格"体系现状 | `scripts/overlay-keyring.cjs` + relay `keys` 表 | 已有四层密钥模型(离线根 → 在线签名者 → 每机节点密钥 → 会话)+ 逻辑名索引 + 成员资格校验 ⇒ **E5 大部分已就位** |
|
||
| **P5** | 45% 容量口径现值 | 参数表 `RELAY_MAX_HOSTS` | 实测 **7515**(序⑥ 重算并已下发两台)⇒ 本单**只读不改**,⛔ 不动容量值 |
|
||
|
||
---
|
||
|
||
## §3 范围
|
||
|
||
### 3.1 在册文件集(⚠️ **超出必须先停下报告** — R7)
|
||
|
||
| 面 | 文件 | 说明 |
|
||
|---|---|---|
|
||
| 新增 | `src/net/relay/jitter.ts` | jitter 采样与直方图(**选路的输入**) |
|
||
| 改动 | `src/net/relay/directory.ts` | 候选排序:健康度 → **jitter 为主序**(⛔ 不删既有冷却语义) |
|
||
| 改动 | `src/net/relay/switcher.ts` | ⚠️ **只加"jitter 劣化即切",⛔ 不改冷却语义** |
|
||
| 改动 | `src/net/relay/server.ts` | 利用率守卫(`E4`)+ 候选路径可查(`E3`) |
|
||
| 改动 | `scripts/overlay-jitter.cjs` | 点测 → 持续采样 |
|
||
| 改动 | `scripts/overlay-probe.cjs` | 新增 `OBS-17`(jitter)/`OBS-18`(余量) |
|
||
| 改动 | `参数表_覆盖网络_20260917.md` | 新增 `JITTER_*` / `RELAY_UTIL_MAX_PCT` 键 |
|
||
|
||
⛔ **不在本单范围**:`RELAY_FAILOVER_*` 任何值、`HB_SEC`、burst、`switcher.ts` 冷却语义、`RELAY_MAX_HOSTS`、房间层、打洞实现、内容分发的块级实现(**另单**,见 `交接单_内容分发块级寻址_20260917.md`)。
|
||
|
||
### 3.2 三条硬约束
|
||
|
||
1. 🔴 **⛔ 不改 `switcher.ts` 冷却语义**(本线持久禁令)—— 只**新增** jitter 触发条件。
|
||
2. 🔴 **⛔ 不新增公网监听口 / 不改 nft·nginx**(R5)—— 骨干仍只绑回环 + 443/TCP 兜底复用。
|
||
3. 🔴 **骨干资格只能控制面签发**(权威状态单点 Manager)—— 骨干**只校验,不自行批准**。
|
||
|
||
---
|
||
|
||
## §4 步骤 S0–S6
|
||
|
||
| 步 | 做什么 | 验证(一次可执行) | 回滚 |
|
||
|---|---|---|---|
|
||
| **S0** | 只读前置 `P1–P5` + 基线 jitter 采样(**零改动**) | 输出 Before:现行选路按什么排序(**原文行号级证据**) | 无(只读) |
|
||
| **S1** | jitter 采样与直方图(`jitter.ts`) | 夹具:喂 3 条已知 jitter 序列 ⇒ 直方图与 p95 **逐项可断言** | 删新增文件 |
|
||
| **S2** | **候选排序改为 jitter 为主序**(`directory.ts`) | `E1`:**先红后绿**(jitter 更低但 RTT 更高的那条**必须被选中**) | 还原排序函数 |
|
||
| **S3** | 切换条件新增"jitter 劣化即切"(`switcher.ts`,⛔ 不碰冷却) | `E2`:劣化 ⇒ 切 + 告警;⛔ 冷却语义断言**不变** | 移除新增条件 |
|
||
| **S4** | 利用率守卫 + 候选可查(`server.ts`) | `E4`:利用率 > 阈值 ⇒ 拒绝新接入并**点名**;`E3`:候选数 ≥ 2 | 还原守卫 |
|
||
| **S5** | 骨干互认与元数据最小化复验(`E5` / `E6`) | 未签名骨干被拒并点名;跨用户 0 命中 | 同 S2 |
|
||
| **S6** | 真机验收 + 观测 + 零回归(`E7`)+ 收口 | 三件套同值;探针新增 2 项 PASS | 产物回滚点 |
|
||
|
||
---
|
||
|
||
## §5 验收判据 E1–E7
|
||
|
||
见 **§1**。⚠️ **`E1` 是主判据**("选路按 jitter 排序而非 RTT")—— 这一条**能不能机器断言**,决定了"连接稳定高效"是不是**嘴上说说**。
|
||
|
||
---
|
||
|
||
## §6 回滚(两层)
|
||
|
||
1. **排序级**:还原 `directory.ts` 的排序函数 + 移除 `switcher.ts` 新增条件 → `tsc` → scp `lib/` → `restart dshs` ⇒ 回到"按健康度/冷却"的旧选路。
|
||
2. **产物级**:scp 回滚点 `/opt/dsh/backups/seq26-<ts>/lib/net/relay/{directory,switcher,server,jitter}.js`。
|
||
🔴 ⛔ **回滚路径里不许出现 `RELAY_FAILOVER_COOLDOWN_MS=0`**。
|
||
|
||
---
|
||
|
||
## §7 安全与加密档位(**用户口径的关键落点**;属已定项、⛔ 不再上抛)
|
||
|
||
用户原话:**「数据安全可加密传输」**。逐条落法:
|
||
|
||
| 层 | 现状 | 本单怎么做 |
|
||
|---|---|---|
|
||
| **传输层加密** | ✅ **wss / TLS 已在**(relay 经 `https://alotbuy.com/dshs-relay` 可达、双路 101) | **复用,⛔ 不重造**。骨干之间同样只走 wss |
|
||
| **身份与授权** | ✅ 四层密钥模型已落地(离线根 → 在线签名者 → 每机节点密钥 → 会话)+ 逻辑名索引 + 成员资格校验 + 吊销演练通过 | `E5`:**骨干间只校验,不自行批准**(补齐"骨干资格"这一档) |
|
||
| **完整性** | ✅ 有签名目录 | 信令与目录**全程验签**;⛔ 不引入第二套密钥体系 |
|
||
| **元数据最小化** | ⚠️ B 档的最大缺点是"看到谁连谁" | `E6`:**A 档可见范围** ⇒ 骨干**只知转发目标、不知连接双方**;跨用户不可见 |
|
||
| **端到端加密(E2E)** | ⛔ **不做** | **属真取舍**:E2E 会让"每个接收者密文不同" ⇒ **与内容分发的按哈希共享块直接冲突**(要加密就失去共享)⇒ 本阶段取 **"TLS + 验签 + 内容哈希"**;E2E 登记为**待评估**(见 §9-3) |
|
||
|
||
🔑 **一句话**:**"可加密"= 能力就位(TLS + 验签 + 哈希)+ 元数据最小化**,⛔ **不是**"现在就上端到端加密"。
|
||
|
||
---
|
||
|
||
## §8 回报格式(执行会话**必须**回填)
|
||
|
||
```markdown
|
||
### 8.x 序 ㉖ 执行棒回报(YYYY-MM-DD HH:MM–HH:MM)
|
||
|
||
#### ① S0–S6 逐条(命令 + 原文输出 + 判定)
|
||
|
||
#### ② 主判据 E1:jitter 更低(但 RTT 更高)的候选被选中
|
||
- 候选 A = ? | 候选 B = ? | 实测选中 = ? | 原文 = ?
|
||
|
||
#### ③ 先红后绿(原文级)
|
||
|
||
#### ④ 零回归三件套(均带 `--table`)
|
||
|
||
#### ⑤ 边界自证
|
||
⛔ 未改 `switcher.ts` 冷却语义 / ⛔ 未改生产值 / ⛔ 未新增公网口 / ⛔ 未改 nft·nginx / 🔴 `COOLDOWN_MS=0` = ? / ⛔ 未 commit·未 push
|
||
|
||
#### ⑥ 指纹
|
||
参数表 = ?(前值 `42238175d84319ada99afa56d583f9db`)|directory.ts / switcher.ts / server.ts md5 = ?
|
||
```
|
||
|
||
---
|
||
|
||
## §9 回头条件(**一出现必须回头**)
|
||
|
||
1. 要**改 `switcher.ts` 冷却语义** ⇒ 停下报告(持久禁令)。
|
||
2. 要**新增公网监听口 / 改 nft·nginx** ⇒ 停下报告(R5)。
|
||
3. 要引入**端到端加密**(E2E)⇒ **属真取舍**(加密即失去按哈希共享块)⇒ 停下上抛。
|
||
4. 要**改 `RELAY_MAX_HOSTS` / 45% 容量口径值** ⇒ 停下报告。
|
||
5. 需要**超出 §3.1 文件集** ⇒ 停下报告(R7)。
|
||
6. `E1` 跑不出机器断言 ⇒ 停下报告,⛔ 不许放宽判据凑绿。
|
||
7. 零回归三件套任一退化 ⇒ 停下报告。
|
||
8. 🔴 ⛔ **不许把 `RELAY_FAILOVER_COOLDOWN_MS=0` 写进任何回滚 / 演练 / 夹具路径**。
|
||
|
||
---
|
||
|
||
## §10 未验证项
|
||
|
||
| # | 项 | 状态 |
|
||
|---|---|---|
|
||
| 1 | 各网络类型实际占比(决定骨干数量需求) | ⚠️ 上游仍为推演设定 |
|
||
| 2 | 骨干上行带宽是否够(家宽上行常远小于下行) | ⚠️ 上游未实测 |
|
||
| 3 | E2E 加密与块级共享的取舍 | ⚠️ 本单**未做**,登记待评估 |
|
||
|
||
---
|
||
|
||
## §11 指纹与状态
|
||
|
||
| 项 | 值 |
|
||
|---|---|
|
||
| 本单 §8 之前正文前缀指纹 | **`dbcbe633aa1aef92f4c35c77fad3ec11`**(口径 = `sed '/^## §8 /,$d' 交接单_骨干稳定选路与加密_20260917.md \| md5sum`) |
|
||
| 参数表指纹(立单时) | **`42238175d84319ada99afa56d583f9db`** |
|
||
| 代码仓 HEAD(立单时) | `04776af` |
|
||
| 本单全文件 md5(立单时) | `f85b86234c2ecfaef5b2e43aa40d86a3`(176 行) |
|
||
| 本单状态 | **待执行** ⇒ 交**序 ㉖ 执行棒** |
|