# 附录 D 学习路线、能力矩阵与自测清单


> 本附录回答四个问题：**按什么顺序读**、**读到什么程度算懂**、**怎么验证自己懂了**、**面试现场会怎么被拆穿**。
> 与附录 A（参数速查）、附录 B（问题索引）、附录 C（术语对照）配合使用：附录 B 用来定位问题，本附录用来定位**自己**。

## D.1 三条阅读路线

### D.1.1 系统学习路线（7 周，每周 4~5 章）

本路线按八篇顺序推进，前置关系见 D.2。每周按 12~15 小时有效学习时间估算（含动手实验，不含通勤背诵）。

| 周次 | 覆盖章节 | 本周任务（可交付物） | 强度提示 |
|---|---|---|---|
| 第 1 周 | 第 1~5 章 | 手写延迟数量级表并脱离书本复述；用 `perf stat` 对同一段循环做 L1/L2/L3 命中率对比；推导一次 `T = 2^h ≈ N` 的树高估算；读 `/proc/[pid]/status` 的 `Threads`/`VmRSS` 并对照第 4 章 COW 解释差异；写一个 nice 值从 −5 到 +5 的进程用 `vruntime` 换算验证 CFS 权重 | 中等：第 3 章是方法论章，必须慢读 |
| 第 2 周 | 第 6~9 章 | 用 `strace -c` 统计一个 HTTP 服务的系统调用占比；写一个 ET 模式 `epoll` 的完整可运行程序并故意写成阻塞 fd 观察挂死；用 `sendfile` 与 `read`+`write` 各写一版文件转发并用 `perf` 对比；把死锁四条件的推导写成一页纸 | **最花时间**：第 6、7、8 章是全书三大硬骨头 |
| 第 3 周 | 第 10~14 章 | 造出 `D` 状态进程并说明 `kill -9` 无效的原因；用 cgroup v2 给一个进程组限 CPU 并观察 `cpu.stat`；在压测机跑一次 `iostat -x 1` 记录 `%util` 与 `await` 的背离；`du` 与 `df` 不一致的复现（删除被 `tail -f` 持有的文件） | 中等：第 11、12 章慢读，第 14 章可当速查跳读 |
| 第 4 周 | 第 15~19 章 | `tcpdump` 抓一次三次握手与一次四次挥手并逐字段标注；制造 `CLOSE_WAIT` 堆积并定位到应用未 `close`；用 `ss -ti` 读出 `cwnd`/`ssthresh`/`rtt` 三列并解释；`curl -w` 打印 `time_*` 全表定位一次慢请求；`dig +trace` 走完递归与迭代 | 中等偏难：第 17 章拥塞控制必须画图 |
| 第 5 周 | 第 20~23 章 | 用 `innodb_page_info` 或 `hexdump` 观察一个 16 KB 页；构造两阶段提交在三种崩溃时机下的恢复推演；自己搭主从并用 `SHOW REPLICA STATUS` 造出延迟；对一个 10 万行表做 `EXPLAIN` 并算 `key_len` | **最花时间**：第 21、22、23 章是数据库篇的支柱 |
| 第 6 周 | 第 24~27 章 | 用唯一索引与非唯一索引各跑一遍等值查询并打印 `SHOW ENGINE INNODB STATUS` 的锁信息；造一个死锁并读死锁日志；把深分页三种改写方案各跑一次对比 `rows`；读 `redis-cli OBJECT ENCODING` 观察编码转换阈值 | **最花时间**：第 24 章间隙锁、第 27 章一致性方案 |
| 第 7 周 | 第 28~36 章 | 用 `javap -c` 看 `monitorenter` 与 `try-with-resources` 字节码；用 `jol` 打印对象头并验证锁升级路径；-XX:+PrintGCDetails 对照第 32 章逐条读日志；用 `Math.random()` 制造一次 `ConcurrentModificationException`；按第 36 章框架完整口述一次秒杀设计并录音回放 | 偏快：第 28、29 章可快读，第 31、32、34、36 章慢读 |

按上面的任务量，7 周的学时分布大致如下（合计约 95 小时）：

| 分段 | 覆盖章节 | 建议学时 | 占比 | 特征 |
|---|---|---|---|---|
| 基础与并发前置 | 第 1~9 章 | 约 26 h | 27% | 机制密度最高，动手实验最多 |
| 观测与排查工具 | 第 10~14 章 | 约 12 h | 13% | 工具性内容，练手即可记住 |
| 网络与协议 | 第 15~19 章 | 约 16 h | 17% | 必须配抓包，纯读无效 |
| 数据库 | 第 20~27 章 | 约 22 h | 23% | 单篇占比最高，且追问最深 |
| Java/JVM/并发 | 第 28~32 章 | 约 13 h | 14% | 本科有基础，可压缩 |
| 分布式与设计 | 第 33~36 章 | 约 6 h | 6% | 依赖前文，最后收敛 |

**可以快读的章节**：第 2 章（能查手册的部分跳过，只保留对齐与伪共享）、第 14 章（纯速查，用一次真实日志统计练手即可）、第 28 章（本科 Java 已覆盖大半，只补常量池与桥方法）、第 29 章（只读 `HashMap` 与 `ConcurrentHashMap` 两节）。

**必须慢读的章节**：第 6、7、8 章（同步与 I/O 与内存）、第 17 章（拥塞控制）、第 21、22、24 章（日志、MVCC、加锁规则）、第 31、32、34 章（AQS、GC、共识）。这 11 章合计约占全书 40% 的阅读时间，也是面试追问密度最高的部分。

> [!TIP]
> 每周结束时不要重读正文，而是直接做 D.4 中对应篇章的自测题：**做不出来的题才是本周真正的欠账**，把它抄进一个"欠账清单"，下周开头先还。

### D.1.2 面试冲刺路线

**7 天版**（每天 6~8 小时，适合一周内有面试、已有本科基础）

| 天数 | 阅读章节 | 配合附录 | 当天必须完成的输出 |
|---|---|---|---|
| 第 1 天 | 第 1、3、4、5、6 章 | 附录 A 延迟数量级表 | 默写延迟表；口述 COW 三步；说出上下文切换开销构成 |
| 第 2 天 | 第 7、8、9、11、12 章 | 附录 B 第二、三篇索引 | 手画 epoll 红黑树+就绪链表；解释 `%util` 失真；说出 overcommit 三模式 |
| 第 3 天 | 第 15、16、17、18 章 | 附录 A TCP 参数表 | 画 `cwnd` 演化折线；说清 `TIME_WAIT` 2MSL 两条理由；TLS 1.2/1.3 时序对比 |
| 第 4 天 | 第 20、21、22、23 章 | 附录 B 第五篇索引 | 画 ReadView 判断流程；三种崩溃时机恢复推演；算一次三层 B+ 树容量 |
| 第 5 天 | 第 24、25、26、27 章 | 附录 A InnoDB 默认值 | 唯一/非唯一索引各推一遍加锁范围；深分页三方案；缓存一致性四方案取舍 |
| 第 6 天 | 第 30、31、32 章 | 附录 C 缩写表 | 画 AQS `state`+双向队列+条件队列图；三色标记漏标时序；线程池四步流程 |
| 第 7 天 | 第 33、34、36 章 + 全篇复盘 | 附录 D（本文件） | 完整口述一次系统设计并录音；把 D.4 中做错的题重做一遍 |

**3 天版**（每天 10~12 小时，只保高频与主干，放弃广度）

| 天数 | 阅读章节 | 配合附录 | 取舍说明 |
|---|---|---|---|
| 第 1 天 | 第 3、4、7、11、16、17 章 | 附录 A 全表 | 放弃计算机组成细节与第 2 章，只保"延迟量级 + COW + epoll + 四板斧 + TCP"这条面试最高频线 |
| 第 2 天 | 第 21、22、23、24 章 | 附录 A InnoDB 部分 + 附录 B 第五篇 | 数据库只保"日志—事务—索引—锁"四件套，放弃第 26 章分库分表细节（用一段话讲清路由与跨库问题即可） |
| 第 3 天 | 第 30、31、32、34、36 章 | 附录 C + 本文件 D.5 | JVM 与并发只保 JMM、线程池、AQS、GC 分代与三色标记；分布式只保 CAP 与 Raft；最后用 D.5 三套脚本各跑一遍 |

> [!WARNING]
> 冲刺路线最容易犯的错是"从第 1 章开始按顺序读到第 36 章"。基础篇（第 1、2 章）在短期冲刺里的单位时间收益最低 —— 它们的追问深度高但出现频率低于第 22、24、32 章。**时间不够时，先放弃顺序，优先放弃低频章。**

### D.1.3 按岗位定制路线

五类岗位的考点权重表。权重星级为 1~5 星，代表该主题在该岗位面试中的出现密度与追问深度。

**后端 / 基础架构方向**

| 主题 | 权重星级 | 必读章节 |
|---|---|---|
| TCP 与网络排障 | ★★★★★ | 第 16、17、19 章 |
| Linux 性能与内存 | ★★★★★ | 第 11、12、13 章 |
| 数据库事务与锁 | ★★★★☆ | 第 22、24、25 章 |
| JVM 与并发 | ★★★★☆ | 第 30、31、32 章 |
| 缓存与消息可靠性 | ★★★★☆ | 第 27、33 章 |
| 系统设计表达 | ★★★★☆ | 第 36 章 |
| 计算机组成与体系结构 | ★★☆☆☆ | 第 1、3 章 |

**数据库方向**

| 主题 | 权重星级 | 必读章节 |
|---|---|---|
| 索引原理与执行计划 | ★★★★★ | 第 23、25 章 |
| 事务、MVCC 与隔离级别 | ★★★★★ | 第 22 章 |
| 日志与两阶段提交 | ★★★★★ | 第 21 章 |
| 加锁规则与死锁 | ★★★★★ | 第 24 章 |
| 存储引擎与内存结构 | ★★★★☆ | 第 20 章 |
| 复制与高可用 | ★★★★☆ | 第 26 章 |
| 操作系统内存与块层 | ★★★☆☆ | 第 8、9、13 章 |

**中间件方向**

| 主题 | 权重星级 | 必读章节 |
|---|---|---|
| 消息可靠性三件套 | ★★★★★ | 第 33 章 |
| Redis 原理与缓存架构 | ★★★★★ | 第 27 章 |
| 网络协议栈与零拷贝 | ★★★★☆ | 第 7、15、16、17 章 |
| 并发工具与 AQS | ★★★★☆ | 第 30、31 章 |
| 分布式一致性与共识 | ★★★★☆ | 第 34 章 |
| 调度与 CPU 亲和 | ★★★☆☆ | 第 5 章 |
| 中断与块层 | ★★★☆☆ | 第 9、13 章 |

