Files
dsh_shenxian/dsh-server-docs/04-调整方案/123-方案规划方法-覆盖网络线提炼.md
T
admin 04776af4b1 docs: 工作区根项目文档批量入仓(04-调整方案 113–128 / 交接单 T09–T21 / ops / archive)
起因:用户 2026-09-17 明确「所有文档都要同步,都放在开发仓库 docs 对应文件夹下」。
判据:工作区根 *.md 中在仓库(git ls-files --quotepath=false)搜不到的那些。

入仓 33 份(一律复制,工作区根原件保留不动,避免引用断链):
- 04-调整方案/113–128(16 份 · 原子占号后落盘):覆盖网络 传输方案取舍 / 应用场景与待完善清单 /
  插件化vs改内核 / 问题逐条推演 / 参数表与观测口径;会合中继拆分取证与改造方案;
  集群化改造方案 Manager-Worker;跨节点迁移与节点自举;项目代码分层范式与迭代风险评估;
  搬运与共享重建方案 guest w47→w106;方案规划方法提炼;文档无效信息审计报告;
  会话接续机制复盘与修复;会话接续规范;dsh 客户端化部署方案;dsh 桌面客户端开发方案
- 交接单/archive/交接单-已完成/T09–T21(13 份 · 覆盖网络线已完成单归档)
- ops/(2 份运行态指针:接续入口 / 接续包 · 覆盖网络线)
- archive/(2 份临时与内部简报)

已排除(无需重复入仓):覆盖网络线 10 份方案正文已入档案 103–112(文件名不同)。

登记:INDEX.md §二 新增 04-113–128 共 16 行 + §四 追加 T09–T21 说明 + 机器摘要行刷新
(⛔ 未跑 docs-index-stats.py --write:该脚本会按 \r\n 归一化全文件行尾,故改为字节级单行替换);
README.md 追加 1 条入仓指针;docs-manifest.json 复跑 scripts/docs-manifest.py 刷新。

验收:工作区根 47 份 .md —— 同名已入仓 8 / 本次内容一致 29 / 已知改名映射 10 / 未入仓 0;
git status 待提交清单只含本次新增与登记 3 件(未涉 src/ 与 relay 代码面)。
2026-09-17 18:24:19 +08:00

