叙事主骨架轴选择方法论 SOP
一份专题起草前先跑判定树、起草后跑检查清单的 SOP。适用范围锁定在面试深追问抗压场景。
适用边界
适用:面试深追问抗压场景——面试官会盯住你说出的任何一个数字、每一层抽象、每一个"我们做了 X 所以性能好"里的"所以"往下追。
偏移适用:面试 5–10 分钟口述(骨架应更粗)、长期个人知识库(应支持多入口)——判定树中给出偏移规则。
不适用:公开演讲 / 教学 / 内部技术分享——它们的攻击面是"听众是否理解",与深追问的"任意节点是否扎得穿"正交,本 SOP 结论套过去会失真。
为什么需要选轴
面试深追问下两种典型失守,都源自主骨架轴选错、或选对了但没让另一根轴以正确形态介入:
失守 1:广度铺满,深度打不穿
把"复杂度轴"从单机 → 主从 → 分片 → 分布式讲了一遍,看似全景,实际上面试官顺着任一节点扎下去("你说的 fsync 是抵达磁盘吗?在 EBS 上呢?")就漏气。
失守 2:深度扎得很深,但缺规模锚点
把某个原理讲到 B+ 树 fanout、slab 大小、TCP 拥塞控制曲线,但一被问"这个数字在 100 QPS 还成立吗?在 100k QPS 呢?"就翻车。
根因:这两种失守都是主骨架轴与追问攻击面错位。SOP 的作用就是让"什么条件下哪根轴当主骨架、另一根轴以什么形态介入"从"经验"转成"可核对的规则"。
三种主骨架轴
主骨架轴不是"深度 vs 广度"这样的二分——仓库里有三种真实形态:
深度轴(Depth Axis)
组织特征:沿时间 / 因果关系 / 数据流单调下钻。主线不横跳到其他复杂度分支。
典型触发问题:
- 「这个数字/结论是怎么算出来的」
- 「为什么是这个而不是那个」
- 「点击到看到响应之间发生了什么」
攻击面对应:面试官会顺着任一因果节点扎下去,直到你答不上或触底为止。深度轴的每个节点已经预置了下钻答案,所以抗追问。
复杂度轴(Complexity Axis)
组织特征:沿规模 / 节点数 / 数据量 / QPS 的阶梯横向展开。每一层引入的是新问题,而不是同一问题的更深原理。
典型触发问题:
- 「从 X 到 Y 时会遇到什么新问题」
- 「这个方案的规模上限在哪」
- 「10 台机器和 1000 台机器时做法一样吗」
攻击面对应:面试官会问"到了 X 规模呢"、"节点挂一半呢",复杂度轴的每一层已经预置了触发它的规模阈值与失败信号。
决策矩阵轴(Decision-Matrix Axis)
组织特征:主骨架不是一条线,而是多个正交维度构成的对照表。每一格是一种维度组合,都有对应的实现选择。
典型触发问题:
- 「A 和 B 组合的情况怎么办」
- 「X 与 Y 冲突时怎么选」
- 「计划态和故障态的处理有什么不同」
攻击面对应:面试官会问"这两个维度撞一起呢",决策矩阵轴的每一格已经预置了对应的选择和理由。
三种轴不是同一层次的东西。硬用二分(只有深度 / 复杂度)时,矩阵型专题会被强塞进复杂度轴变形;SOP 承认三种。
3 层判定树
起草任何一个新专题前,顺次回答三层,得到主/次轴分工。
第 1 层:读者场景
- A. 面试深追问抗压 → 走第 2 层
- B. 面试 5–10 分钟口述 → 主轴 = 复杂度轴 / 次轴 = 深度轴(次轴形态:只对 1–2 个高价值节点做深挖,其余按骨架带过);跳过第 2、3 层
- C. 长期个人知识库 → 主轴 = 由读者第一次进入的入口决定 / 次轴 = 通过交叉索引以脚注或反向链接介入;跳过第 2、3 层。起草时须显式指定"读者第一次进入的入口轴"
第 2 层:触发问题类型(仅深追问场景)
- 因果类("这个数字怎么算的"、"为什么是这个不是那个"、"X 到 Y 中间发生了什么")→ 主轴 = 深度轴
- 规模类("到 X 规模会怎样"、"这个方案的上限"、"从 N 到 10N 时的变化")→ 主轴 = 复杂度轴
- 多维权衡类("A 和 B 组合"、"X 与 Y 冲突时的选择"、"计划态 vs 故障态")→ 主轴 = 决策矩阵轴
第 3 层:面试官追问预期(决定次轴介入形态)
- 主轴 = 深度轴:次轴 = 复杂度轴,形态 = 在每个深度节点后附一句"该数字/结论在什么规模下才成立"的规模锚点
- 主轴 = 复杂度轴:次轴 = 深度轴,形态 = 每一层的关键机制扎穿一处实现细节
- 主轴 = 决策矩阵轴:次轴 = 深度轴,形态 = 每个矩阵格的关键选择扎穿理由
反自动机提示:这不是自动机——遇到与三种场景都不完全匹配的情况,选择偏向读者的实际决策场景。多数专题的主轴在起草过程中会自然浮现,判定树是用来事后核对而不是取代判断。
面试深追问场景下的默认映射
把第 2、3 层的结论压平成一张表:
| 触发问题类型 | 主轴 | 次轴 | 次轴介入形态 |
|---|---|---|---|
| 因果类 | 深度轴 | 复杂度轴 | 规模锚点脚注 |
| 规模类 | 复杂度轴 | 深度轴 | 每层扎穿 1 个实现细节 |
| 多维权衡类 | 决策矩阵轴 | 深度轴 | 每个矩阵格的关键选择扎穿理由 |
为什么深度轴处理因果类问题:深追问的攻击面是"任意节点是否扎得穿",而深度轴的节点天然抗追问(每个节点已带下钻答案)。反过来,深度轴独用又容易被"换个规模呢"翻车,所以复杂度轴以脚注形态介入,成本低、覆盖率高。
为什么复杂度轴处理规模类问题:规模类问题的攻击面是"从 X 到 Y 的跃迁",深度轴的单调下钻答不上这种横向问题;复杂度轴的每一层是不同规模下的新答案。
为什么决策矩阵轴处理多维权衡问题:多维问题的攻击面是"两个维度组合成的第三种场景",只有矩阵结构能一格一格地覆盖。
案例:仓库里的三个正例
三个来自本仓库的真实专题,各自属于三种轴之一——它们是"未经方法论指导就自然长成"的样本,因此是可信的证据。
案例 1:深度轴主骨架 — web-200ms-narrative
参考:docs/.vuepress/public/200ms-cn/index.html / spec:openspec/specs/web-200ms-narrative/spec.md
主骨架:九幕结构按时间 μs → ms 单调下钻——点击 / 名字 / 握手 / 请求启程 / 抵达内核 / 走进 Node.js / 数据库 / 响应 / 归途。总时长 T_END = 211.4 ms,页面时钟单调递增。
次轴介入:每个精确数字(62 ms RTT、4,700 km、~60 次放大、PID 1447、initcwnd 10、slab 64 KB)都附一个 <sup class="fn"> 数字脚注,说明"这个数字怎么算 / 参考自哪份规范"——这正是"复杂度轴以规模锚点脚注形态介入"的实现。
为什么它成立:它服务的触发问题是"一次请求 211.4 ms 是怎么用掉的",标准因果类。九幕沿一条不横跳的时间线走到底、每个数字可追溯,任何追问最终都回到深度轴。
若强行换轴(想象性反例):如果把 200ms 改成复杂度轴("单机 → 主从 → CDN 边缘计算"),它会变成一份 CDN 教科书目录,读者失去"一次请求 211.4 ms"这条唯一主线;面试官问"你刚才那个 62 ms 是怎么来的"时,答题者只能回到 CDN 分层再挑一个节点扎,深度追不到底。
案例 2:复杂度轴主骨架 — docs/game-infra/access-gateway.md
参考:docs/game-infra/access-gateway.md
主骨架:沿"接入模式(PDU 五种) → 单实例接入网关 → 集群化:从'一对一绑死'到'网状路由'"的规模阶梯组织。每一层都以"上一层遇到什么无法解决的新问题"作为进入下一层的触发条件。
次轴介入:每一层的关键机制扎穿一处实现细节——FRAME 协议在单实例层解决"网关↔GameSvr 的内部契约"、START 握手与断线重连在会话层扎穿"连接可断,会话不断"、路由算法(random vs 一致性哈希)在集群层扎穿"拿到成员表后一个请求怎么选目标节点"。
为什么它成立:它服务的触发问题是"游戏接入网关从单机到大规模网状是怎么演进的",标准规模类。规模阶梯清晰、每层的失败信号(一对一绑死不够用了、成员表变化时路由要跟着变)明示。
若强行换轴(想象性反例):如果把 access-gateway 改成深度轴(沿"一次玩家登录到断线重连"的时间轴讲),它会失去"什么规模下需要引入网状路由"这条驱动逻辑;面试官问"你们从 1 个网关到 100 个网关时改了什么"时,答题者只能沿单次登录的深度链答,不知道横向规模迁移点在哪。
案例 3:决策矩阵轴主骨架 — k8s-stateful-ops-doc
参考:docs/game-infra/k8s-stateful-ops.md / spec:openspec/specs/k8s-stateful-ops-doc/spec.md
主骨架:以「编排层 × 业务层 × 计划 vs 故障」两轴构成对照矩阵:
| 计划内 | 故障 | |
|---|---|---|
| 业务态 | stateful-migration(快照 / WAL / 切流) | stateful-recovery(checkpoint + WAL 回放) |
| 编排层 | 防漂移(本文段落 A) | 节点崩溃恢复(本文段落 B) |
本文覆盖矩阵下半行的两格,与 stateful-migration / stateful-recovery 双向交叉链接不复述业务态。
次轴介入:每一格的关键机制扎穿理由——防漂移格里,nodeAffinity 硬约束 vs topologySpreadConstraints 拓扑约束扎穿"为什么 preferred 不够、必须 required";节点崩溃恢复格里,Taint-Based Eviction 时序、Fencing 三层(存储侧 / 电源侧 / API 侧)、NonGracefulShutdown 1.28 GA 各扎穿一层实现。
为什么它成立:它服务的触发问题是"K8s 有状态服务的编排层要覆盖哪几种情况",标准多维权衡类。矩阵维度显式命名("编排层 × 业务层 × 计划 vs 故障"),每格有具体实现案例,维度冲突时(例如"故障 × 编排层"下 StatefulSet 保守语义与 Force-Delete 的裁决)规则明示。
若强行换轴(想象性反例):如果把 k8s-stateful-ops 改成深度轴(沿"一个 Pod 从被调度到被驱逐再到重建"的时间轴讲),它会失去"计划 vs 故障"这一维的对照——读者只能沿一条故障链读完,但不知道计划态该怎么防漂移;如果改成复杂度轴("3 节点 K8s → 100 节点 → 1000 节点"),"编排层 × 业务层"这一维彻底丢失,业务态和编排层的边界模糊,Fencing 三层与业务态 checkpoint 的接续讲不清。
14 条落地检查清单
起草完专题后跑一次检查。每一条必须能给出通过 / 不通过二值结论,"部分通过 / 看情况"记作不通过。
深度轴主骨架(5 条)
复杂度轴主骨架(4 条)
决策矩阵轴主骨架(3 条)
通用(2 条)
用法:
- 作者:只跑主轴对应分组 + 通用 2 条(7~8 条)。深度轴专题跑 D1–D5 + G1–G2,复杂度轴专题跑 C1–C4 + G1–G2,决策矩阵轴专题跑 M1–M3 + G1–G2。
- Review 者:跑全部 14 条——因为 review 的意义之一是识别"作者以为自己在写 X 轴、实际长成 Y 轴"的偏移。
已知偏离
docs/common/database.md(数据库范式与存储引擎总纲)当前兼顾多轴,未严格按本 SOP 起草——它是 SOP 制定前的存量。未来若做叙事级重写,可回填 SOP 的检查清单。本次不改现有专题内容。docs/common/redis.md/docs/common/distributed-transaction.md等专题在轴选择上介于复杂度轴与决策矩阵轴之间,未被本 SOP 强制归类。
自查记录
拿 14 条清单对本 SOP 页自身做一次 review。本页天然是决策矩阵轴主骨架的样例——它围绕「读者场景 × 触发问题类型」两轴组织内容。跑 M1–M3 + G1–G2:
- ✅ M1:矩阵维度显式命名(
读者场景 × 触发问题类型,见"面试深追问场景下的默认映射"表) - ✅ M2:每格有可对应的实现案例(因果 → 200ms、规模 → access-gateway、多维 → k8s-stateful-ops)
- ✅ M3:维度冲突裁决明示(反自动机提示 + 落到实际决策场景)
- ✅ G1:适用边界明示读者场景("面试深追问抗压")
- ✅ G2:不适用边界明示("公开演讲 / 教学 / 内部技术分享")
内容来源
- 本 SOP 结论综合自本仓库三个专题的实际结构:
web-200ms-narrative/docs/game-infra/access-gateway.md/k8s-stateful-ops-doc。 - 详细讨论见
openspec/changes/depth-first-narrative-sop/:proposal.md/design.md/specs/*/spec.md/tasks.md。