**大数据方向**

| 主题 | 权重星级 | 必读章节 |
|---|---|---|
| 磁盘 I/O 与吞吐口径 | ★★★★★ | 第 9、13 章 |
| 内存管理、page cache 与 OOM | ★★★★★ | 第 8、12 章 |
| 顺序写与日志结构 | ★★★★☆ | 第 21、33 章 |
| 分布式一致性与分区 | ★★★★☆ | 第 34 章 |
| 并发与线程模型 | ★★★★☆ | 第 5、31 章 |
| 容量估算 | ★★★★☆ | 第 3、36 章 |
| 网络传输与拥塞控制 | ★★★☆☆ | 第 17 章 |

**云原生方向**

| 主题 | 权重星级 | 必读章节 |
|---|---|---|
| namespace 与 cgroup 隔离 | ★★★★★ | 第 10 章 |
| 内存限额与 OOM 行为 | ★★★★★ | 第 12 章 |
| HTTP 与 HTTPS、网关 | ★★★★☆ | 第 18、35 章 |
| 进程模型与信号 | ★★★★☆ | 第 4、10 章 |
| 网络与 DNS、服务发现 | ★★★★☆ | 第 19、35 章 |
| 可观测性与性能四板斧 | ★★★★☆ | 第 11、14 章 |
| 消息与分布式一致性 | ★★★☆☆ | 第 33、34 章 |

## D.2 全书依赖关系图

```text
                        ┌──────────────────────────────────────────────┐
                        │ 第一篇 计算机组成与体系结构（第 1~3 章）      │
                        │ 延迟量级 · 流水线与缓存 · 性能方法论          │
                        └───────────────┬──────────────────────────────┘
                                        │ 提供"所有性能判断的量纲"
              ┌─────────────────────────┼───────────────────────────┐
              ▼                         ▼                           ▼
   ┌──────────────────────┐  ┌──────────────────────┐  ┌──────────────────────┐
   │ 第二篇 操作系统       │  │ 第四篇 计算机网络     │  │ 第三篇 Linux         │
   │（第 4~9 章）         │  │（第 15~19 章）       │  │（第 10~14 章）       │
   │ 进程/COW · 调度 · 锁  │  │ 分层 · TCP · HTTP    │  │ 观测工具与内核参数    │
   │ 内存分页 · 中断/块层  │  │ DNS/CDN · 抓包       │  │ 需第 8/9 章做解释底座 │
   └───────┬──────────────┘  └──────────┬───────────┘  └──────────┬───────────┘
           │                            │                          │
           │ 提供"线程/内存/可见性模型"  │ 提供"请求路径"            │ 提供"怎么看到"
           ▼                            ▼                          ▼
   ┌──────────────────────┐  ┌──────────────────────┐  ┌──────────────────────┐
   │ 第六篇 Java/JVM/并发  │  │ 第五篇 数据库         │  │ 第七篇 MQ/分布式/微服务│
   │（第 28~32 章）       │  │（第 20~27 章）       │  │（第 33~35 章）       │
   │ JMM · 线程池/AQS · GC │  │ 日志 · MVCC · 索引   │  │ 可靠性 · 共识 · 治理  │
   └───────────┬──────────┘  └──────────┬───────────┘  └──────────┬───────────┘
               └──────────────┬─────────┴─────────────────────────┘
                              ▼
              ┌──────────────────────────────────────────────┐
              │ 第八篇 场景设计与面试复盘（第 36 章）          │
              │ 容量估算 · 秒杀 · 短链 · 排行榜 · 沟通节奏    │
              │ 依赖前面几乎全部结论，是全书唯一的收敛点       │
              └──────────────────────────────────────────────┘
```

**三条主干依赖链**

1. **第 1~3 章（组成原理）→ 第 4~9 章（操作系统）→ 第 10~14 章（Linux）→ 第 15~19 章（网络）**：这条链是"自上而下的机制 → 自下而上的观测"——组成原理给出延迟量纲，操作系统解释机制为什么这么设计，Linux 篇把这些机制变成可观测指标，网络篇再把请求路径叠加上去；读反了顺序，第 11 章的四板斧就只是背指标。
2. **第 20~27 章（数据库）依赖第 4 章 COW、第 8 章内存、第 21 章日志**：InnoDB 的 buffer pool 命中率与淘汰、undo 版本链占内存的方式、redo 的顺序写与 `fsync` 代价，都必须落到"页/内存/磁盘"这套语汇上；第 21 章日志则是第 22 章 MVCC 与第 26 章复制的共同前置。
3. **第 28~32 章（Java/JVM/并发）依赖第 4~6 章（进程线程、调度、同步）**：JMM 的内存屏障是第 6 章硬件可见性的语言级重述，AQS 的排队与唤醒是第 5 章调度语义在用户态的复刻，GC 的标记与并发收集器是对第 6 章同步原语的极限使用；跳过第二篇直接背 AQS，会在"为什么需要 `state` 而不是一把锁"上卡死。

> [!IMPORTANT]
> 第 33~36 章（分布式与场景设计）依赖前面几乎全部：第 33 章的幂等依赖第 31 章的原语与第 24 章的锁、第 34 章的 Raft 依赖第 17 章的"丢包即拥塞"式权衡思维、第 36 章的容量估算依赖第 3 章与第 12 章。**做不出设计题，通常不是设计题不会，而是某一层前置塌了。**

### D.2.1 三条依赖链的"跳过代价"

依赖链不是阅读顺序建议，而是**因果链**：后一环的解释力来自前一环的机制。下表说明跳过中间某一环时具体会塌在哪里。

| 主干链 | 依赖的具体机制（用一句话解释该链） | 跳过后最先塌掉的问题 |
|---|---|---|
| 第 1~3 章 → 第 4~9 章 → 第 10~14 章 → 第 15~19 章 | 组成原理给出延迟量纲，操作系统解释机制为何如此设计，Linux 篇把机制变成可观测指标，网络篇把请求路径叠加上去 | 第 11 章的四板斧退化为背指标；被问"`wa` 高说明什么"只能答"磁盘忙" |
| 第 20~27 章 ← 第 4 章 COW、第 8 章内存、第 21 章日志 | InnoDB 的页、buffer pool、undo 版本链与 redo 顺序写，全都建立在分页、内存回收与日志顺序写这三套语汇之上 | 第 22 章 MVCC 变成背 `m_ids`；被问"长事务为什么危险"答不出 purge 与版本链 |
| 第 28~32 章 ← 第 4~6 章（进程线程、调度、同步） | JMM 的屏障是硬件可见性的语言级重述，AQS 的排队唤醒是调度语义在用户态的复刻，GC 并发标记是对同步原语的极限使用 | 第 31 章 AQS 变成背双向队列；被问"为什么需要 `state`"答不出资源计数与条件等待的分工 |

### D.2.2 按"故障现象"定位欠账章节

依赖图还有一个用法：把线上现象或面试卡点反向映射到**最该补的那一章**。下表左侧是现象，右侧是根因所在章节。

| 观察到的现象或卡点 | 根因所在章节 | 说明 |
|---|---|---|
| 高平均负载但 CPU 使用率不高 | 第 11、12 章 | 先分清可运行与不可中断两类任务，再看存储与内存换页 |
| 接口均值正常而 P99 长期偏高 | 第 3、31 章 | 先排除尾延迟放大，再查线程池排队与队列积压 |
| 服务端大量 `CLOSE_WAIT` | 第 16 章 | 是本端未关闭，属于代码缺陷而非网络问题 |
| 连接数上不去、握手被丢弃 | 第 16、10 章 | 半连接与全连接队列、`somaxconn` 与文件描述符限制叠加 |
| 磁盘写入延迟抖动大、业务周期性卡顿 | 第 12、13 章 | 脏页回刷与 `dirty_ratio` 造成的批量写，而非磁盘本身坏 |
| 同一 SQL 有时走索引有时全表扫 | 第 20、23 章 | 统计信息偏差与代价估算，而非索引设计错误 |
| 事务里两次读结果不同却以为在读已提交 | 第 22 章 | ReadView 创建时机决定可见性，需先确认隔离级别 |
| 加了一条索引反而出现更多锁等待 | 第 24 章 | 加锁范围由索引形态决定，唯一与非唯一索引差别很大 |
| 消息消费偶发重复处理导致资金错账 | 第 33、31 章 | 幂等键缺失，且缺少状态机或唯一约束的原语保证 |
| 缓存与数据库长期不一致且延迟双删无效 | 第 27 章 | 需要按读写路径选择方案，而不是叠加删除动作 |
| 容器内进程被随机杀死但宿主内存充足 | 第 12、10 章 | cgroup 内存限额下的组内 OOM，而非宿主 OOM |
| 设计题一被追问规模就答不下去 | 第 3、36 章 | 容量估算与假设表达缺失，与架构选型无关 |

## D.3 能力矩阵

行是能力项，列是档位。单元格写的是**可验证标准**——能通过"做一遍给同事看"来判定的动作或输出，而不是感受。

