上半部分(48 问总表)由 tools/derive.py 从 16 章的 .interview 区块派生,禁止手工编辑;节奏表、评分尺与计时 mock 是固定模板,同样只能改脚本、不能手改产出。
这页现在是三段:先看下面这张 48 问总表建地图;再用节奏表和评分尺练「怎么答」与「答得够不够」;最后用 3 道计时 mock 练「没见过的题目怎么办」。
| 章节 | 高频追问 | 答题骨架 | 锚点链接 |
|---|---|---|---|
| 第 1 章 | 「估算一下这个系统需要多少台服务器 / 多大容量。」 | 答题骨架:先要 DAU 和人均请求数(没有就自己假设并说出来)→ 日请求量 → 平均 QPS → 乘峰值倍数(说明为什么这个业务取这个倍数)→ 再用 并发 ≈ QPS × RT 折成机器数 → 最后单独说一句存储和带宽。反直觉加分点:主动指出峰值形状比总量重要,并问一句「这个业务的流量是平缓型还是尖峰型」。 | 第 1 章 → |
| 第 1 章 | 「讲一下从用户点击到看到结果,中间经过了什么。」 | 答题骨架:DNS → 建连(TCP + TLS 握手,强调来回次数)→ 反向代理 → 应用(路由/鉴权/业务)→ 数据库(连接池 → SQL → 事务)→ 原路返回。每一环补一句「这里可能慢在哪」,并点出数据库通常是最贵的一环。 | 第 1 章 → |
| 第 1 章 | 「一开始就该上微服务吗?」 | 答题骨架:不按偏好答,按信号答 → 团队规模与发布冲突频率、变更频率差异、故障隔离需求 → 说明单体在小团队下的真实优势是"函数调用而非网络调用" → 给出拆分的触发条件而不是时间表。可以主动说:拆分不降低复杂度,只是把它从代码搬到网络上(第 13 章会展开)。 | 第 1 章 → |
| 第 2 章 | 「为什么不能无限加大连接池?」 | 答题骨架:池是并发许可 → 下游容量才是吞吐上限 → 大池把等待搬到 DB → 实例数 × 单池大小核算总连接 → 用压测找安全水位。 | 第 2 章 → |
| 第 2 章 | 「为什么 P99 比平均值重要?」 | 答题骨架:平均值会稀释长尾 → 排队由慢请求占槽传播 → 对比 P50/P99 与超时比例 → 用分位数定位少量请求如何拖住资源。 | 第 2 章 → |
| 第 2 章 | 「超时应该怎么定?」 | 答题骨架:从端到端用户预算倒推 → 参考正常 P99 而非拍脑袋 → 给各层分配 deadline → 明确取消与重试 → 用错误率和资源释放验证。反直觉加分点:超时首先是资源预算。 | 第 2 章 → |
| 第 3 章 | 「主从延迟导致读到旧数据,怎么办?」 | 答题骨架:先按业务定义可接受新鲜度 → 圈出关键写后读 → 强制读主 / 会话粘性 / 乐观展示三选或组合 → 给出主库容量与失败回滚账单。 | 第 3 章 → |
| 第 3 章 | 「复制延迟怎么监控?」 | 答题骨架:主库提交位点 → 副本接收位点 → 副本应用位点 → 区分网络与重放 → 补业务 write-to-visible 的 P50/P99 → 按新鲜度目标告警。 | 第 3 章 → |
| 第 3 章 | 「读写分离的路由放哪一层?」 | 答题骨架:列应用层 / 数据访问层 / 代理层责任边界 → 比较业务语义感知、统一治理与故障切换 → 用写后读标记贯穿路由。反直觉加分点:路由不只是负载均衡,它也在执行一致性契约。 | 第 3 章 → |
| 第 4 章 | 「缓存一致性方案怎么设计?」 | 答题骨架:先定权威源与可接受窗口 → 选 cache-aside 等模式 → 写顺序与失败补偿 → 热点回源保护 → 版本比对与业务对账。 | 第 4 章 → |
| 第 4 章 | 「为什么先删缓存再写库也有坑?」 | 答题骨架:画并发时序 → 删除后读 miss → 读到旧 DB 值并回填 → DB 新值提交 → 缓存遗留旧值 → 给出二次失效或改顺序的账单。 | 第 4 章 → |
| 第 4 章 | 「延迟双删值不值?」 | 答题骨架:它缩小特定并发窗口 → 延迟长度依赖读耗时与复制延迟 → 第二次删除仍可能失败 → 不能替代重试和对账。反直觉加分点:先量错误窗口,再决定是否加复杂度。 | 第 4 章 → |
| 第 5 章 | 「Redis 突然全挂了,系统会发生什么?怎么办?」 | 答题骨架:契约公式说明 DB 将承受多少倍流量 → 止血(限流降级)→ 恢复(高可用切换/重启)→ 预热 → 慢放量 → 复盘单点问题。能主动讲出「冷缓存死亡螺旋」是强信号。 | 第 5 章 → |
| 第 5 章 | 「穿透、击穿、雪崩的区别与对策?」 | 别背处方,先讲症状形状(渗血 / 尖刺 / 断崖)再对症给药——展示的是诊断能力而非记忆力。 | 第 5 章 → |
| 第 5 章 | 「命中率降到多少需要告警?」 | 反直觉加分点:不看命中率绝对值,看 总流量 × (1 − 命中率) 相对 DB 容量的余量。命中率 90% 在小流量系统里岁月静好,在大流量系统里已经着火。 | 第 5 章 → |
| 第 6 章 | 「限流算法怎么对比与选型?」 | 答题骨架:先给已验证配额 → 描述令牌桶尖头 / 漏桶直线 / 滑动窗口台阶 → 匹配突发容忍度 → 给队列、状态与公平性账单。 | 第 6 章 → |
| 第 6 章 | 「降级预案怎么设计?」 | 答题骨架:按资金与履约分 L0/L1/L2 → 每层写开关、兜底数据和用户文案 → 独立资源隔离 → 定期演练恢复顺序。 | 第 6 章 → |
| 第 6 章 | 「限流阈值怎么定?」 | 答题骨架:压测容量 → 扣除故障与长尾余量 → 按核心链路最窄处设总预算 → 生产指标校准 → 分级动态调整。反直觉加分点:阈值不是机器峰值,而是可持续服务承诺。 | 第 6 章 → |
| 第 7 章 | 「重试为什么会把小故障放大?」 | 答题骨架:画调用层 → 写乘积公式 → 代入 3×3×3=27 → 解释资源占用制造更多超时 → 给单一责任层、预算与幂等前提。 | 第 7 章 → |
| 第 7 章 | 「熔断和限流有什么区别?」 | 答题骨架:限流按容量控制进入量 → 熔断按失败状态停止某依赖 → Closed/Open/Half-open → 两者与降级、舱壁组合。 | 第 7 章 → |
| 第 7 章 | 「backoff 的 jitter 有什么用?」 | 答题骨架:backoff 把峰向后摊开 → 相同参数仍会同步醒来 → jitter 随机打散 → 说明它不减少总量。反直觉加分点:预算与 jitter 分别管总数和波形。 | 第 7 章 → |
| 第 8 章 | 「分库分表方案怎么设计?」 | 答题骨架:容量与查询画像 → 选择分片键 → 路由与全局 ID → 扩容迁移 → 跨片查询与事务 → 按分片观测和回滚。 | 第 8 章 → |
| 第 8 章 | 「热点 key 怎么处理?」 | 答题骨架:算最热/平均 → 识别业务 key → 限流与隔离 → 二次 bucket 打散 → 缓存击穿保护 → 热点消退后的合并与回收。 | 第 8 章 → |
| 第 8 章 | 「分片键选错了怎么补救?」 | 答题骨架:先加映射层或二级索引止痛 → 双写新旧路由 → 回填校验 → 灰度切读 → 停旧写并回收。反直觉加分点:先量迁移比例和热点分布,不把扩容当重分片。 | 第 8 章 → |
| 第 9 章 | 「MQ 如何保证消息不丢?」 | 答题骨架:生产确认 → 队列持久化与副本 → 消费成功后确认 → 失败重试与死信 → 业务对账补发。先声明保证边界,再说明跨系统不能只靠一个组件承诺。 | 第 9 章 → |
| 第 9 章 | 「消息积压了怎么办?」 | 答题骨架:生产/消费差值定方向 → oldest age 定影响 → 限制非核心生产 → 找消费瓶颈 → 按分区与下游余量扩容 → 算追平时间 → 清零后对账。 | 第 9 章 → |
| 第 9 章 | 「消息顺序性怎么保证?」 | 答题骨架:先问全局还是业务键内有序 → 同 key 路由同分区 → 单分区串行或版本校验 → 重试不允许状态倒退 → 说明热点键与吞吐账单。反直觉加分点:多数订单系统需要的是聚合内有序,不是全局排队。 | 第 9 章 → |
| 第 10 章 | 「秒杀系统怎么防超卖?」 | 答题骨架:定义单一库存裁决点 → 拒绝非原子读改写 → DB 条件更新或 Redis Lua → 成功凭证与幂等键 → 队列削峰 → 对账与补偿 → 压测最后一张票。 | 第 10 章 → |
| 第 10 章 | 「预扣库存和实际库存怎么对账?」 | 答题骨架:初始配额 → 预扣凭证 → 订单落库 → 支付状态 → 取消释放 → 按业务键做差集 → 超时未知先查询再补偿。说明对账不变量与人工处置入口。 | 第 10 章 → |
| 第 10 章 | 「Redis 挂了,库存怎么办?」 | 答题骨架:先停止新增批准 → 明确 RDB/AOF 与副本恢复边界 → 用已落库订单和预扣凭证重建 → 对账后慢放量。反直觉加分点:库存服务降级应偏向少卖,不能在状态未知时绕过权威账继续收款。 | 第 10 章 → |
| 第 11 章 | 「接口幂等怎么设计?」 | 答题骨架:请求方预生成业务键 → 同键绑定请求摘要 → 原子占位 → 业务结果与状态持久化 → 重复请求返回第一次结果 → 超时按原键查询 → TTL 与归档策略。 | 第 11 章 → |
| 第 11 章 | 「分布式锁有哪些坑?」 | 答题骨架:无过期死锁 → TTL 太短并发持有 → 无 owner 校验误删 → 主从切换丢锁 → GC/网络分区后的旧持有者 → 幂等 + fencing token 兜底。 | 第 11 章 → |
| 第 11 章 | 「唯一索引兜底怎么做?」 | 答题骨架:从业务意图选择复合键 → 数据库 UNIQUE 约束抵住并发 INSERT → 冲突后读取既有结果 → 同键不同参数拒绝 → 说明它只兜写入竞态,不能替代完整状态机。反直觉加分点:冲突是幂等命中,不应统一翻译成 500。 | 第 11 章 → |
| 第 12 章 | 「请用 45 分钟设计一个秒杀系统。」 | 答题骨架:需求与库存约束 → 峰值估算 → 静态化/网关/排队漏斗 → 库存原子扣减 → 订单支付异步化 → 幂等对账 → 降级与容量验证。 | 第 12 章 → |
| 第 12 章 | 「怎么防黄牛?」 | 答题骨架:账号/设备/行为风险信号 → 资格预校验 → 限频与凭证 → 排队公平 → 支付与收货约束 → 申诉和误伤指标。 | 第 12 章 → |
| 第 12 章 | 「全链路压测怎么做?」 | 答题骨架:隔离测试数据 → 按漏斗逐层给量 → 同时验证正常与故障路径 → 观察到达/通过/拒绝/积压 → 自动回滚 → 对账收尾。反直觉加分点:压测要证明拒绝路径也能工作。 | 第 12 章 → |
| 第 13 章 | 「单体和微服务怎么选?」 | 答题骨架:团队规模与发布冲突 → 业务边界稳定度 → 独立扩容/故障隔离收益 → 网络与平台成本 → 端到端 SLO → 给出模块化单体作为可逆中间态。 | 第 13 章 → |
| 第 13 章 | 「微服务拆分边界怎么定?」 | 答题骨架:业务能力内聚 → 数据单一归属 → 独立变更频率 → 故障可降级 → 长期团队 owner → 用历史共变更和事故数据验证,而不是按表或技术层切。 | 第 13 章 → |
| 第 13 章 | 「什么时候不该拆?」 | 答题骨架:团队小、边界频繁变化、强事务密集、平台能力不足、端到端观测缺失时先不拆。反直觉加分点:部署单元少不等于代码无边界,模块化单体也可以有严格归属约束。 | 第 13 章 → |
| 第 14 章 | 「线上整体变慢,怎么定位?」 | 答题骨架:端到端 SLI 确认影响 → 按用户/路由/版本切片 → RED 找服务 → 正常/慢 trace 差分 → USE 找饱和资源 → logs 与变更时间线验证 → 小范围恢复。 | 第 14 章 → |
| 第 14 章 | 「怎么设计告警不被淹没?」 | 答题骨架:症状告警 page、原因告警自动化/工单 → SLO burn rate 多窗口 → 去重合并 → owner + runbook → 定期统计精度、响应时间和噪音成本。 | 第 14 章 → |
| 第 14 章 | 「metrics、traces、logs 各解决什么问题?」 | 答题骨架:metrics 看覆盖与趋势 → traces 还原单次跨服务路径 → logs 解释局部决策 → 用 trace id/exemplar 关联。反直觉加分点:数据量最多的支柱不自动拥有最高诊断价值。 | 第 14 章 → |
| 第 15 章 | 「异地多活架构怎么设计?」 | 答题骨架:业务分级 RTO/RPO → 同城/异地/单元化选择 → 数据归属与写策略 → 多数派和围栏 → 路由与容量接管 → 冲突仲裁 → 演练与回滚。 | 第 15 章 → |
| 第 15 章 | 「脑裂怎么防?」 | 答题骨架:固定成员集多数派 → 成员变更走共识 → 入口与存储双层 fencing → 单调 token 拒绝旧主 → 单元化减少共享写 → 分叉后按业务账本仲裁。 | 第 15 章 → |
| 第 15 章 | 「RTO/RPO 怎么定?」 | 答题骨架:按业务影响分层 → RTO 是业务恢复时间、RPO 是可接受丢失窗口 → 映射复制与备份能力 → 计算成本 → 用演练测实际值。反直觉加分点:目标写在文档里不算达成,演练实测才是当前能力。 | 第 15 章 → |
| 第 16 章 | 「如何保障大促稳定性?」 | 答题骨架:峰值估算与故障后容量 → 分层漏斗与核心优先级 → 限流/熔断/舱壁 → 数据一致性与对账 → 预案演练 → 值班、回滚与复盘。 | 第 16 章 → |
| 第 16 章 | 「混沌实验怎么起步?」 | 答题骨架:选已知故障与单一稳态指标 → 预发验证工具 → 最小生产单元 → 自动停止条件 → 一次只改一个变量 → 证据通过再扩大。 | 第 16 章 → |
| 第 16 章 | 「容量规划怎么做?」 | 答题骨架:业务峰值与形状 → 压测验证容量 → 水位起步值 0.7(按误差、冗余、故障域、恢复能力上下调) → 按故障场景重算分母 → 补容量或减流 → 用生产指标持续校准。反直觉加分点:余量是可验证的故障预算。 | 第 16 章 → |
系统设计面试一轮常见 45–60 分钟,各家不同;下面按 45 分钟排一份可执行的节奏表——不是死规矩,是给你一个默认锚点,防止在某一段里超支到收不了尾。
| 阶段 | 建议分钟数 | 这一段要产出什么 |
|---|---|---|
| 需求澄清 | 5 分钟 | 功能范围 + 非功能约束(QPS 量级、延迟目标、一致性要求)+ 明确说一句「这次不做什么」。 |
| 容量估算 | 5 分钟 | DAU/QPS/存储量级 + 峰值倍数,说出假设,不用算到小数点。 |
| API 与数据模型 | 7 分钟 | 2–3 个核心接口签名 + 关键实体和它们的索引/分片键。 |
| 总体架构 | 10 分钟 | 组件框图 + 数据流箭头,边画边讲每个组件的职责一句话。 |
| 瓶颈深挖 | 10 分钟 | 面试官追问的那一个点讲透——通常是缓存、分片、一致性或削峰里的一个,不用四个都展开。 |
| 可靠性与故障 | 5 分钟 | 指出架构里的单点,给出降级/兜底动作。 |
| 收尾 | 3 分钟 | 权衡总结一句话 + 主动说一条「我知道但没时间展开」的短板。 |
下面这把尺子不是给面试官用的,是给你自己练完一题后回看用的。每一档写的是可观察的行为,不是形容词——你应该能对照自己刚才说的话,逐条打勾。
怎么定档:每一档写的都是比上一档多做到的事;「够用」格写的是最常见的短板,「良好」「优秀」写的是补上它之后的样子。从「够用」往上看,你的档位是最后一个你完整做到的档——只命中一句「优秀」却没做到「良好」的条目,仍然只算「够用」。如果某道题根本没触发某个维度(比如题面里没有失败场景),该维记 N/A,不要记 0,也不要用它拉低整体判断。
| 维度 | 够用 | 良好 | 优秀 |
|---|---|---|---|
| 需求与约束 | 说出了功能范围和大致 QPS 量级,没有主动问延迟或一致性要求。 | 主动追问了非功能约束(延迟、一致性、可用性),并明确说出了「这次不做什么」。 | 把约束翻译成了后续设计的判据(例如「读多写少、能容忍秒级新鲜度,所以后面允许用缓存」),并在设计里真的用上了这句话。 |
| 估算与容量 | 算出了 QPS 量级,用乘法得出结果,但没检查数量级是否合理。 | 给出 DAU → QPS → 峰值倍数 → 机器数区间的完整链条,并说明了每一步的假设。 | 指出了哪个假设最敏感(换一个数量级,结果会差多少),并说明了下一步用什么压测去缩小这个不确定性。 |
| 架构与数据流 | 画出了组件,但无法从入口开始逐条边走到最终的读/写结果;至少有一条关键边没有说明协议、数据或状态变化。 | 边画边讲清楚了完整数据流,并标出了读路径和写路径的差异。 | 主动标出了架构里当前最可能先倒下的那条边,并说明了为什么先怀疑它而不是别的组件。 |
| 失败与恢复 | 提到了「要限流」「要重试」这类通用词,没有映射到架构里的具体组件。 | 针对架构图里某个具体依赖,说清楚了它变慢/挂掉会发生什么,以及第一层兜底动作。 | 讲出了故障传播路径——哪个下游变慢会拖垮哪个上游——并给出了阻断点,而不是给每个组件逐个贴创可贴。 |
| 权衡表达 | 选出了方案,但答案里没有为至少一个未选方案写出具体代价(不依赖面试官是否追问——自己主动写才算)。 | 对每个候选方案都说出了具体代价(不是「更贵」这种模糊词,而是一句可核实的账单)。 | 说出了「什么事实一变,这个选择就会反过来」——翻转变量式的表达,而不是记住一个固定偏好。 |
下面 3 题只给初始需求,答案不会被保存,刷新即失——这是刻意的:现实中的面试也不会让你带答案进场。每题分两阶段:先按给定的分钟数写方案,点开揭晓看基准答案;基准答案里会带出下一阶段的追问,写完追问的方案再展开第二次揭晓。三题覆盖三种题型,练的是方法能不能迁移,而不是记住某一道题的答案。
先只交两样:① 你会问的 3 个澄清问题;② 整体架构草图(组件 + 数据流,用文字箭头写,不用画图)。
写不出来也要写下卡在哪一步——那本身就是有用的诊断。答案不会被保存,刷新即失。
你还没写。先写下来再看——再点一次仍会展开。
澄清问题至少覆盖:库存是否分场次/分区、是否要求先到先得还是允许摇号、超卖的容忍度是多少。架构骨架:入口限流/排队 → 静态化详情页/CDN → 库存原子扣减(DB 条件更新或 Redis Lua)→ 订单异步落库 → 支付与出票。
运营现在要求:同一个用户最多买 4 张;且要支持「先到先得」和「随机摇号」两种放票模式随时切换。你的架构要改哪里?
看完阶段一的基准答案和追问段后再写。只交修改点,不用重写整个架构:哪些组件要动、为什么。
答案不会被保存,刷新即失。
你还没写。先写下来再看——再点一次仍会展开。
限购通常在库存裁决点旁边加一次「用户已购数」的原子检查,和扣减库存放进同一个原子操作,不能拆成先查后扣两步。先到先得的裁决点是「谁先完成原子扣减」;摇号模式的裁决点变成「谁被抽中」——差别在于扣减库存之前要不要插入一次批量抽签,扣减本身的原子性要求不变。
先只交两样:① 3 个澄清问题;② 一次点赞事件到榜单更新的数据路径草图。
答案不会被保存,刷新即失。
你还没写。先写下来再看——再点一次仍会展开。
澄清问题至少覆盖:热度分数怎么算(播放/点赞/转发的权重)、榜单允许多陈旧(30 秒是硬指标还是可以再宽松)、要不要防刷分。路径骨架:互动事件 → 消息队列削峰 → 流式聚合更新分数(内存计数器或近似 Top-K 结构)→ 每 30 秒把结果落一份快照到缓存 → 读请求只打这份快照,不直接查明细表。
运营要求:不同城市要看到不同的热榜(同城内容优先),且不能让一线城市的大流量把三四线城市的小众热点淹没。你的方案要改哪里?
看完阶段一的基准答案和追问段后再写。只交修改点:哪里要按维度切分、切分之后原来的瓶颈会不会转移。
答案不会被保存,刷新即失。
你还没写。先写下来再看——再点一次仍会展开。
把「全国一个热度分数」改成按城市分别聚合、分别排序,热度用城内相对值。注意归因:三四线城市的内容进不了榜,不是因为算力被一线城市挤占,而是排序尺度问题——全国榜按绝对互动量排,小城市的视频绝对量永远进不了 Top 100,无论给它多少算力。实现上不必物理拆成几百条流水线,同一条流式作业按 city 分区即可;资源隔离只是顺带收益。城市粒度太细会导致长尾城市数据稀疏,通常还要加一层兜底:数据不足时退化到大区或全国榜垫底。
先只交两样:① 3 个澄清问题;② 这条链路的编排方式草图(谁触发下一步、状态存在哪)。
答案不会被保存,刷新即失。
你还没写。先写下来再看——再点一次仍会展开。
澄清问题至少覆盖:某一步失败了是重试还是回滚前面的步骤、超时算多久、这条链路要不要支持人工介入。骨架要明确选一种,别混着说:编排式——一个履约编排器持有订单状态表,按状态给下一步的服务发命令、等回执、写回状态,各步服务只做自己那件事并保证幂等;事件式——每步完成发一条事件、下一步订阅,但那样就没有中央状态表和中央重试,阶段二的「第 3 次失败转人工」得每个服务各自实现。两种都合格,答案里要说清选了哪种,并与阶段二保持一致。每一步都写幂等键,允许安全重放。
运营要求:某一步失败超过 3 次要自动转人工,但转人工之前不能让用户以为订单卡死了——要有中间态展示。你的方案要改哪里?
看完阶段一的基准答案和追问段后再写。只交修改点:状态机要加什么状态、用户端读到的是什么。
答案不会被保存,刷新即失。
你还没写。先写下来再看——再点一次仍会展开。
状态机里加一个「处理中(重试计数 N/3)」和「待人工处理」两个中间状态,而不是失败了就直接把订单标记成失败。计数器随每次重试自增,第 3 次失败后状态转「待人工」并生成一张工单,同时停止对它的自动推进——编排式是编排器不再发下一条命令,事件式是各消费者读到「待人工」即跳过。用户端读到的仍然是订单状态表里的这个中间状态,展示成「正在处理,请稍候」,不暴露内部的失败/重试细节。
这三道 mock 是第 16 章「接下来 4 周」里 第 4 周 的内容——前三周分别是:给自己的系统做一次体检、写三份故障 runbook、做一次预发游戏日。如果你是直接翻到附录 B 的,建议回去把前三周补上:没有自己系统的上下文,面试答案很容易停在「组件都提到了」那一档,而那正是上面这把评分尺第一维要卡的地方。
每做完一题,用评分尺给自己打一次分,把落在「够用」的那几维记下来——它们就是你下一轮要练的东西。
如果你要面的是 Agent 方向的岗位,同样的「先交卷、再对照、再接追问」练法,本系列另有一本 Agent 设计面试手册:题目换成「设计一个会调用工具的 Agent」,追问换成权限、评估与失败恢复。