回收 411 MB(470 M → 58.8 M),全部经回收站,可恢复: - 待清理/(146.2 M,含 relay 分片 128 M 与 42 项过程目录) - tmp/(32.4 M,按接续棒命名的过程临时区) - .workbuddy/tmp/(39.5 M) - 4 份 workbuddy.db 冗余副本(101 M,09-23 事故的坏副本 / 抢救产物) - tmp/im16/gw/centrifugo 二进制(63.9 M,可重下)+ 缓存残留 入库范围:常驻规则(CODEBUDDY.md / README.md / state.py)、在途接续入口与 接续包、docs/、交付物/、交接单/、归档/、scripts/、.codebuddy/、 .workbuddy/memory/;共 398 件,其中 >60 KB 的 26 件全为文档。 排除(.gitignore):tmp/、待清理/、运行态日志与缓存、*.db 与 DB 备份整目录、 打包二进制(*.tar.gz / *.tgz)、记忆修复前备份。
20 KiB
方案规划方法 —— 从覆盖网络线提炼(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% = 估算;presence16,700 次/秒= 推算。
常见失手
⛔ 把业内口径当自家实测(会导致后续所有容量结论虚高)|⛔ 只收"支持我结论"的资料|⛔ 范围边界写成事后补充。
2. 第二段 · 方案调研
只回答一个问题:这套东西别人已经做过吗、踩过什么坑——目标是照抄,不是发明。
核心原则(一句话)
关键是照抄它们踩过的坑,而不是自己发明。(覆盖网络线原文口径)
要做的三件事
- 参考方案对照表:
能力域 → 参考方案 → 借什么。"借什么"必须写具体(不是"参考 Tailscale",而是"借它的控制面/数据面分离 + DERP 区域模型")。 - 默认参数直接固化:成熟项目的默认值不要自己拍(libp2p 的拨号并发 ≤4 / 总 100 / 超时 30 s、连接水位 100/400/1 min、中继自荐 15 min/30 min TTL、BitTorrent 上传并发 4 等)⇒ 直接进 §1 的参数表。
- 分层:先给架构分层(覆盖网络线 = 控制面 / 会合层 / 骨干中继层 / 数据面 / 观测层五层),再谈组件。分层定了,后面"这块放哪"才有判据。
先拆概念(这一步经常被跳过,然后全盘皆错)
覆盖网络线的实例:「插件」这个项目里有两个完全不同的含义 —— (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头(改它 = 全量/api403);② 说"有 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 收尾三件套(每份推演都必须有)
- 未验证项表(标题就写"勿当结论")—— 所有不能证实的,统一放这里;
- 本次未做(范围声明) —— 明确边界,避免下游误读;
- 上抛项收敛 —— 写"未新增上抛项"或列出新增项;能排出优劣的自己拍掉。
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 | 未验证 | 本方法尚未在第二条线上复用过 ⇒ 尚属"一次成功案例反推",不是已验证的通用流程 |