| 能力项 | 初级 | 中级 | 高级 |
|---|---|---|---|
| 内存与性能排查 | 能读出 `free`/`vmstat` 关键列并说出含义 | 能区分 page cache 与匿名内存，从 `smaps` 定位增长段并给出回收动作 | 能在 cgroup 限额下判断 OOM 归属，用 `slabtop`+`/proc/pagetypeinfo` 定位碎片与泄漏并给出长期方案 |
| TCP 抓包与排障 | 能用 `tcpdump` 抓到一次握手并读出端口与标志位 | 能从抓包中识别重传、零窗口、`RST` 并对应到第 17 章机制 | 能用 `ss -ti` 读 `cwnd`/`rtt`/`retrans` 推断拥塞状态，区分应用侧慢与网络侧慢 |
| SQL 与索引优化 | 能读懂 `EXPLAIN` 的 `type`/`key`/`rows` | 能算 `key_len`、识别 `filesort` 与 `Using index`，按选择性重排联合索引列序 | 能在 `EXPLAIN ANALYZE` 给出的估算偏差上推断统计信息与优化器选择错因，并给出改写方案 |
| 事务与锁问题定位 | 能说出四种隔离级别与对应异常 | 能用 ReadView 判断某条读该看见哪个版本 | 能从死锁日志还原加锁顺序，改写业务顺序或调索引消除间隙锁冲突 |
| JVM 调优 | 能说出堆分区与 JDK 默认 GC | 能读 GC 日志判断是晋升失败还是并发模式失败，并调 `SurvivorRatio`/`MaxTenuringThreshold` | 能按停顿目标在 G1/ZGC 间取舍，用 `-XX:+PrintAdaptiveSizePolicy` 定位自适应参数抖动 |
| 并发正确性 | 能说出 `volatile` 与 `synchronized` 的差别 | 能用 `happens-before` 判断一段代码是否有可见性问题 | 能证明一段无锁代码的正确性，或指出其 ABA、伪共享、内存序缺陷并给出屏障方案 |
| 缓存设计 | 能说出穿透/击穿/雪崩的含义 | 能按业务给出 key 结构、过期策略与一致性方案取舍 | 能给出多级缓存（本地+分布式）失效顺序、热 key 打散与降级兜底的完整方案 |
| 消息可靠性设计 | 能说出消息丢失的三个环节 | 能为每个环节给出确认与刷盘配置，并设计幂等键 | 能在顺序、重复、积压、事务消息四个约束同时存在时给出可运行的方案与代价 |
| 分布式一致性取舍 | 能说出 CAP 与 BASE | 能按业务区分线性一致与最终一致，选出 2PC/TCC/Saga 中合适的一种 | 能基于 Raft 机制解释成员变更与网络分区下的正确性边界，并说明本地消息表为何能收敛 |
| 容量估算 | 能按 DAU 估算 QPS 量级 | 能算出存储容量与带宽，并给出机器数与其假设 | 能同时给出峰值系数、读写比、缓存命中率三条假设，并说明假设错了系统怎么退化 |
| 系统设计表达 | 能按"需求→接口→存储"顺序讲完一题 | 能主动澄清歧义并给出量化约束，画清核心流程 | 能主动暴露瓶颈与取舍，被追问三层仍能回到同一套假设上作答 |
| 源码阅读 | 能按类名找到 `HashMap` 的 `putVal` | 能定位 `ThreadPoolExecutor.execute`、`ReentrantLock.lock` 等关键路径并说清分支 | 能沿 InnoDB `lock_rec_lock`、HotSpot `CollectedHeap::mem_allocate`、Raft `maybeCommit` 追踪跨文件调用链 |
| 压测与基准测试 | 能跑 `wrk`/`ab` 并读出 QPS 与 P99 | 能识别预热、坐标轴、均值掩盖长尾三类陷阱并设计对照实验 | 能设计可复现的基准（固定 CPU 频率、关闭超线程对照、客户端不成为瓶颈）并给出置信区间 |
| 故障复盘 | 能按时间线还原现象 | 能区分触发因素与根本原因，给出可验证的改进项 | 能从单次事故抽象出该类故障的检测信号与降级开关，并推动落到监控告警 |
| 日志与可观测性 | 能按关键字在日志里定位一次报错 | 能设计带 `TraceID` 的日志并串起一次跨服务调用 | 能按 RED/USE 方法补齐缺失指标，说明每个仪表盘对应的决策动作 |
| 锁与同步原语选型 | 能说出自旋锁与互斥锁的差别 | 能按临界区长度与竞争度选择原语，并说明自旋的代价 | 能用 `RCU`/原子计数/无锁队列替换热点锁，并给出内存回收期的安全性论证 |
| 文件系统与 I/O 路径 | 能区分 buffered I/O 与直接 I/O | 能解释 page cache 命中率与脏页回刷对尾延迟的影响 | 能按顺序/随机与队列深度设计 `fio` 实验，结合块层与调度器给出选型结论 |
| 网络协议选型 | 能说出 HTTP/1.1 与 HTTP/2 的主要差异 | 能解释 TCP 层队头阻塞为何 HTTP/2 无法解决，HTTP/3 用什么机制绕过 | 能按首字节时间、连接复用、0-RTT 风险给出协议升级的实际收益边界 |
| 版本与默认值意识 | 能说出 MySQL 默认隔离级别与 JDK 默认 GC | 能区分 MySQL 5.7 与 8.0、JDK 8 与 17 在参数与实现上的差异 | 能把一个现象的结论限定在具体版本与参数区间内，并说明越界后结论怎么变 |

### D.3.1 怎么用这张矩阵

矩阵的用法不是"逐项打分求平均"，而是**找短板行**。自我评估分三步：

| 步骤 | 动作 | 判定规则 |
|---|---|---|
| 第一步：定位（约 30 分钟） | 逐行问自己"这一行的中级标准，我能不能当场做出来给同事看"，只回答能或不能 | 会犹豫的行全部记为短板，不要用"大概会"自我安慰 |
| 第二步：取证（每行约 1 小时） | 对每个短板行，实际做一次该单元格描述的动作（跑一次 `fio`、读一次死锁日志、写一次容量算式） | 做不出来就是短板确认；做得出来说明是"自评偏低"，划掉该行 |
| 第三步：排序（约 15 分钟） | 按"对口岗位权重 × 短板严重度"排序，只保留前 3 行作为近期投入方向 | 超过 3 行就无法在一周内推进，等于没有目标 |

各档位的判定阈值可以参考下表，避免"感觉自己在中级"这类模糊结论：

| 档位 | 判定阈值（可验证） | 常见误判 |
|---|---|---|
| 初级达标 | 15 个能力项中至少 10 项能独立完成初级标准，且能说出每项对应的观测命令或参数 | 把"听过这个名词"当成初级达标 |
| 中级达标 | 至少 8 项达到中级标准，且其中必须包含"内存与性能排查""SQL 与索引优化""并发正确性"三项 | 只在最熟悉的一项上很深，其他项全靠背诵 |
| 高级达标 | 至少 5 项达到高级标准，且能指出自己高级标准中的**不成立边界**（如某结论只在特定版本或参数区间成立） | 把"能背出源码类名"当成高级，却说不出该类的调用条件 |

> [!NOTE]
> 矩阵中"源码阅读"一项的档次差异最能反映真实水平：初级是按类名搜索，中级是能读关键分支，高级是能沿跨文件调用链追下去。面试中追问"这个方法的下一步在哪"时，只有高级档能继续回答。

## D.4 150 条自测清单

自测题不是名词解释，而是**能区分"背过"与"懂了"的判断、计算、推导题**。通过标准写的是"答到什么程度算过关"。

### D.4.1 第一篇 计算机组成与体系结构（第 1~3 章，18 条）

| # | 自测题 | 章节 | 通过标准 |
|---|---|---|---|
| 1 | 主存访问约 100 ns、L1 命中约 1 ns，这个 100 倍差距在程序里靠什么被掩盖掉大部分 | 第 1 章 | 能说出局部性原理如何让命中率主导平均访问时间，并给出含命中率的平均延迟估算式 |
| 2 | 数组按行遍历与按列遍历，在 C 的二维数组上性能差几倍，为什么 | 第 1 章 | 能指出空间局部性 + 缓存行（cache line）粒度，并说明行优先布局下缓存行被完整利用 |
| 3 | 分支预测失败为什么要损失约 5 ns 而不是 1 个周期 | 第 1 章 | 能说出流水线深度与冲刷代价的关系，指出失败代价随流水线级数增加 |
| 4 | 乱序执行没有改变程序的可见结果，靠的是什么约束 | 第 1 章 | 能说出寄存器重命名与重排序缓冲，并指出它只在单核内保证，跨核需内存屏障 |
| 5 | Spectre 与 Meltdown 的共同根因是什么，为什么补丁会带来性能损失 | 第 1 章 | 能指出推测执行的副作用可被观测，且提到缓解手段（如隔离页表）导致 TLB 刷新增多 |
| 6 | 为什么 `T = 2^h ≈ N` 可以用来估树高，它的前提是什么 | 第 1 章 | 能说明分支因子、节点容量与"每层能容纳的键数"，并指出前提是节点近乎填满 |
| 7 | 同一个二进制在 NUMA 机器上性能不稳定，你会先看什么 | 第 1 章 | 能说出跨节点访存延迟差与进程/线程绑定，提到 `numactl` 或调度亲和 |
| 8 | 结构体成员顺序改变导致大小变化，规则是什么 | 第 2 章 | 能说出对齐要求与填充字节，举出把一个 `char` 从中间移到末尾可减少填充 |
| 9 | 两个线程各自频繁更新相邻的两个计数器，吞吐反而下降，原因是什么 | 第 2 章 | 能说出伪共享（false sharing）与缓存行失效，给出填充或按线程分离的解法 |
| 10 | PLT/GOT 的延迟绑定省了什么，又付出了什么 | 第 2 章 | 能说明首次调用时解析符号以缩短启动时间，代价是首次调用变慢且引入可写表项风险 |
| 11 | 为什么 `fork` 之后立即 `exec` 的进程实际很少真的复制内存 | 第 2 章 | 能指出 COW 只标记页表为只读，并说明这与第 4 章机制的衔接 |
| 12 | 一次"页面不可用"的缺页与一次 TLB 未命中，代价差多少量级 | 第 2 章 | 能给出 TLB 命中约几十纳秒、缺页约微秒到毫秒级，并说明差异来源是磁盘与内核路径 |
| 13 | 一个接口 P99 是 200 ms、均值是 20 ms，你如何判断问题在下游还是自身 | 第 3 章 | 能提出按调用链分解、看下游 P99 与自身排队时间，指出尾延迟放大可能来自扇出 |
| 14 | 用 Little 定律解释：并发 100、单请求耗时 50 ms 时 QPS 上限是多少 | 第 3 章 | 能写出 `L = λ × W` 并算出约 2000 QPS，且说明该式成立的前提是系统进入稳态 |
| 15 | Amdahl 定律说把 10% 的部分优化到无限快，总加速比上限是多少 | 第 3 章 | 能算出约 1.11 倍，并说明串行部分决定上限，进一步引出 Gustafson 的规模视角 |
| 16 | 基准测试里"预热"为什么不是仪式，不做会错在哪里 | 第 3 章 | 能指出 JIT 编译、缓存与连接池填充、页表与内存分配器预热都会使前段数据不代表稳态 |
| 17 | 只报均值为什么危险，你会要求补什么指标 | 第 3 章 | 能说出均值掩盖长尾，要求 P95/P99/P999 与直方图，并能解释 P999 在扇出场景的意义 |
| 18 | USE 方法与 RED 方法分别用于什么场景，指标怎么对应 | 第 3 章 | 能说出 USE 面向资源（使用率/饱和度/错误）、RED 面向服务（速率/错误/时长），并各举两个指标 |

### D.4.2 第二篇 操作系统（第 4~9 章，24 条）