316 lines
20 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 方案规划方法 —— 从覆盖网络线提炼(2026-09-16)
> **它是什么**:一套「从零推演出一个可落地架构」的分段作业法。五段 = **信息收集 → 方案调研 → 场景梳理 → 逻辑验证 → 应用推演**,每段有固定骨架、固定产出、固定出口判据,全部走完才允许进入执行。
> **它不是凭空设计的** —— 是从覆盖网络线 **17 份文档 + 6 份勘误 + 1 次落地执行** 的真实过程里**反推**出来的(§9 有 8 次纠错作证)。
> **适用边界**:信息不全、没有现成答案、要一次拍准方向的重规划任务。**小改动不需要这么重**(那种直接按 `dsh-change-workflow` 六阶段走即可)。
> **不适用范围**:已有明确技术答案的实现任务;单文件改动;纯 UI 调整。
---
## 0. 一句话总览
**把"一个大到没法定的事"拆成五段流水线;每段只回答一个问题,出口必须能给"这步做完了吗"的判据。**
```
① 信息收集 该知道的数,都有出处了吗? → 参数表(实测 / 业内 / 推算 三档标注)
② 方案调研 别人踩过的坑,照抄了吗? → 参考方案对照 + 分层架构
③ 场景梳理 要扛的事,列全了吗?口径对了吗? → 场景清单(含故障)+ 完成度表
④ 逻辑验证 每条推得通吗?有跳跃/矛盾吗? → 缺口清单 P0/P1/P2 + 勘误 + 反模式
⑤ 应用推演 叠加起来先炸哪个?能算吗? → 流量预算总表 + 瓶颈先炸顺序
────────────────────────────────────────────────────────
出口闸门 估值换成实测 + 参数表固化 + 权限/成本评估 → 交接单(方可开工)
```
**五段的顺序不可交换**:跳过 ③④ 直接做 ⑤,会得到"数字很漂亮但前提是错的";跳过 ①② 直接做 ⑤,会得到"自己发明的一套轮子"。
---
## 1. 第一段 · 信息收集
**只回答一个问题**:我要用的每个数、每条结论,**出处是什么、可信到什么程度**。
### 要做的四件事
| # | 动作 | 判据 |
|---|---|---|
| 1 | **范围边界前置** | 文档开头写死「只做什么 / 不考虑什么」,并注明这是**谁的口径**(用户原话 / 自定) |
| 2 | **找对照组(能力标尺)** | 每个能力域找到**真实在跑的产品**作标尺,不允许"我觉得" |
| 3 | **数据分三档标注** | **实测**(本环境有命令/证据)|**业内口径**(有出处,非本环境)|**推算**(自己算的)——⛔ 三档不许混写 |
| 4 | **先标"最该先测的三项"** | 在收集阶段就点出"哪几个数一换、全部结论的可信度就变" |
### 覆盖网络线的实例
- 范围声明(用户原话):「**方案只考虑技术实现,跨境数据合规是谁用谁自己考虑**」⇒ 此后所有文档统一带 🟢 范围声明,且**选型不为合规让路**。
- 对照组:Tailscale / headscale / ZeroTier / Nebula / libp2p / BitTorrent / Slack / Telegram / WhatsApp / Discord / SCCM / restic。
- 三档标注实例:首屏 `10.8 MB`、跨云 `22 KB/s`、心跳 `20 s` = **实测**;打洞率 90%/40%/10% = **估算**;presence `16,700 次/秒` = **推算**。
### 常见失手
⛔ 把业内口径当自家实测(会导致后续所有容量结论虚高)|⛔ 只收"支持我结论"的资料|⛔ 范围边界写成事后补充。
---
## 2. 第二段 · 方案调研
**只回答一个问题**:这套东西**别人已经做过吗、踩过什么坑**——目标是**照抄**,不是发明。
### 核心原则(一句话)
> **关键是照抄它们踩过的坑,而不是自己发明。**(覆盖网络线原文口径)
### 要做的三件事
1. **参考方案对照表**:`能力域 → 参考方案 → 借什么`。**"借什么"必须写具体**(不是"参考 Tailscale",而是"借它的控制面/数据面分离 + DERP 区域模型")。
2. **默认参数直接固化**:成熟项目的默认值**不要自己拍**(libp2p 的拨号并发 ≤4 / 总 100 / 超时 30 s、连接水位 100/400/1 min、中继自荐 15 min/30 min TTL、BitTorrent 上传并发 4 等)⇒ 直接进 §1 的参数表。
3. **分层**:先给架构分层(覆盖网络线 = 控制面 / 会合层 / 骨干中继层 / 数据面 / 观测层**五层**),**再谈组件**。分层定了,后面"这块放哪"才有判据。
### 先拆概念(这一步经常被跳过,然后全盘皆错)
覆盖网络线的实例:「插件」这个项目里**有两个完全不同的含义** —— (a) dsh 官方插件(跑在实例内部)**够不到宿主网络栈**;(b) 平台自身的模块化。**没先拆这两个概念,就会在错的对象上讨论"插件 vs 改代码"**。
⇒ **判据**:出现一个术语可能指两件事时,**先列表拆开**再往下走。
### 三层归属(普适判据,可直接复用)
| 层 | 内容 | 形态 | 判据 |
|---|---|---|---|
| 数据面组件 | 要碰宿主网络栈、要独立扩缩容与加固 | **独立进程 / 独立 systemd 单元** | 与主进程**同生共死**就出局 |
| 平台侧集成 | 寻址、身份、资格签发、容量准入 | **改平台代码** | **必须与权威状态同源**(外置 = 第二个权威源 = 脑裂) |
| 实例内展示与工具 | 「我的 XX」面板、实例内工具 | **插件** | 纯实例内 UI/工具才配插件 |
---
## 3. 第三段 · 场景梳理
**只回答一个问题**:这东西**被用在什么场景、要扛多大**——且**先确认口径对不对**。
### 要做的五件事
| # | 动作 | 说明 |
|---|---|---|
| 1 | **口径先校正** | 目标场景必须由用户确认过;文档里显式写 `📌 口径校正(日期,谁纠正)` |
| 2 | **设备/环境画像** | 按类列表(不是平均值):覆盖网络线用 6 类(云服务器 / 家宽 / CGNAT / 移动网 / 企业网 / VPN)× 台数 × 成功率 |
| 3 | **场景枚举含故障** | **正常场景 + 故障场景 + 极端场景**三类都要有(S1–S11 含"中继故障 / 控制面重启 / 区域突变 / NAT 表溢出") |
| 4 | **分工矩阵** | `环境类型 × 应用 → 关键约束`(一眼看出"哪类节点必然走中继") |
| 5 | **完成度表** | **纸面推演 / 可运行模拟 / 实测** 三档分开标 ——⛔ 不许把"纸面算过"说成"验证过" |
### 关键动作:把口径纠正当成产出
覆盖网络线真实发生过一次重排:用户明确目标场景 = **① 多人 + agent 对话 ② MUD / MMORPG 网游 ③ 以上述应用为负载的 1000 台异构网络互联** ⇒ 原报告把"跨机访问实例/文件交换"排第 1 档**属次级用途,已重排**。
⇒ **教训**:场景优先级排错,后面全部推演**都在给次要场景做容量**。**这一步上抛是值得的**(属"业务目标与优先级",是边界外真门禁)。
### 常见失手
⛔ 只列正常场景(故障场景才是容量规划的主体)|⛔ 用"平均设备"代替异构画像(掩盖了 CGNAT/移动网这类**必走中继**的少数派)|⛔ 不标注"哪些是纸面"(下游会把推演当事实)。
---
## 4. 第四段 · 逻辑验证(**本方法的核心**)
**只回答一个问题**:从场景到结论,**每一步都站得住吗**。
### 4.1 固定四段骨架(**每条问题都按这个写,不例外**)
```
① 问题 —— 一句话说清缺什么/错在哪
② 查到什么资料 —— 业界范式 + 出处(能照抄就给照抄点)
③ 推演 —— 拿资料 + 我方实际约束,推出来
④ 结论 —— 能不能解 / 怎么解 / 代价是什么(三问必答)
```
> 这个骨架的价值:**它把"我觉得"逼成"资料说什么 + 我们实际是什么 + 推出什么"**。任何一条卡在②或③,说明还不到下结论的时候。
### 4.2 四类必须主动去找的"洞"(覆盖网络线全部命中)
| 类型 | 长什么样 | 覆盖网络线的实例 |
|---|---|---|
| **缺口** | 方案里有个位置**空着**,但下游已经依赖它 | "单房间上限 = min(扇出预算, presence 预算, **agent 预算**)",而 **agent 预算从未标定** ⇒ 三个预算里一个是空的 |
| **逻辑跳跃** | 结论 A 需要前提 B,而 **B 从没被论证过** | S3 算出"服放家宽 ⇒ 600 Mbps 过中继",但**玩家是外部客户端、不是网络成员,凭什么走我们的中继**⇒ 由此发现**缺一整个"发布层"**,且瓶颈性质变了 |
| **自相矛盾** | 方案内部两条约束互斥 | S5 设"1000 人房聚集 200 个 agent",而自家硬约束是"房间 agent ≤ 人数/10 = 100" |
| **事故级预判** | 不提前处理**必然**出事,且事后极难排查 | 设备池里 200 台 CGNAT + 150 台移动网**本机就在 `100.64.0.0/10` 内**;若覆盖网也用这段 ⇒ 路由黑洞、**"部分节点时通时不通",极难排查** ⇒ 主寻址必须走 IPv6 ULA + IPv4 冲突检测进首版 |
⇒ **这四类不许靠"通读一遍觉得没问题"**,要**逐条对照**:每个结论问"它的前提被论证过吗",每条约束问"它和另一条冲突吗"。
### 4.3 实测证伪 —— 纸面推演不算数
**任何"机制类的设计"在落地前,必须有一次最小实测**:
> 实例:方案 S3 原设计用"回环别名"(`ssh -R 127.0.0.2:…`)隔离中继落点。**实测**:47 的 `sshd -T` ⇒ `gatewayports no` ⇒ **`127.0.0.2` 被静默改写成 `127.0.0.1`,ssh 侧零报错**(`ExitOnForwardFailure` 未触发、日志为空)⇒ **机制作废,改用"实例端口区间隔离"**。
> ⚠️ **要点:失败是静默的** —— 如果只做纸面推演,这套机制会带着"看起来对"的样子进入生产。
**实测的副产品往往是真 bug**:顺着这条线查出 `findFreePort()` 各 worker 各自随机 + `tunnel.forward()` 返回值**两处被忽略** ⇒ 撞号时 `-R` 失败但**静默** ⇒ Manager 照旧拨 `127.0.0.1:<port>` ⇒ **静默打到另一个用户的实例**。这条 **两台机器即可触发**。
### 4.4 前人结论,先做最小取证
> **实证**:同一天踩两次 —— ① 方案写"`proxy.ts:109` 是中继连接目标",实为**发给上游 dsh 的 `Host` 头**(改它 = 全量 `/api` 403);② 说"有 3 处基础层反向依赖",实为**入口层的合法依赖、真实违规 0 处**。
> ⇒ **拿上一份文档的结论当既成事实,是这类规划最主要的错误来源。** 引用前必须复核(连行号都会漂:`138-139` 实测为 `136-137`)。
### 4.5 勘误要集中成节,且写清"照字面做会出什么事"
| 要求 | 说明 |
|---|---|
| 位置 | 集中一节(覆盖网络线 = 方案 §8/§9 + 交接单 §0.2),⛔ 不散落在正文 |
| 分级 | 🔴 实测证伪(改变做法)|⚠️ 需修正(不改做法)|📌 结论不变仅行号漂移 |
| 必写 | **"照原方案字面做会白做/会出事"** 一句 —— 否则执行会话会照抄 |
| 复验 | 下一轮对上一轮勘误**再确认一次**(覆盖网络线 §9.7 复验了 §8 的三条) |
### 4.6 反模式清单(同步产出)
验证过程中识别出的"踩了就出事"的做法,**汇总成表**(覆盖网络线 12 条:建全互联 / 无扇出限制的 gossip / 客户端持有权威状态 / 控制面下发全网名单 / 单中心中继 / 把网内副本当主备份 / 慢链路做备份 / 失败即重试 / agent 直接触发 agent / 推送式分发 / 共享密钥当身份 / 只按 IPv4 设计)。⇒ **这张表是给执行会话的红线,不是给自己看的笔记。**
---
## 5. 第五段 · 应用推演
**只回答一个问题**:这些场景**叠加**起来,**先炸哪个、多大、怎么治**。
### 5.1 三条层层递进的动作
**① 逐场景独立算** —— 每场景给"数值 + 判读",**判读比数值重要**(例:`presence ≈16,700 次/秒`,判读 = "**presence 比消息早爆一个量级**")。
**② 流量预算总表(全案最重要的一张表)** —— 列:`流量 × 频率 × 单次 × N 台放大 → 上限手段`。要求**可复算**(每个数从哪来能追)。
**③ 叠加推演(此前最容易漏的一步)** —— 串行列举 ≠ 最坏情况。方法三步:
| 步骤 | 做法 |
|---|---|
| **时间轴重叠检查** | 把各场景的时间窗排开(游戏高峰 20:00–22:00 / 群聊 20:00–23:00 / agent 随真人 / 备份 02:00)⇒ **重叠的才是要叠加的**;顺带确认"备份与游戏错峰"是**设计而非巧合** |
| **共享资源争用矩阵** | 列出被多方抢的**同一个资源**(出口带宽 / presence 通道 / 控制面 req/s / 客户端上行)⇒ 叠加后量级 |
| **主导项法** | **差一个数量级可忽略** ⇒ 只保留主导项,其余进"次要" |
**叠加的产出是"瓶颈排序会变"**:覆盖网络线叠加后,第一瓶颈仍是出口带宽,但**第二从「presence」变成「presence × agent 叠加」(≈33,400 事件/秒,是任何单场景的两倍)**。
### 5.2 瓶颈排序 = 按"先炸顺序"排,不是按"大小"排
产出一张 `序 / 瓶颈 / 量级 / 主要处置` 表。**这张表就是落地顺序的输入**(再按"收益 ÷ 成本"重排一次 ⇒ 覆盖网络线的结论是"**只做三件事**")。
### 5.3 数字可信度必须分级(**这条决定了整套推演的诚实度**)
> 覆盖网络线的原话口径:**"关键结论对比例敏感、对绝对值不敏感"** ⇒ **结构判断可信,具体容量数字还不可信**。
⇒ 任何一份推演都要写清:**哪些结论是"结构可信"(换个数也成立)、哪些是"数字可信"(已实测)**。⛔ 不许把两者混在一句话里。
### 5.4 收尾三件套(每份推演都必须有)
1. **未验证项表**(标题就写"**勿当结论**")—— 所有不能证实的,统一放这里;
2. **本次未做(范围声明)** —— 明确边界,避免下游误读;
3. **上抛项收敛** —— 写"**未新增上抛项**"或列出新增项;**能排出优劣的自己拍掉**。
---
## 6. 七条横切纪律(贯穿五段)
| # | 纪律 | 判据 / 反例 |
|---|---|---|
| 1 | **先只读,后动手** | 每份规划文档头部写明「⛔ 未改代码、未动服务器、未写文档库」;改任何文件前先抢执行锁 |
| 2 | **行号级引用** | 结论引用到 `文件:行`;引用前复核(行号会漂) |
| 3 | **三档数据标注** | 实测 / 业内 / 推算,三档不许混写 |
| 4 | **口径校正显式化** | 用户纠正过的地方,文档里留 `📌 口径校正` 标记,⛔ 不静默改写 |
| 5 | **上抛收敛** | 一轮只问"**真取舍**"(各有优有劣);只有优点或只有缺点的**自己拍**;**每个候选必须写优点 + 缺点,竖排成段** |
| 6 | **一条线一个入口** | 新会话只读"接续入口",不读全量日志(覆盖网络线:入口 3 KB,日志 60 KB) |
| 7 | **文档间标"承接"** | 每份文档头写"承接 X"⇒ 形成 DAG,避免重复造轮子、也避免下游读到已作废的结论 |
---
## 7. 出口闸门:什么时候可以从"推演"走到"落地"
**五段全绿不等于可以开工**。覆盖网络线把卡点收敛成**三件必须先办的事**:
| # | 闸门 | 判据 | 覆盖网络线的实况 |
|---|---|---|---|
| 1 | **把关键估值换成实测** | 最少 3–5 台真机;只测那 3 个"一换全变"的数 | 选定 **打洞成功率 / 中继 jitter / 真实可用带宽** —— ⚠️ 直到 09-16 仍未做,故容量数字仍标"不可信" |
| 2 | **参数表固化** | 所有输入参数在一张表里 ⇒ **可复算、可仿真** | 已给(B3 表),⏳ 待落文档 |
| 3 | **权限影响评估 + 成本承诺** | 扩权(R5)与花钱(边界外)**必须上抛** | 三处扩权:虚拟网卡驱动 / 骨干开端口 / **发布层对外暴露**;成本 = 发布层 + 会合 + 中继 |
**另一条独立闸门:执行前置** —— 落地前必须先把"**挡住整个方向的那一个耦合点**"拆掉。覆盖网络线的判断是:**中继绑在 Manager 上 ⇒ 多区域 / 多中心 / 骨干层全部做不了**,所以 S0–S4 排在任何功能开工之前。
> ⛔ **反模式**:一上来换协议(WireGuard / TURN)。正确顺序是"**先把耦合抽成配置与接口**,让现有实现退化成'第一个可替换实现'"⇒ 每一步独立可验、独立可回滚。
---
## 8. 落地形态:规划 → 交接单 → 执行 → 勘误
规划会话**只产出交接单**,执行会话**不读规划上下文**。交接单必含(覆盖网络线的单子模板):
| # | 段 | 要求 |
|---|---|---|
| 1 | **§0 复核结论 + 勘误** | 实测基线表 + 逐条勘误(🔴 会白做/会出事 的排最前) |
| 2 | **§1 只读前置** | 抢锁 / 读哪几节 / 照基线逐项复核 / 远程入口 |
| 3 | **§2 范围** | **做**什么、⛔ **不做**什么(把勘误结论写成禁令) |
| 4 | **§3 步骤** | 每步:改哪些文件 / 接口怎么切 / **怎么验** / **怎么回滚** —— **四件缺一不可** |
| 5 | **§4–5 全局验收 + 清理** | 用户口径的业务验收 + **测试残留必须清**(有副作用的验证脚本要写明) |
| 6 | **§6 回报格式** | 判定 → 改了什么 + 部署到哪 → 实测输出 → 未做/风险 → 锁状态。⛔ **不许写"应该没问题"** |
| 7 | **§7 已知的坑** | 省执行方踩一遍(凭据、配置位置、端口、环境限制) |
**执行完必须回写**:执行记录(P1/P2/P3 实测证据)+ 新勘误 + 未做项**为什么没做**(命中哪条红线)。
---
## 9. 方法自证:这条线上真实发生的 8 次纠错
| # | 纠错 | 由哪一段抓住 |
|---|---|---|
| 1 | **场景优先级排错** —— 把"跨机访问实例/文件交换"排第 1 档(实为次级) | ③ 场景梳理(口径校正) |
| 2 | **缺一整个"发布层"** —— 玩家是外部客户端,凭什么走中继 | ④ 逻辑验证(逻辑跳跃) |
| 3 | **自相矛盾** —— 200 个 agent 违反自家"≤人数/10" | ④ 逻辑验证(矛盾检出) |
| 4 | **回环别名机制作废** —— sshd `gatewayports no` **静默改写**绑定地址 | ④ 逻辑验证(实测证伪) |
| 5 | **地址段冲突** —— 设备池本机就在 `100.64.0.0/10` 内 | ④ 逻辑验证(事故级预判) |
| 6 | **真 bug:静默拨到别人实例** —— 端口撞号 + 返回值被忽略 | ④ 逻辑验证(实测副产品) |
| 7 | **前两条结论勘误** —— `proxy.ts:109` 是 `Host` 头;"3 处反向依赖"实为 0 处 | ④ 逻辑验证(最小取证) |
| 8 | **部署面漏了 47** —— 方案与交接单 v1 都只写了 106 | 执行阶段回写(**规划也要复核部署面**) |
⇒ **8 次里有 5 次发生在第四段**。这就是为什么第四段值得单独成段、且必须用固定骨架逐条走。
---
## 10. 可抄模板
### 10.1 文档头(三行定性质)
```
> 日期:YYYY-MM-DD | 性质:**只读推演稿 / 调研稿 / 设计稿 / 复盘稿**(⛔ 未改代码、未动服务器、未写文档库)
> 承接:<上一份文档>
> 🟢 范围:只考虑技术实现;<明确不做什么>
> 用户要求:<用户原话或口径来源>
```
### 10.2 条目骨架(第四段核心)
```
### X-n · <问题名>
**① 问题**:<一句话>
**② 资料(<范式名>)**:<可照抄的点 + 出处>
**③ 推演**:<我方实际约束 + 推出的结构>
**④ 结论**:✅/⚠️/❌ <能不能解> | 怎么解 | **代价**(缺一个不算结论)
```
### 10.3 文档尾(三件套)
```
## 未验证项(勿当结论)
| # | 项 | 状态 |
## 本次未做
- ⛔ 未改代码 / 未动服务器 / 未写文档库(原因:执行锁被 X 占用)
## 上抛
- 未新增上抛项 | 或:<项> —— A:优点/缺点 | B:优点/缺点 | 倾向
```
### 10.4 判定分级(全流程统一用词)
`✅ 已完成并验收` | `⏳ 待授权/待做` | `⚠️ 缺口/需修正` | `🔴 实测证伪/事故级` | `⛔ 禁令/反模式`
---
## 11. 已知局限
| # | 局限 | 说明 |
|---|---|---|
| 1 | **样本单一** | 方法从"覆盖网络"一条线反推 ⇒ 对"信息不全、要从零拍架构"的任务适配最好;对实现型任务偏重 |
| 2 | **第四段的产出高度依赖实测能力** | 没有真机/真环境时,只能停在"结构可信";本线的容量数字至今仍是估值 |
| 3 | **成本** | 全程 17 份文档 + 多次实测;「只做三件事」的收敛是必要的,否则规划本身会失控 |
| 4 | **未验证** | 本方法尚未在第二条线上复用过 ⇒ 尚属"一次成功案例反推",不是已验证的通用流程 |