#系统设计面试解题框架
#一个面试现场的对比
候选人 A 被问到"设计 Twitter":
A:画了个图,说用 Redis 缓存,用 MySQL 存储,说完了。
面试官:能支撑多少用户?
A:呃...很多?
面试官:Redis 挂了怎么办?
A:...不知道。候选人 B:
B:先问:DAU 是多少?平均每人关注多少人?每天发多少推文?
面试官:DAU 1亿,平均关注 500 人,平均每天发 5 条。
B:好,那我来分析一下流量...
(5分钟后)
B:我的方案分三个阶段:第一阶段用简单架构,第二阶段加缓存,第三阶段扩展。
面试官:好,你觉得哪里是瓶颈?
B:Feed 读取是最大的挑战,因为...区别在于:有没有方法论。
#二、四步解题法🔴
#Step 1: 需求澄清(5分钟)
必问的 5 个问题:
| 问题 | 为什么重要 |
|---|---|
| DAU/MAU 是多少? | 决定系统规模和架构 |
| 峰值 QPS 是多少? | 决定缓存、限流策略 |
| 核心功能是什么? | 确定 MVP 范围 |
| 数据量有多大? | 决定存储选型 |
| 可用性要求? | 决定容灾策略 |
问题模板:
"我先确认几个问题:
1. 系统的用户规模和增长预期?
2. 核心功能有哪些?(必须有的 vs 可以后加的)
3. 性能指标要求?(延迟、吞吐量)
4. 可用性要求?(SLA 是多少)
5. 有什么特殊约束?(预算、技术栈、团队能力)"#Step 2: 高层设计(10分钟)
画出核心组件:
┌─────────────────────────────────────────────┐
│ 用户请求 │
│ ↓ │
│ ┌─────────────────┐ │
│ │ Load Balancer │ │
│ └────────┬────────┘ │
│ ↓ │
│ ┌─────────────────┐ │
│ │ API Service │ │
│ └────────┬────────┘ │
│ ↓ │
│ ┌────────────┼────────────┐ │
│ ↓ ↓ ↓ │
│ ┌───────┐ ┌───────────┐ ┌───────────┐ │
│ │ Cache │ │ Service │ │ Queue │ │
│ └───────┘ └─────┬─────┘ └─────┬─────┘ │
│ ↓ ↓ │
│ ┌───────────┐ ┌───────────┐ │
│ │ Database │ │ Kafka │ │
│ └───────────┘ └───────────┘ │
└─────────────────────────────────────────────┘API 设计:
// 核心 API
POST /api/v1/feed // 创建动态
GET /api/v1/feed // 获取 Feed
POST /api/v1/users/{id}/follow // 关注用户
DELETE /api/v1/users/{id}/follow // 取消关注#Step 3: 核心细节设计(15分钟)
选一个核心问题深入:
Twitter 面试的核心问题通常是 Feed 系统:
1. 如何存储用户的 Feed?
2. 如何生成 Feed?
3. 如何高效读取 Feed?
4. 如何处理新用户关注?
选一个,深入讲。深度分析模板:
问题:如何生成用户首页 Feed?
方案 A:拉模式(Pull)
- 读取时聚合所有关注用户的动态
- 优点:写入快、数据一致
- 缺点:读取慢、复杂度高
- 适用:粉丝数少、读取量低
方案 B:推模式(Push)
- 发推时推送给所有粉丝
- 优点:读取快
- 缺点:写入量大(大V问题)
- 适用:粉丝数多、写入量低
方案 C:混合模式(Hybrid)
- 普通用户推,大V拉
- 阈值:粉丝数 > 10000 用拉模式
- 优点:兼顾读写
- 缺点:复杂度最高#Step 4: 权衡与扩展(5分钟)
讨论 trade-off:
面试官:"Redis 挂了怎么办?"
好的回答:
"这里有一个权衡:
- 如果 Redis 不可用,我可以降级到数据库查询
- 但这会导致性能下降 10-100 倍
- 所以我需要限流保护数据库
- 同时需要告警通知运维
或者:
"Redis 挂了意味着 Feed 系统不可用。
我可以做多级降级:
1. L1 本地缓存 → 热点数据
2. L2 Redis → 主缓存
3. L3 MySQL → 最终兜底
每层故障时自动降级到下一层。"#三、高频系统设计题分类🔴
#3.1 存储类
| 题目 | 核心问题 | 关键方案 |
|---|---|---|
| 设计短链系统 | ID 生成 | 雪花算法 + Base62 |
| 设计分布式 ID | 唯一 ID | 雪花算法、号段模式 |
| 设计排行榜 | 排名计算 | Redis ZSet |
#3.2 流处理类
| 题目 | 核心问题 | 关键方案 |
|---|---|---|
| 设计 Feed 流 | 推拉模式 | Hybrid 模式 |
| 设计秒杀系统 | 库存扣减 | Redis Lua、MQ |
| 设计消息系统 | 消息路由 | WebSocket、路由表 |
#3.3 检索类
| 题目 | 核心问题 | 关键方案 |
|---|---|---|
| 设计搜索框 | 全文检索 | ES、倒排索引 |
| 设计附近的人 | 地理查询 | Geohash、Redis GEO |
| 设计推荐系统 | 协同过滤 | 矩阵分解 |
#四、容量估算模板🔴
#4.1 数据量估算
假设:
- DAU = 1 亿
- 每人每天操作 = 10 次
- 平均数据大小 = 1 KB
计算:
- 日写入量 = 1亿 × 10 × 1KB = 1 TB
- 年存储量 = 1TB × 365 = 365 TB
- 考虑备份 = 365TB × 3 = 1 PB#4.2 QPS 估算
假设:
- DAU = 1 亿
- 日活跃 = 10%
- 日请求 = 1 亿 × 10% × 10 = 1 亿次
- 峰值系数 = 10
计算:
- 平均 QPS = 1亿 / 86400 ≈ 1200
- 峰值 QPS = 1200 × 10 = 12000#五、面试话术模板🟡
#5.1 开头
"好的,让我先确认一下需求..."
"在开始设计之前,我想问几个关键问题..."
(确认完需求后)
"根据你说的 DAU 是 X,我估计峰值 QPS 大约是 Y,
核心挑战是 Z..."#5.2 方案陈述
"我的方案分三个阶段:
第一阶段(MVP):用最简单的方式实现核心功能
- 组件:单机房、单机
- 数据:单库
第二阶段(扩展):解决主要瓶颈
- 缓存层
- 读写分离
第三阶段(高级):应对未来增长
- 分库分表
- 多活部署
"#5.3 被追问时
面试官:"这个方案有什么问题?"
好的回答:
"这个方案的问题在于 X 和 Y。
具体来说:
- X 会在 Z 场景下成为瓶颈
- Y 可能会导致一致性问题
我的解决方案是...或者接受这个限制,因为..."#5.4 权衡讨论
面试官:"你选 A 方案而不是 B 方案,为什么?"
好的回答:
"A 和 B 各有权衡:
- A 的优势是...劣势是...
- B 的优势是...劣势是...
我选择 A 是因为在我的场景下,...更重要,而...不是主要矛盾。
如果...发生了变化,我会切换到 B 方案。"#六、常见陷阱🟡
| 陷阱 | 表现 | 解决 |
|---|---|---|
| 不澄清需求 | 直接开始画图 | 先问 DAU、QPS、功能范围 |
| 过度设计 | 一上来就微服务 | 先 MVP,再逐步扩展 |
| 不讨论失败 | 只讲成功场景 | 主动讨论故障处理 |
| 不量化 | "应该够用" | 给出具体数字 |
| 不承认局限 | "我的方案完美" | 承认权衡,说明选择原因 |
【面试官心理】 系统设计面试的核心是权衡能力。没有完美的方案,只有适合的方案。面试官想看的是:你能不能识别关键权衡、做出合理决策、并说清楚原因。
#七、面试总结
| 级别 | 期望表现 |
|---|---|
| P5 | 能澄清需求,画出基本架构 |
| P6 | 能深入一个核心问题,给出多种方案对比 |
| P7 | 能做完整的容量估算,主动讨论权衡 |