| # | 自测题 | 章节 | 通过标准 |
|---|---|---|---|
| 19 | COW 省内存的完整三步是什么，页表在这三步里各是什么状态 | 第 4 章 | 能画出父子共享物理页且页表只读，缺页时复制并改回可写，写清引用计数的变化 |
| 20 | `vfork` 与 `fork` 的区别不只是"快"，它换来了什么约束 | 第 4 章 | 能说出子进程共享父进程地址空间、父进程被挂起，且只允许 `exec` 或 `_exit` |
| 21 | 一个进程的虚拟内存从几十 MB 变成几 GB，但 RSS 没变，可能发生了什么 | 第 4 章 | 能区分 `VSZ` 与 `RSS`，指出 `mmap` 预留或 `malloc` 大块后未触碰页面 |
| 22 | 僵尸进程与孤儿进程分别在什么时机产生，谁负责回收 | 第 4 章 | 能说出退出后父进程未 `wait` 与父进程先退出两种情形，以及 init/1 号进程接管 |
| 23 | CFS 为什么用 `vruntime` 而不是直接按优先级分时间片 | 第 4 章 | 能说明 `vruntime` 累积使调度与"已得 CPU 时间"成正比，权重差异自然体现为推进速度差异 |
| 24 | nice 值差 1 级，权重差多少，时间片差多少 | 第 5 章 | 能给出 nice→weight 的换算关系与具体算例，说明权重比决定 CPU 份额比 |
| 25 | 红黑树在 CFS 里用来解决什么，用最小堆不行吗 | 第 5 章 | 能说出需要"取最小 `vruntime`"与"删除任意节点后重插入"两种操作，红黑树的删除+插入代价可接受 |
| 26 | 上下文切换 1~5 μs 的开销由哪几部分构成 | 第 5 章 | 能至少说出寄存器保存、地址空间切换导致 TLB 失效、缓存污染三部分，并给出量级 |
| 27 | `SCHED_FIFO` 与 `SCHED_RR` 的区别是什么，误用会有什么后果 | 第 5 章 | 能说出 FIFO 不轮转而 RR 有时间片，指出实时线程会饿死普通线程 |
| 28 | 为什么线程数超过物理核数后，CPU 密集型任务反而变慢 | 第 5 章 | 能指出切换开销与缓存失效，并提到负载均衡导致的热点迁移代价 |
| 29 | 死锁四个必要条件同时满足，为什么仍可能不死锁 | 第 6 章 | 能举出单线程或不存在循环等待的实际例子，说明必要条件不等价于充分条件 |
| 30 | 自旋锁在什么条件下优于互斥锁，什么时候是灾难 | 第 6 章 | 能说出临界区极短且竞争者可运行（多核）时占优，单核或长时间持有时浪费 CPU |
| 31 | `lock cmpxchg` 与普通 `cmpxchg` 的差别是什么 | 第 6 章 | 能说出前缀使其成为原子指令并隐含全屏障语义，指出代价是缓存行独占 |
| 32 | 为什么提升锁粒度有时会降低吞吐，颗粒度该怎么选 | 第 6 章 | 能说出锁开销与并发度之间的权衡，给出按访问模式拆锁或分段锁的判断依据 |
| 33 | 一次 `write` 到文件的调用路径上，哪些步骤可能阻塞 | 第 7 章 | 能说出 page cache 写入、脏页回刷、块层排队与设备完成，指出 buffered 写通常不阻塞到落盘 |
| 34 | `fork` 之后子进程的文件偏移量与父进程共享吗 | 第 7 章 | 能指出共享的是打开文件表项，因此共享偏移量，而 `dup` 同样共享、独立 `open` 不共享 |
| 35 | 硬链接与软链接在 inode 层面的差别是什么，删除原文件后各是什么状态 | 第 7 章 | 能说出硬链接共享 inode 且计数减一，软链接是独立文件指向路径，目标删除后悬空 |
| 36 | `epoll` 比 `select` 快的根本原因是什么，不只是"没有轮询" | 第 7 章 | 能说出 fd 一次注册进红黑树、就绪时回调入就绪链表，返回的是就绪集合而非全量扫描 |
| 37 | ET 模式为什么必须配非阻塞 fd | 第 7 章 | 能说出 ET 只在状态变化时通知一次，若不读到 `EAGAIN` 会永久丢事件，阻塞读会卡在最后一次读上 |
| 38 | 传统 `read`+`write` 转发文件有几次数据拷贝，零拷贝省掉了哪几次 | 第 7 章 | 能写出 4 次拷贝与 2 次 DMA 参与，说出 `sendfile` 让数据不出内核、`splice` 用管道页 |
| 39 | `%util` 到 100% 代表磁盘已满负荷吗 | 第 11 章 | 能说出它统计的是设备有 I/O 在进行的采样时间占比，给出并发 I/O 与 RAID 下失真的反例，并改用 `aqu-sz`/`await` |
| 40 | 缺页有哪四种类型，各自的处理路径差别在哪 | 第 8 章 | 能区分主缺页、次缺页、写时复制缺页、保护违例，并说明哪些不需要读磁盘 |
| 41 | LRU 在真实硬件上为什么只能近似，Clock 算法怎么近似 | 第 8 章 | 能说出硬件不记录每页访问序，用访问位 + 指针扫描来近似，指出其不抗顺序扫描 |
| 42 | `malloc` 什么时候用 `brk`、什么时候用 `mmap`，为什么有阈值 | 第 8 章 | 能给出约 128 KB 的阈值口径，说明小分配用堆顶扩展、大分配用 `mmap` 便于直接归还 |

### D.4.3 第三篇 Linux（第 10~14 章，21 条）

| # | 自测题 | 章节 | 通过标准 |
|---|---|---|---|
| 43 | 平均负载的准确含义包含哪两类任务，高平均负载但 CPU 空闲说明什么 | 第 11 章 | 能说出可运行 + 不可中断睡眠两类，并指出可能是磁盘 I/O 或 NFS 等不可中断等待 |
| 44 | CPU 使用率里 `wa` 高的两种原因是什么，怎么区分 | 第 11 章 | 能区分应用大量写导致脏页回刷与后端存储变慢，并给出用 `iostat`/`sar` 交叉验证的方法 |
| 45 | `us` 高与 `sy` 高分别指向什么问题，`sy` 高的常见来源有哪些 | 第 11 章 | 能说出系统调用与中断处理，提到上下文切换、锁竞争、频繁小 I/O 三类来源 |
| 46 | `free` 里 `available` 与 `free` 差在哪里，为什么不该看 `free` | 第 11 章 | 能说出 `available` 扣除了不可回收的 page cache 与 slab，并能说明可回收部分的估计方式 |
| 47 | `iostat` 的 `await` 与 `%util` 冲突时你信哪个，为什么 | 第 11 章 | 能选择 `await` 与 `aqu-sz`，并说明 `%util` 在并发与设备聚合下失真 |
| 48 | 造一个 `D` 状态进程，说明 `kill -9` 为什么杀不掉它 | 第 10 章 | 能指出 `D` 是不可中断睡眠，信号要等返回用户态才处理，并给出常见的 I/O 阻塞成因 |
| 49 | `SIGCHLD` 处理里最容易犯的错是什么 | 第 10 章 | 能说出信号不排队、多个子进程同时退出只收到一次，需要在循环里 `waitpid(-1, WNOHANG)` |
| 50 | `ulimit -n` 改大后程序仍报 `Too many open files`，还差什么 | 第 10 章 | 能指出硬限制、进程已启动未生效、systemd 的 `LimitNOFILE` 与 `fs.file-max` 多个层次 |
| 51 | cgroup v2 限制 CPU 用哪个文件，`cpu.max` 的两个数各是什么 | 第 10 章 | 能说出配额与周期，并说明超限后的节流表现会体现在 `cpu.stat` 的 `nr_throttled` |
| 52 | namespace 提供了隔离，但没有提供什么 | 第 10 章 | 能指出资源额度限制由 cgroup 负责，namespace 只做视图隔离 |
| 53 | 一个进程 RSS 持续增长但 `pmap` 显示是同一段地址在涨，最可能是哪类泄漏 | 第 12 章 | 能区分堆泄漏与线程栈/映射文件泄漏，提出用 `smaps` 按段对比两次快照 |
| 54 | `vm.overcommit_memory` 为 0 时 `malloc` 成功代表内存已可用吗 | 第 12 章 | 能指出只是预留虚拟地址，实际写入时才分配，并说明这种行为在 fork 场景下的风险 |
| 55 | OOM killer 选谁下手，`oom_score` 受什么影响 | 第 12 章 | 能说出按内存占用与 `oom_score_adj` 计算，指出容器内首选大占用进程而不是"最坏"进程 |
| 56 | 容器内存超限被杀，`dmesg` 里能看到什么，和宿主 OOM 有何不同 | 第 12 章 | 能说出 cgroup 级 OOM 会打印带 cgroup 信息的记录，宿主 OOM 影响面更大 |
| 57 | swap 开了以后延迟反而变差，`swappiness` 该怎么设 | 第 12 章 | 能说明换出换入的代价量级（磁盘级）与延迟敏感服务倾向于低值甚至关闭，但需留余量避免 OOM |
| 58 | `du` 与 `df` 结果不一致的最常见原因 | 第 13 章 | 能说出文件已删除但仍被进程持有，用 `lsof +L1` 定位 |
| 59 | `df -i` 报满但空间还有，怎么处理 | 第 13 章 | 能说出 inode 耗尽与小文件过多的关系，指出清理方向与 ext4/xfs 在 inode 分配上的差异 |
| 60 | RAID 5 的写惩罚为什么是 4，这对随机写意味着什么 | 第 13 章 | 能推导读旧数据+读校验+写数据+写校验四次 I/O，指出随机写吞吐约为裸盘 1/4 |
| 61 | 用 `fio` 测 IOPS 时，`iodepth`、`bs`、`rw` 三个参数怎么设才可信 | 第 13 章 | 能说明随机小 IO 配深队列、顺序大 IO 配浅队列，并指出必须报告参数否则数字无意义 |
| 62 | 统计日志 TOP10 IP，`sort | uniq -c | sort -rn | head` 里最容易错的一步是什么 | 第 14 章 | 能指出 `uniq` 只合并相邻行必须先 `sort`，并说明大文件下 `LC_ALL=C` 与流式处理的取舍 |
| 63 | `find ... -exec` 与 `xargs` 在特殊字符文件名上的差异 | 第 14 章 | 能说出用 `-print0` 配 `xargs -0`，并指出 `-exec {} +` 的批处理优势 |

