面试官扔来一句「设计一个 Twitter」「设计一个发号器」,45–50 分钟,白板或共享文档,没有标准答案。新手以为考的是「我知道多少组件」,于是开始背诵『加 CDN、加 Redis、加 Kafka』——这恰恰是最快的挂法。
面试官真正在测的是四件事(现代 rubric 基本都能拆成这四桶):判断力(judgment,在约束下做选择)、技术深度(depth,能不能往下挖到实现)、操作成熟度(operational maturity,想没想到失败/扩容/监控)、沟通(communication,能不能主导对话、讲清推理)。同一道题,能区分 L4 / L5 / L6 的不是答案对错,而是这四个维度的密度。
graph TD
Q["面试官:设计一个 X
开放 · 无标准答案"]
S1["① 范围界定 ~5min
功能/非功能 · 主动砍范围"]
S2["② 容量估算 ~5min
QPS/存储/带宽 BOTE"]
S3["③ 高层架构 ~10min
画框架图 · 数据流"]
BUY{"面试官 buy-in?
先对齐再继续"}
S4["④ 深挖 ~15min
选瓶颈组件 · 讲 trade-off"]
S5["⑤ 收尾 ~5min
瓶颈 · 扩展 · 取舍总结"]
NARR["全程:出声推理
narrate 每个决策"]
Q --> S1 --> S2 --> S3 --> BUY
BUY -->|跑偏/范围不对| S1
BUY -->|对齐| S4 --> S5
NARR -.贯穿.-> S3
classDef start fill:#2a1530,stroke:#ff7ab6,color:#e8eef5
classDef step fill:#1a2530,stroke:#64c8ff,color:#e8eef5
classDef gate fill:#1a1a30,stroke:#ffb450,color:#e8eef5
classDef side fill:#0e2030,stroke:#5eead4,color:#e8eef5
class Q start
class S1,S2,S3,S4,S5 step
class BUY gate
class NARR side
时间盒是骨架;菱形的 buy-in 检查点防止你花 15 分钟把错的系统设计得很漂亮
原理:开放题的第一动作不是画图,是把题收敛成可设计的题。先分 功能需求(发推、看 timeline、关注)和 非功能需求(规模、延迟 SLO、一致性、可用性)。然后主动声明取舍:「我先聚焦发推 + home timeline 这两个核心路径,搜索和广告这次先不展开,可以吗?」——这一句话同时传递了 judgment 和 communication 两个信号。面试官给模糊题,就是想看你会不会问、敢不敢划线。
# 范围界定 = 一组澄清问题,按信息增益排序
clarify = [
"核心功能边界?哪些是 must-have,哪些先不做", # 决定整个设计的形状
"规模?DAU / 读写 QPS / 数据量 / 增长曲线", # 决定要不要分片/缓存
"延迟 SLO?p99 读 200ms?写可异步?", # 决定同步 vs 异步
"一致性要求?能容忍 stale 多久", # 决定 CAP 取舍
"读写比?10:1 重读 → 缓存/读副本", # 决定架构重心
]
# 把答案写在白板角落,作为后续每个决策的「约束锚点」
原理:框架是 clarify → estimate → high-level design → deep dive → wrap-up。它的价值不是「步骤」,而是时间盒和buy-in 检查点。每画完高层架构,停下来问一句「这个方向 ok 吗?我接下来想深挖 X」——这一步让你不会埋头把面试官不关心的部分做满,也把对话的主导权握在手里。
| 阶段 | 时间 | 产出 | 失分点 |
|---|---|---|---|
| 澄清 + 范围 | ~5min | 功能/非功能 + 砍掉的部分 | 直接开画 |
| 容量估算 | ~5min | QPS / 存储 / 带宽数量级 | 不估算 → 后面无法 justify 分片 |
| 高层架构 | ~10min | 组件框架图 + 数据流 | 画太细,陷进单个组件 |
| 深挖 | ~15min | 1–2 个组件的实现 + trade-off | 泛泛,不往下挖 |
| 收尾 | ~5min | 瓶颈 / 扩展 / 监控 / 取舍 | 没时间了 |
原理:depth 信号几乎全部产生在深挖阶段。关键动作有二:①主动选深挖点——挑那个最有 trade-off 张力的组件(瓶颈、热点、一致性边界),而不是被动等面试官追问;②出声推理(think out loud)——把脑子里的候选方案、淘汰理由都说出来。即使最终结论错了,清晰的推理路径也能拿到 partial credit;沉默地写出一个正确答案,反而拿不到沟通分。
# 该深挖哪里?一个排序启发式
def pick_deep_dive(components):
return max(components, key=lambda c:
c.has_tradeoff * 3 + # 有多个合理方案 → 能展示 judgment
c.is_bottleneck * 3 + # 高 QPS / 大数据量 → 扩展性话题
c.has_failure_mode * 2 + # 会挂、需要重试/降级 → operational
c.i_know_it_well * 2) # 诚实评估自己的掌握度
# 通常命中:写路径的 fanout、热点 key、一致性窗口、消息投递保证
原理:系统设计没有「正确架构」,只有「在约束 X 下,我选 A、牺牲 B、因为 C 比 D 更重要」。每个技术决策都该带上 被淘汰的替代方案 和 淘汰理由。一句「用 Kafka」是零信号;「读写比 100:1 且要支持 replay,所以选 Kafka 而非 RabbitMQ,代价是运维和 partition 管理更复杂」——这是满分表达。它证明你知道自己在放弃什么。
# Trade-off 表达模板(说出口时按这个结构)
"在【约束:读写比/延迟/一致性】下,
我选【方案 A】,而不是【B / C】,
因为 A 在【维度】上更优;
代价是【牺牲的维度】,
但对本场景可接受,因为【业务理由】。
如果约束变成【反约束】,我会改选【B】。" # ← 最后这句是 staff 信号
面试官最爱的 5 个追问(提前想好):
砍什么:保留发推 + home timeline(最有 trade-off 张力:fanout-on-write vs read 的经典取舍);明确声明这次不展开搜索、广告、trending、私信、媒体转码——它们各自是独立大题。
怎么申请才不像偷懒:关键是给出理由而非只说「不做」。「Twitter 的核心难点在 timeline 的 fanout 与名人热点,我想把时间集中在这条路径上深挖到存储和扩展层;搜索和广告是独立子系统,如果还有时间我们再回来——这样安排可以吗?」——这同时展示了 judgment(你知道哪里最难)、communication(主动对齐)、和时间意识。偷懒是「不做且不解释」;缩范围是「有意识地分配深度预算」。面试官几乎总会接受,因为这正是资深工程师做项目的方式。
信号解读:面试官在主动引导你去他真正想考的点。可能原因:①这块你已经讲够了,再讲是边际递减;②他的评分卡上有别的必考项(比如他想看一致性,你却在抠 API 分页);③时间不够,他要保证覆盖到关键考点。无论哪种,这都是礼物而非批评——他在帮你把时间花在能得分的地方。
怎么调整:别恋战、别解释「但这里也很重要」。立刻顺着他的方向:「明白,那我转到 X——这里我看到的关键 trade-off 是……」。同时更新你对「这场面试在考什么」的判断:他刚刚暴露了他的评分重心,后面主动往那个方向多走。能快速读懂并响应这种引导,本身就是高 communication 分。
senior:把系统做对——选 token bucket,讲清算法,用 Redis 做分布式计数,处理原子性(Lua 脚本),返回 429 + Retry-After。正确、完整、有深度。
staff:在 senior 的基础上,跳出单个系统看二阶效应与组织约束。例如:①「分布式计数每次都打 Redis 会让限流器自己成为瓶颈和单点,我会在每个节点本地预借一批配额(local token + 周期对账),用一点点精度换可用性」;②「限流规则谁来配、怎么热更新、误杀了怎么快速回滚——这关系到 oncall 和其他团队」;③「限流应该是平台能力还是每个服务自己实现?如果 50 个团队各写一遍,维护成本和不一致就是组织级问题」。差别不在技术深度,而在视野半径:senior 优化组件,staff 优化组件之间、团队之间的 trade-off。
有反作用:出声推理的目的是暴露结构化的思考,不是填满每一秒的沉默。如果你一边想一边语无伦次地跳来跳去,反而暴露思路混乱,给面试官「不成体系」的印象。流式输出未经组织的念头 ≠ 沟通。
该先静想的时刻:①面试官刚给完题或刚加了新约束——花 20–30 秒在白板列要点、组织框架再开口,比立刻喷强得多;②被追问到一个需要权衡的硬问题——明确说「让我想 30 秒」,从容比抢答更显资深;③要做容量估算——先安静算,再把结论和关键假设讲出来。原则:先在脑子里(或白板角落)形成一个有结构的小结论,再 narrate 这个结论的推理路径。沉默是用来组织、出声是用来呈现,两者交替,不是二选一。
面试里:BOTE(back-of-envelope)给个数量级——「10 亿用户 × 每人 1KB = 1TB,单机放不下 → 分片」——加上出声 justify,就足够支撑决策。面试考的是推理是否合理,不是数字是否精确。
生产里:同样的决策要靠①真实指标(当前 QPS、存储增长斜率、p99 延迟趋势);②压测(在接近真实数据分布下测出单分片的实际拐点,而非理论值);③可观测性回归(上线后持续验证假设是否成立)。为什么不能照搬:BOTE 假设均匀分布,而生产的杀手是热点和长尾——平均值告诉你「该分片」,但真正决定分片键和分片数的是 p99 和最热那个 key 的行为。面试里你可以说「假设均匀」,生产里这个假设往往就是事故的根源。面试训练的是决策框架,生产要的是用数据校验过的框架——框架同源,依据不同。(延伸见 Day 26 / Day 27)