### D.4.4 第四篇 计算机网络（第 15~19 章，21 条）

| # | 自测题 | 章节 | 通过标准 |
|---|---|---|---|
| 64 | 分片发生在哪一层、分段发生在哪一层，搞错的后果是什么 | 第 15 章 | 能说出 TCP 分段在传输层、IP 分片在网络层，指出任一分片丢失会导致整个报文重传 |
| 65 | 一次 HTTP 请求从应用到对端应用，封装解封装各层加了什么 | 第 15 章 | 能按应用→传输→网络→链路逐层说出头部与目标地址，指出交换机与路由器处理到哪一层 |
| 66 | MSS 与 MTU 的关系是什么，MSS 由谁协商 | 第 15 章 | 能说出 MSS 约等于 MTU 减去 IP 与 TCP 头，在握手时用选项通告 |
| 67 | BDP 是什么，它对窗口大小和缓冲区意味着什么 | 第 15 章 | 能写出 `BDP = 带宽 × RTT`，给出算例并指出窗口小于 BDP 时吞吐受限 |
| 68 | 三次握手第三步能不能带数据，为什么 | 第 16 章 | 能说出可以带（应用层数据随 ACK 发出），但服务端此时可能仍在 SYN 队列，指出常见实现限制 |
| 69 | SYN 队列与 accept 队列分别解决什么，`somaxconn` 影响哪一个 | 第 16 章 | 能区分半连接与全连接队列，指出 `somaxconn` 与 `tcp_max_syn_backlog` 各管一个，并说明溢出后的丢包或截断行为 |
| 70 | `TIME_WAIT` 为什么要等 2MSL，不等的两条后果分别是什么 | 第 16 章 | 能说出保证最后 ACK 可重发使旧连接彻底消失，以及防止旧连接的迟到报文污染新连接 |
| 71 | 服务端大量 `TIME_WAIT` 与服务端大量 `CLOSE_WAIT` 是同一类问题吗 | 第 16 章 | 能指出前者通常是主动关闭方的正常现象（或用长连接缓解），后者是本端未调用 `close` 的代码缺陷 |
| 72 | `SO_REUSEADDR` 与 `SO_REUSEPORT` 各解决什么问题 | 第 16 章 | 能说出前者允许绑定处于 `TIME_WAIT` 的地址，后者允许多进程/线程绑定同一端口做内核级负载均衡 |
| 73 | RTO 的计算为什么要用平滑而不是最近一次 RTT | 第 17 章 | 能说出 `SRTT` 与 `RTTVAR` 的平滑与偏差项，指出直接用瞬时值会因抖动频繁误重传 |
| 74 | 快速重传为什么要三个重复 ACK，两个不行吗 | 第 17 章 | 能说出是乱序与丢包的权衡，指出阈值越小越容易把乱序误判为丢包 |
| 75 | 零窗口探测解决什么问题，没有它会死锁在哪一步 | 第 17 章 | 能说出接收方窗口为 0 后发送方停止发送，窗口更新报文丢失则双方互等，靠探测定时器打破 |
| 76 | Nagle 算法与延迟 ACK 为什么会互相伤害 | 第 17 章 | 能说出小包等待更多数据与 ACK 等待更多报文形成等待环，给出关闭 Nagle 或调 `TCP_QUICKACK` 的解法 |
| 77 | 请画出 `cwnd` 从慢启动到快恢复的完整演化折线并标注 `ssthresh` 的两处变化 | 第 17 章 | 能标出指数增长、阈值处转线性、三重复 ACK 时减半并进入快恢复，说出超时与快重传时阈值取值的差异 |
| 78 | 为什么丢包被当作拥塞信号，这个假设在什么链路上不成立 | 第 17 章 | 能说出有线链路丢包多因缓冲溢出，指出无线链路误码丢包会让 Reno 类算法误降速，引到 BBR 的思路 |
| 79 | HTTP/2 多路复用后，为什么还会出现队头阻塞 | 第 18 章 | 能指出 TCP 是有序字节流，一个段丢失会阻塞该连接上所有流，这是 TCP 层队头阻塞 |
| 80 | HTTP/3 用 QUIC 换掉了什么，0-RTT 的风险是什么 | 第 18 章 | 能说出基于 UDP 在用户态实现可靠传输与流级独立，0-RTT 数据可被重放攻击 |
| 81 | TLS 1.3 为什么只要 1-RTT，省掉的往返是什么 | 第 18 章 | 能说出密钥交换与认证合并、预共享密钥（PSK）与会话复用，指出 1.2 的两次往返在何处 |
| 82 | 301/302/307/308 在方法保持上的差别是什么，为什么 302 曾被当成 303 用 | 第 18 章 | 能说出 307/308 明确保持方法与体，301/302 历史上实现不一致，303 强制改 `GET` |
| 83 | 一次"网站慢"的分层排查顺序是什么，每层用什么工具 | 第 19 章 | 能按 DNS→建连→TLS→首字节→传输给出顺序，并各配 `dig`/`ss`/`openssl s_client`/`curl -w` |
| 84 | `curl -w` 的 `time_starttransfer` 与 `time_total` 差在哪里，它排除或包含了什么 | 第 19 章 | 能说明前者是到首字节，包含 DNS/TCP/TLS/服务端处理段，指出需要 `time_connect`、`time_appconnect` 相减来定位 |

### D.4.5 第五篇 数据库（第 20~27 章，36 条）

| # | 自测题 | 章节 | 通过标准 |
|---|---|---|---|
| 85 | 一条 SQL 从连接到返回，各层各做了什么，优化器在哪一步介入 | 第 20 章 | 能按连接层→解析→预处理→优化→执行→存储引擎说清，并指出优化器负责选索引与连接顺序 |
| 86 | 优化器为什么会选错索引，统计信息在其中扮演什么角色 | 第 20 章 | 能说出代价估算基于采样统计，指出采样偏差、`rows` 估算不准与多条件相关性问题 |
| 87 | 自适应哈希索引解决什么访问模式，为什么它可能成为负担 | 第 20 章 | 能说出对等值热点加速，指出维护成本与在范围查询、写密集下的负收益 |
| 88 | 一个 16 KB 页里放索引记录，页头页尾各占什么，`COMPACT` 与 `DYNAMIC` 的差别在哪 | 第 20 章 | 能说出页目录、槽位与溢出页策略差异，指出 `DYNAMIC` 把长列完全放溢出页 |
| 89 | 为什么 InnoDB 要求先写日志再写数据页，反过来会怎样 | 第 21 章 | 能说出数据页是随机的而日志是顺序的，反序会导致崩溃后数据页已改而日志缺失，无法恢复 |
| 90 | `LSN` 与 `checkpoint` 的关系是什么，`checkpoint` 推进意味着什么 | 第 21 章 | 能说出 `LSN` 单调递增标记日志位置，`checkpoint` 推进意味着此前脏页已落盘、日志可被覆盖 |
| 91 | 组提交（group commit）省的是什么开销，为什么它能保证一致性 | 第 21 章 | 能说出把多个事务的 `fsync` 合并为一次，指出日志先落盘后提交成功，因此不破坏持久性 |
| 92 | 两阶段提交里 `redo` 处于 `prepare` 时崩溃，恢复后这条事务是提交还是回滚 | 第 21 章 | 能说出需要看 binlog 是否完整：完整则提交，不完整则回滚，并说明为什么必须这样 |
| 93 | `STATEMENT` 格式的 binlog 在哪些语句下不安全 | 第 21 章 | 能举出带 `LIMIT` 无 `ORDER BY`、`NOW()` 等非确定性函数、`UUID()`，说明主从结果可能不同 |
| 94 | 长事务对 undo 与 MVCC 的危害是什么 | 第 22 章 | 能说出阻止 purge、版本链变长、回滚段膨胀，并指出 `ReadView` 长期持有会让清理停滞 |
| 95 | RC 与 RR 下 ReadView 的创建时机差在哪，这个差异如何产生不同的可见性结果 | 第 22 章 | 能说出 RC 每次快照读都新建、RR 只在第一次快照读创建并复用，能据此对比同一事务两次读的结果 |
| 96 | `RR` 下什么时候还会幻读 | 第 22 章 | 能给出两类场景：快照读与当前读混用（先快照读后 `UPDATE`/`SELECT ... FOR UPDATE`），以及事务内更新后再次快照读看到自己写的新行 |
| 97 | 可见性判断算法里 `m_ids`、`min_trx_id`、`max_trx_id` 各起什么作用 | 第 22 章 | 能完整走一遍判断流程：先比 `max_trx_id`，再比 `min_trx_id`，再查 `m_ids`，并沿版本链回溯 |
| 98 | 快照读与当前读分别什么时候发生，`UPDATE` 的 `WHERE` 用哪个 | 第 22 章 | 能区分普通 `SELECT` 与加锁读/写操作，指出 `UPDATE` 的定位用当前读、否则会丢更新 |
| 99 | 读取已提交在 InnoDB 里的实现是否与"读已提交"字面一致 | 第 22 章 | 能指出它读的是最新已提交版本（每次新 ReadView），比字面"已提交"更接近"语句级一致" |
| 100 | 三层 B+ 树大约能放多少行数据，怎么估算 | 第 23 章 | 能给出非叶节点约 1200 个指针、叶节点约 16 行的口径，算出约两千万行量级并说明键长影响 |
| 101 | 聚簇索引与二级索引查一行数据的路径差多少 | 第 23 章 | 能说出二级索引需回表、可能多一次 B+ 树查找与随机 I/O，并引出覆盖索引消除回表 |
| 102 | 最左前缀原则为什么成立，`(a,b,c)` 上 `WHERE b=1` 为什么用不上 | 第 23 章 | 能说出复合键按列序拼接比较，缺少前导列无法定位有序区间，指出 5.6+ 的索引下推只能减少回表不能定位 |
| 103 | 哪些写法会让索引失效，请给出不少于六种 | 第 23 章 | 能列出函数包裹列、隐式类型转换、前导模糊、`OR` 连接非索引列、`!=`、排序方向不一致等 |
| 104 | `ORDER BY` 什么时候能走索引、什么时候必然 `filesort` | 第 23 章 | 能说出排序列顺序与索引列顺序一致且方向一致时可避免排序，指出 `WHERE` 与 `ORDER BY` 共用索引的条件 |
| 105 | 联合索引列序怎么设计，区分度高的列一定放最前吗 | 第 23 章 | 能说出优先满足等值条件与排序需求，指出区分度只是参考，最左列的复用频率更重要 |
| 106 | 前缀索引的代价是什么，什么情况下不能用 | 第 23 章 | 能说出不能用于覆盖索引与排序，且需保证足够区分度；指出需用 `COUNT(DISTINCT LEFT(...))` 校验 |
| 107 | 唯一索引与非唯一索引在等值查询命中记录时加锁有何不同 | 第 24 章 | 能说出唯一索引等值命中只加记录锁，非唯一索引需加临键锁（退化为间隙锁），并解释原因 |
| 108 | 等值查询命中不存在的记录时，间隙锁加在哪个区间 | 第 24 章 | 能按具体数据推出加在相邻两条记录之间的间隙上，并指出 RC 下间隙锁被关闭 |
| 109 | 插入一条记录时为什么"看不到"加锁，隐式锁是什么 | 第 24 章 | 能说出插入本身不加显式锁，靠事务 ID 与记录标记，冲突时才由后来者补锁 |
| 110 | 意向锁的作用是什么，没有它会发生什么 | 第 24 章 | 能说出它是表级标记用于快速判断表中是否有行锁，避免逐行扫描检查表锁冲突 |
| 111 | 从死锁日志里你能还原出什么信息 | 第 24 章 | 能说出两个事务各持有什么锁、在等什么锁、等待哪个记录，并据此指出加锁顺序或索引缺失 |
| 112 | `EXPLAIN` 的 `type` 从好到坏大致怎么排，出现 `ALL` 一定有问题吗 | 第 24 章 | 能排出一个合理顺序；指出小表全扫或高选择性过滤下 `ALL` 未必是问题，需结合 `rows` 与 `filtered` |
| 113 | `key_len` 怎么算，它能告诉你什么 | 第 25 章 | 能按列类型字节数 + 可空标记 + 变长长度算出使用了几列，据此判断联合索引用上了几列 |
| 114 | `Using index`、`Using index condition`、`Using where` 三者差别 | 第 25 章 | 能区分覆盖索引、索引下推与服务端过滤，指出各自减少的是哪一层开销 |
| 115 | 深分页 `LIMIT 1000000, 10` 为什么慢，三种优化各适用什么场景 | 第 25 章 | 能说出需回表大量无用行；给出延迟关联、游标（记住上次位置）、覆盖索引取主键三种方案的适用边界 |
| 116 | `COUNT(*)`、`COUNT(1)`、`COUNT(col)` 的语义差别是什么 | 第 25 章 | 能说出前两者统计行数不校验列，`COUNT(col)` 跳过 `NULL`，并指出 InnoDB 无缓存计数需扫描 |
| 117 | 8.0 的 Hash Join 在什么条件下生效，比 BNL 好在哪 | 第 25 章 | 能说出等值连接且无合适索引时生效，指出它用哈希表代替被驱动表的多次扫描，减少回表 |
| 118 | 大表加字段怎么做到几乎不锁表，在线 DDL 工具的通用思路是什么 | 第 25 章 | 能说出建影子表+触发器/日志同步+改名的思路，指出 `gh-ost` 用 binlog 代替触发器的原因 |
| 119 | `seconds_behind_master` 为什么不准，你会用什么替代 | 第 26 章 | 能指出它基于本机时钟与事件时间戳，时钟不同步或大事务会造成跳变；用 `GTID` 等待或心跳表 |
| 120 | 主从延迟的常见原因有哪些，并行复制怎么缓解 | 第 26 章 | 能说出大事务、单线程回放、从库负载、DDL、无主键表等，指出按 `WRITESET` 分组并行回放 |

### D.4.6 第六篇 Java、JVM 与并发（第 28~32 章，27 条）

| # | 自测题 | 章节 | 通过标准 |
|---|---|---|---|
| 121 | `equals` 与 `hashCode` 的契约被破坏后，`HashMap` 会出什么现象 | 第 28 章 | 能说出相等对象哈希不同会落在不同桶，导致 `get` 不到且可能重复插入 |
| 122 | `String` 的不可变性带来了哪两个实际收益，`intern` 的代价是什么 | 第 28 章 | 能说出可安全共享与哈希缓存，指出常量池查找的成本与内存占用风险 |
| 123 | `Integer` 的 `-128~127` 缓存会写出什么 bug | 第 28 章 | 能举出用 `==` 比较包装类型在边界两侧结果不同的例子 |
| 124 | `finally` 里的 `return` 会覆盖 `try` 的返回值吗，字节码层面为什么 | 第 28 章 | 能说出会覆盖，并指出编译器把返回值暂存后 `finally` 的 `return` 再次写回 |
| 125 | 泛型擦除后桥方法是干什么用的 | 第 28 章 | 能举出子类重写泛型方法时编译器生成桥方法保证多态，说明它带来的重载歧义 |
| 126 | `ArrayList` 扩容一次涨多少，为什么要这样设计 | 第 29 章 | 能说出约 1.5 倍与传统上均摊代价的权衡，指出扩容时数组复制的成本 |
| 127 | `HashMap` 的哈希扰动函数为什么要有高 16 位异或 | 第 29 章 | 能说出桶下标只取低位，让高位参与进来可减少低位规律性造成的碰撞 |
| 128 | 负载因子 0.75 是怎么来的，改成 1.0 会怎样 | 第 29 章 | 能从空间与冲突的权衡解释，指出冲突增加会让链表变长、树化概率提高 |
| 129 | 树化阈值是 8、退化阈值是 6，为什么不对称 | 第 29 章 | 能说出避免在 7 附近反复树化与退化造成抖动，并提到泊松分布的假设 |
| 130 | 扩容时 `hash & oldCap` 为什么能判断节点留在原桶还是移动到原桶+旧容量 | 第 29 章 | 能说出容量是 2 的幂，新增的那一位决定高低，因此只需检查该位 |
| 131 | `ConcurrentHashMap` 从分段锁改到 `CAS + synchronized` 解决了什么 | 第 29 章 | 能说出分段锁的并发度受段数限制且内存开销大，新实现按桶加锁、空桶用 `CAS` |
| 132 | `TimSort` 抛出 "Comparison method violates its general contract" 的根因是什么 | 第 29 章 | 能指出比较器不满足传递性或一致性，导致归并时的分区不变量被破坏 |
| 133 | `happens-before` 有哪几条，程序顺序规则能推出跨线程可见性吗 | 第 30 章 | 能至少列出五条，指出程序顺序只保证单线程内，跨线程需靠锁/`volatile`/`join` 等规则传递 |
| 134 | 内存屏障有哪四种，`volatile` 写插哪几种 | 第 30 章 | 能说出读/写各两种（LoadLoad、StoreStore、LoadStore、StoreLoad），指出 `volatile` 写后插 `StoreLoad` 是最贵的 |
| 135 | DCL 单例为什么必须给实例字段加 `volatile` | 第 30 章 | 能说出对象引用赋值可能先于构造完成被看到，导致其他线程拿到半初始化对象 |
| 136 | `synchronized` 锁升级的完整路径与各阶段的成本 | 第 30 章 | 能说出无锁→偏向→轻量级（自旋/CAS）→重量级（内核互斥），指出偏向锁的撤销代价与 JDK 15+ 默认关闭 |
| 137 | `ThreadLocal` 内存泄漏的根因是什么，`remove` 为什么必要 | 第 30 章 | 能说出 `ThreadLocalMap` 的 key 是弱引用而 value 强引用，线程池复用时 value 长期存活 |
| 138 | 线程池提交任务的四步流程是什么，队列满了为什么不一定直接拒绝 | 第 31 章 | 能说出核心→队列→最大→拒绝，指出只有在队列满且线程数达最大时才触发拒绝策略 |
| 139 | `newFixedThreadPool` 与 `newCachedThreadPool` 各自的隐患是什么 | 第 31 章 | 能说出前者无界队列导致 OOM 与任务堆积、后者线程数无上限导致线程爆炸 |
| 140 | 线程数怎么定，IO 密集为什么可以远大于核数 | 第 31 章 | 能给出 `核数 × (1 + 等待时间/计算时间)` 的思路，指出等待期间可让出 CPU 且受下游承载限制 |
| 141 | AQS 的 `state` 在独占与共享模式下分别怎么用 | 第 31 章 | 能说出独占用 0/1 或重入计数，共享用剩余许可数，并指出 `Condition` 队列与同步队列的转移关系 |
| 142 | 公平锁与非公平锁的差别只是"排队"吗，为什么非公平吞吐更高 | 第 31 章 | 能说出非公平允许插队减少唤醒开销与上下文切换，指出可能造成饥饿 |
| 143 | `CountDownLatch`、`CyclicBarrier`、`Semaphore` 的语义差别是什么 | 第 31 章 | 能说出一次性减法等待、可重用栅栏、许可计数三类语义，并各给一个适用场景 |
| 144 | `CompletableFuture` 默认用哪个线程池，为什么可能出问题 | 第 31 章 | 能说出默认 `ForkJoinPool.commonPool`，指出公共池被阻塞任务占满会影响全局，应传自定义执行器 |
| 145 | 对象分配的 `TLAB` 解决什么问题，逃逸分析带来哪些优化 | 第 32 章 | 能说出避免多线程分配指针碰撞的同步开销，指出标量替换与栈上分配减少堆压力 |
| 146 | 哪四种引用，软引用和弱引用在回收时机上的差别是什么 | 第 32 章 | 能说出强/软/弱/虚，指出软引用在内存不足时回收、弱引用在下次 GC 即回收 |
| 147 | Minor GC 一次之后对象去了哪里，晋升老年代的三个触发条件是什么 | 第 32 章 | 能说出到 Survivor 并年龄加一，指出达到阈值、动态年龄判定、大对象直接进老年代 |
| 148 | 三色标记漏标的两个条件是什么，SATB 是怎么解决其中一个的 | 第 32 章 | 能说出"黑色对象新增指向白色对象的引用"与"灰色对象删除到白色对象的引用"需同时成立；SATB 记录删除前的快照 |
| 149 | 增量更新与原始快照两种解法分别对应哪类收集器 | 第 32 章 | 能说出增量更新（CMS）与原始快照（G1），并指出两者分别破坏漏标的哪一个条件 |
| 150 | CMS 的 `Concurrent Mode Failure` 在什么情况下发生，怎么缓解 | 第 32 章 | 能说出老年代在并发清理期间被填满导致退化为串行 Full GC，缓解手段包括降触发阈值、增大堆、减少晋升 |

### D.4.7 第七篇 消息队列、分布式与微服务（第 33~35 章，18 条）

| # | 自测题 | 章节 | 通过标准 |
|---|---|---|---|
| 151 | 消息可能在哪三个环节丢失，每个环节的确认机制叫什么 | 第 33 章 | 能分别说出生产者确认、存储刷盘与副本、消费者手动提交，并指出哪一环最容易被忽略 |
| 152 | `acks=all` 就保证不丢消息吗，还差什么 | 第 33 章 | 能指出还需 `min.insync.replicas` 足够与副本落盘，说明只配 `acks` 的边界 |
| 153 | 消费端重复消费的根因有哪几类，幂等键该怎么设计 | 第 33 章 | 能说出重平衡、提交失败重投、生产端重试三类；幂等键要能唯一标识业务事件而非消息 ID |
| 154 | 分区内有序的边界在哪，跨分区有序怎么实现 | 第 33 章 | 能说出同一分区内保证顺序，指出跨分区需按业务键路由或全局单分区（牺牲吞吐） |
| 155 | 消费积压时你会先扩容消费者还是先扩容分区，为什么 | 第 33 章 | 能指出消费者数超过分区数无收益，应先扩分区或提升单消费者吞吐，并考虑重平衡代价 |
| 156 | 事务消息和本地消息表解决的是同一个问题吗 | 第 33 章 | 能说出都是让本地事务与消息发送原子化，指出事务消息靠半消息+回查、本地消息表靠同库事务+投递重试 |
| 157 | CAP 的准确表述是什么，"三选二"错在哪 | 第 34 章 | 能指出分区容错是前提而非可选项，C 与 A 在分区期间只能取一；引出 PACELC 补充常态取舍 |
| 158 | 线性一致与顺序一致的差别是什么，Raft 提供哪一种 | 第 34 章 | 能说出线性一致要求全局实时顺序、顺序一致只要求全局一致顺序；指出 Raft 的线性一致读需要额外措施（如 ReadIndex） |
| 159 | 网络分区下 Raft 为什么不会出现两个都能提交的 leader | 第 34 章 | 能说出多数派交集与任期比较、候选人日志不旧才能当选，两个分区中至多一个能拿到多数票 |
| 160 | `commitIndex` 与 `matchIndex` 各由谁维护、作用是什么 | 第 34 章 | 能说出 leader 维护并据此判断已复制到多数派，指出只能提交当前任期的日志条目这一约束 |
| 161 | 2PC 与 TCC 的不一致窗口分别出现在哪里 | 第 34 章 | 能说出 2PC 协调者崩溃后的阻塞与参与者悬挂，TCC 的补偿失败与空回滚/悬挂问题 |
| 162 | Snowflake 遇到时钟回拨怎么办，为什么不直接用时间戳 | 第 34 章 | 能说出回拨时等待、抛出或改用备用位；指出单纯时间戳在同毫秒并发下会冲突 |
| 163 | `Redlock` 的争议点是什么 | 第 34 章 | 能指出批评集中在时钟漂移与 GC 停顿导致锁过期而客户端不知，及对 fencing token 的缺失 |
| 164 | 熔断器的三态是什么，从打开到半开的转换条件是什么 | 第 35 章 | 能说出关闭/打开/半开，指出打开后经过冷却期放入少量请求探测 |
| 165 | 线程池隔离与信号量隔离怎么选 | 第 35 章 | 能说出线程池隔离可超时中断但成本高，信号量隔离轻量但不能中断阻塞调用 |
| 166 | 链路追踪在跨线程与跨异步时如何传递上下文 | 第 35 章 | 能说出 `TraceID`/`SpanID` 需显式透传或用 `ThreadLocal`+装饰器，指出线程池复用会污染上下文 |
| 167 | 微服务拆分时机怎么判断，什么时候不该拆 | 第 35 章 | 能说出按团队边界与独立变更频率判断，指出团队小、事务强一致密集时拆分反而增加成本 |
| 168 | 限流四种算法的差别，令牌桶为什么能应对突发 | 第 34 章 | 能说出计数器/滑动窗口/漏桶/令牌桶，指出令牌桶允许以桶容量为上限的突发 |

### D.4.8 第八篇 场景设计与面试复盘（第 36 章，9 条）

| # | 自测题 | 章节 | 通过标准 |
|---|---|---|---|
| 169 | 设计题的第一个动作应该是什么，为什么不是画架构图 | 第 36 章 | 能说出先澄清需求与约束（读写比、峰值、一致性要求），指出没有约束的架构无法评价 |
| 170 | 日活 1000 万、人均 20 次请求、峰值系数 3，峰值 QPS 量级是多少 | 第 36 章 | 能算出平均约 2300 QPS、峰值约 7000 QPS，并说明峰值系数与集中时段的假设来源 |
| 171 | 秒杀为什么必须在 Redis 扣减，数据库扣减为什么不行 | 第 36 章 | 能说出数据库行锁与连接数在瞬时高并发下的排队崩溃，指出 Redis 原子操作用来挡住无效流量 |
| 172 | 秒杀场景下超卖的两种成因是什么 | 第 36 章 | 能说出 Redis 扣减与数据库扣减不同步、以及扣减成功但订单创建失败导致的少卖/超卖边界 |
| 173 | 短链接为什么常用 302 而不是 301 | 第 36 章 | 能说出 301 会被浏览器长期缓存导致无法统计与无法更换目标，302 每次回源便于计数与风控 |
| 174 | 排行榜用 `ZSet` 时，分页与并发更新各有什么坑 | 第 36 章 | 能说出 `ZREVRANGE` 深分页代价与分数相同时的排序稳定性，指出用时间戳做次级键 |
| 175 | Feed 流的推模式与拉模式各在什么场景下失效 | 第 36 章 | 能说出推模式在超大 V 场景写扩散、拉模式在关注数多时读放大，指出活跃度分层的混合方案 |
| 176 | 在线人数统计为什么不用集合精确统计 | 第 36 章 | 能说出内存与并发成本，指出 `HyperLogLog` 的误差与近似取舍，或分桶位图方案 |
| 177 | 白板上被追问到不会的点，正确的沟通节奏是什么 | 第 36 章 | 能说出先承认边界、给出可验证的替代假设、把问题收敛回已知机制，而不是沉默或硬编 |

> [!NOTE]
> 本清单共 177 条，覆盖第 1~36 章。建议用法：第一遍按篇做，把做不出的题号记下来；第二遍只做错题；面试前一天通读 D.5，用脚本自测"答不好的信号"是否出现。

## D.5 模拟面试脚本

三套脚本各约 30 分钟。问题按难度递增排列，**每个问题的价值在其后的追问**：第 1 问答对只是入门，第 2~3 问才能分层。

### D.5.1 脚本一：后端通用（网络 + Linux + 数据库）

| 序 | 问题 | 考什么 | 答不好的信号 |
|---|---|---|---|
| 1 | 一个 HTTP 请求从客户端到你的服务，中间经过哪些层，每层可能出什么问题 | 第 15 章分层与封装 | 只会背七层名字，说不出每层的故障模式 |
| 2 | 线上接口偶发 5 秒超时，你怎么把它定位到网络还是应用 | 第 19 章分层排查 | 直接说"看日志"，没有分层顺序与工具对应 |
| 3 | 服务端出现大量 `CLOSE_WAIT`，你怎么处理 | 第 16 章四次挥手与代码缺陷 | 答"等待就好"或与 `TIME_WAIT` 混淆 |
| 4 | `TIME_WAIT` 为什么不能省，服务端和客户端处理方式一样吗 | 第 16 章 2MSL 的两条理由 | 只说"确保 ACK 到达"，说不出防止旧报文污染 |
| 5 | 一个连接传输大文件时吞吐上不去，你会看哪些 TCP 指标 | 第 17 章窗口与拥塞 | 说不出 `cwnd`、窗口、BDP 中至少两个 |
| 6 | 磁盘 `%util` 100% 但业务没变慢，怎么解释 | 第 11 章指标口径 | 直接判定磁盘是瓶颈，说不出 `%util` 的统计口径 |
| 7 | 机器内存被 page cache 占满，你会清理吗 | 第 12 章内存回收 | 说"要 drop_caches"，而不判断是否真有内存压力 |
| 8 | 慢查询排查的完整步骤是什么 | 第 25 章执行计划 | 只会说"加索引"，不问慢在扫描还是排序还是回表 |
| 9 | 联合索引 `(a,b,c)` 上 `WHERE b=1 ORDER BY c` 能用上多少 | 第 23 章最左前缀 | 答"能用上 b 和 c"，说出能用但只起过滤不能定位区间才算过关 |
| 10 | 同一事务内两次读结果不同，可能是什么原因 | 第 22 章隔离级别 | 说不出隔离级别、快照读与当前读混用两种可能 |

### D.5.2 脚本二：JVM 与并发

| 序 | 问题 | 考什么 | 答不好的信号 |
|---|---|---|---|
| 1 | 一个对象从 `new` 到可以被回收，经历了哪些阶段 | 第 32 章对象生命周期 | 只会说"分配在堆上、GC 回收"，说不出 TLAB 与可达性 |
| 2 | 线上 Full GC 频繁，你的排查顺序是什么 | 第 32 章分代与晋升 | 只说"加内存"，不问是晋升失败还是元空间还是显式调用 |
| 3 | 为什么 `volatile` 能保证可见性但不能保证原子性 | 第 30 章内存屏障 | 说不出屏障类型或把可见性与原子性混为一谈 |
| 4 | `i++` 在多线程下出错的具体过程是什么 | 第 30 章读改写与竞态 | 只答"不是原子操作"，说不出读-改-写三步交错 |
| 5 | 手写一个双重检查的单例，说明每处细节 | 第 30 章重排序与安全发布 | 漏掉 `volatile`，或说不出为什么静态内部类更简单 |
| 6 | 线程池任务提交后一直不执行，可能有哪些原因 | 第 31 章四步流程 | 说不出队列类型、核心线程数、线程创建失败三种可能 |
| 7 | 队列用的是无界 `LinkedBlockingQueue`，你会怎么改 | 第 31 章资源边界 | 不认为无界队列是问题，说不出 OOM 与堆积风险 |
| 8 | `ReentrantLock` 的 `state` 是 2 说明什么 | 第 31 章 AQS 重入 | 答不出重入计数，或说不出释放需要两次 |
| 9 | 三色标记为什么会漏标，G1 怎么处理 | 第 32 章并发标记 | 只背"漏标要满足两个条件"，推不出 SATB 破坏哪个条件 |
| 10 | 你会为一个延迟敏感的在线服务选哪个收集器，依据是什么 | 第 32 章 GC 选型 | 直接答"G1"而不问堆大小、停顿目标与吞吐要求 |

### D.5.3 脚本三：系统设计

| 序 | 问题 | 考什么 | 答不好的信号 |
|---|---|---|---|
| 1 | 设计一个短链接服务，先说说你要问清楚什么 | 第 36 章需求澄清 | 直接开始画架构，不问 QPS、存储年限、是否需要统计 |
| 2 | 发号器怎么设计，哈希冲突怎么办 | 第 36 章 ID 生成 | 只说"用自增"，不考虑分布式与时钟回拨 |
| 3 | 短链接跳转用 301 还是 302，为什么 | 第 36 章语义与缓存 | 只说"302 更安全"，说不出缓存与统计的取舍 |
| 4 | 现在把这个系统扩到日活千万，容量怎么估算 | 第 36 章容量估算 | 给不出带假设的算式，或算完不给机器数 |
| 5 | 设计一个秒杀，库存怎么扣 | 第 36 章秒杀六层防线 | 直接说"用 Redis 扣减"，说不出为什么要挡在数据库之前 |
| 6 | 怎样保证不超卖，Redis 扣减成功但下单失败怎么办 | 第 36 章一致性与补偿 | 说不出最终扣减与对账、也提不出少卖与超卖的取舍 |
| 7 | 前端重复点击导致一个用户抢到两单，怎么防 | 第 33 章幂等 | 只说"前端置灰"，说不出服务端幂等键与唯一约束 |
| 8 | 流量削峰用 MQ，消费者处理不过来积压了怎么办 | 第 33 章积压与分区 | 只说"加消费者"，不提分区数上限与重平衡代价 |
| 9 | 这个系统的瓶颈会在哪，怎么验证 | 第 3 章与第 36 章 | 说不出压测方案与关键指标，只说"应该没问题" |
| 10 | 如果要求强一致不能超卖也不能少卖，你的方案怎么变 | 第 34 章一致性取舍 | 说不出代价（吞吐下降、可用性降低），只会说"上分布式事务" |

### D.5.4 面试官如何判断你在背八股还是真懂

以下 6 条为正信号、6 条为负信号两两对照。**正负信号不是"答对/答错"，而是"回答的组织方式"。**

1. **正**：回答有稳定的三段结构——机制是什么、为什么这样设计、不这样会怎样。**负**：回答是并列的名词清单，每个名词后面跟一句教科书定义，没有因果连接词。
2. **正**：主动给量化口径与假设（"假设读多写少 10:1、峰值系数 3，则……"）。**负**：给结论不给假设，被追问参数来源时改口或含糊（"大概是这个量级"）。
3. **正**：主动声明版本与前提（"MySQL 8.0 的默认隔离级别是 RR，PG 默认 RC；这里说的是 InnoDB"）。**负**：把不同系统的结论混在一起讲，或在被指出后才发现自己混了。
4. **正**：被追问到底层时能顺着一条路径继续往下走三层（如从慢查询追到 B+ 树回表、再追到 buffer pool 命中率）。**负**：第一层答得极流畅，第二层开始重复第一层的原话，第三层转到别的话题。
5. **正**：主动说出自己方案的代价与失效边界（"这个方案在热点 key 上会退化到单分片"）。**负**：只讲优点，问"这个方案有什么问题"时答"没有明显问题"。
6. **正**：对不确定的部分给出可验证的判断方法（"这个需要看 `EXPLAIN ANALYZE` 的真实行数才能定"）。**负**：用"一般来说""通常都是"填补不确定，或用记忆中的数字硬撑。

> [!CAUTION]
> 最容易被识破的不是答错，而是**答得过于完整且速度过快**：真实理解过机制的人在被追问参数来源时会停顿、会因为版本差别而修正自己。全程零停顿、零修正、零边界的回答，通常说明答案来自背诵材料而不是推导。

> [!TIP]
> 反向使用本节：自己也用这 12 条给自己录音打分。若第 2、4、5 条的正信号一次都没出现，说明知识是"平的"——每一层都能说一句，但没有一层能往下走。

## D.6 如何继续深入

以下 18 条都指向可定位的材料或可复现的实验。每条末尾说明**做完能回答哪类问题**。

1. **《深入理解计算机系统》（CS:APP）第 6 章"存储器层次结构"**，重点读 6.4~6.6 的缓存友好代码与 6.5 的矩阵乘法优化；配一个实验：把 `N×N` 矩阵乘法分别用 `i-j-k`、`i-k-j`、`k-i-j` 三种循环顺序跑一遍并计时。→ 能回答"为什么换循环顺序能差几倍""缓存行与工作集怎么估计"。
2. **《计算机体系结构：量化研究方法》第 2 章（指令级并行）与第 3 章（分支预测与推测）**，只读与流水线冒险、预测失败代价相关的段落。→ 能回答"分支预测失败的代价为什么随流水线深度增长""Spectre 为什么能读到不该读的内存"。
3. **《性能之巅》（Systems Performance）第 2 章方法论与第 8 章文件系统**，把 USE 方法的三列实际套到一台机器上填一遍。→ 能回答"新系统上线前该看哪些指标""怎么证明瓶颈在磁盘而不在 CPU"。
4. **Brendan Gregg 的 off-CPU 火焰图与 `perf` 脚本集**（Linux 内核文档 `tools/perf/Documentation`），跑一次 `perf record -g -a -- sleep 10` 再生成火焰图，并对照一次 off-CPU 采样。→ 能回答"CPU 不忙但请求很慢，时间花在哪""on-CPU 与 off-CPU 采样各能看到什么"。
5. **Linux 内核源码 `mm/memory.c` 的 `handle_mm_fault`** 与 `mm/rmap.c` 的 COW 相关路径（`do_wp_page`），用 `git log` 看这两处的历史修改。→ 能回答"写时复制缺页的完整分支""为什么共享页的引用计数必须精确"。
6. **`man 2 epoll` 的完整手册页 + 内核 `fs/eventpoll.c`**，重点读 `ep_poll_callback` 与就绪链表 `rdllist` 的挂接；实验：写一个 ET 模式服务器，把 `EPOLLIN` 事件漏读到 `EAGAIN` 并观察行为。→ 能回答"epoll 的就绪通知如何避免惊群""ET 下漏读为什么会永久丢事件"。
7. **《UNIX 网络编程 卷 1》第 6 章 I/O 复用与第 16 章非阻塞 I/O**，对照 `select`/`poll`/`epoll` 三份示例代码，用 `strace -c` 比较各自在 1000 个空闲连接下的系统调用次数。→ 能回答"`select` 的 O(n) 具体贵在哪里""LT 与 ET 在实现上的分界线"。
8. **RFC 5681（TCP Congestion Control）第 3 节**逐段读慢启动、拥塞避免、快重传、快恢复，并把 3.1 的 `ssthresh` 更新规则抄成一段伪代码；配 `ss -ti` 在一条人为限速的链路上采样 `cwnd`。→ 能回答"为什么超时与快重传对 `cwnd` 的处理不同""CUBIC 换了哪一步"。
9. **RFC 6298（Computing TCP's Retransmission Timer）**全文（很短），按其中的公式实现一个 `SRTT`/`RTTVAR` 的计算器，喂入一组含抖动的 RTT 序列。→ 能回答"RTO 为什么必须平滑""抖动大时 RTO 会怎么变"。
10. **RFC 9000（QUIC）第 2 章流与第 7 章丢包恢复**，只读"stream-level flow control"与"0-RTT"两节。→ 能回答"HTTP/3 为什么能消除 TCP 层队头阻塞""0-RTT 的重放风险怎么缓解"。
11. **MySQL 官方手册 "InnoDB Locking" 与 "Consistent Nonlocking Reads" 两节**，把八条加锁规则逐条对着手册确认；实验：建一张测试表，用两个会话按手册里的例子各跑一遍并打印 `SHOW ENGINE INNODB STATUS`。→ 能回答"非唯一索引等值查询为什么加临键锁""间隙锁在 RC 下为什么消失"。
12. **InnoDB 源码 `lock/lock0lock.c` 的 `lock_rec_lock` 与 `trx/trx0trx.c` 的事务状态机**，重点看加锁前的记录定位逻辑。→ 能回答"加锁范围是由什么决定的""为什么缺索引会让锁范围扩大"。
13. **InnoDB 源码 `trx/trx0purge.c` 与 `read/read0read.c` 的 `ReadView::changes_visible`**（或同义函数），对照第 22 章的可见性判断流程。→ 能回答"版本链回溯的终止条件""长事务为什么会拖住 purge"。
14. **《数据库系统内幕》（Database Internals）第一部分第 3~5 章**（存储引擎、B 树与 LSM 树），对照 B+ 树与 LSM 在写放大、读放大上的差异。→ 能回答"为什么分析型存储爱用 LSM""B+ 树的写放大会出现在哪里"。
15. **《Java 并发编程实战》第 3 章（共享对象）与第 5 章（基础构建模块）**，把 `happens-before` 的每条规则配一个最小反例代码并让它在不加同步时失败。→ 能回答"哪些看似安全的代码其实有可见性问题""安全发布的几种写法"。
16. **HotSpot 源码 `src/hotspot/share/gc/g1/g1CollectedHeap.cpp` 与 `gc/shared/satbMarkQueue.cpp`**，重点读 SATB 队列的入队时机与 `g1SATBBufferEnqueueingThresholdPercent`。→ 能回答"SATB 记的是哪个时刻的快照""为什么 SATB 需要额外的内存缓冲"。
17. **《数据密集型应用系统设计》（DDIA）第 5 章（复制）与第 9 章（一致性与共识）**，把第 9 章关于线性一致性与共识的编号步骤做成一张时序图。→ 能回答"线性一致读为什么需要额外机制""Raft 的多数派交集如何保证唯一 leader"。
18. **Raft 官方站点 `raft.github.io` 的可视化演示**，按"分区→选举→日志分歧→回退与覆盖"四步手动操作一遍，记录每步的任期与 `commitIndex` 变化；再读 Raft 论文第 5.4 节（安全性论证）。→ 能回答"日志冲突时 leader 如何强制覆盖 follower""为什么只能提交当前任期的条目"。

> [!IMPORTANT]
> 深入的原则是**一条路径走到能动手**：选上面任意 3 条，每条都产出一个可运行的实验脚本或一段可复述的推导。读完 18 条却一条没动手，收益低于认真做完 3 条。


---

> 作者: [破戒僧](https://onlyblacktea.cn)  
> URL: https://onlyblacktea.cn/book/backend/appendix-d/  

