第1章:系统设计面试步骤(Steps for System Design Interview)
一、导读
1.1 本章学习目标
系统设计面试没有标准答案,但有标准流程。第1章建立了一套结构化的面试方法论,分为四个步骤。Alex Xu 通过大量实例展示了如何在45分钟内有条理地完成一个完整的系统设计。
本章的核心学习目标包括:
- 掌握四步面试框架:需求澄清 → 高层设计 → 详细设计 → 总结扩展。
- 学会区分功能需求和非功能需求:前者定义"系统做什么",后者定义"系统做得多好"。
- 理解数据规模估算的重要性:QPS、存储、带宽的估算决定架构选型。
- 掌握高层设计的画图技巧:如何用最少的组件表达核心架构。
- 学会详细设计的深入方向:数据库 Schema、API 设计、关键算法。
- 了解常见面试错误:如何避免"过度设计"和"忽视非功能需求"。
1.2 为什么本章如此重要
Alex Xu 在开篇就指出:系统设计面试考的不是你能设计多复杂的系统,而是你能否在有限时间内展示结构化的思考能力。很多候选人技术能力很强,但因为缺乏面试方法论,在45分钟内无法展示完整的思考过程,最终遗憾落选。
本章的四步框架是全书的方法论基础,后续每一章的案例分析都严格遵循这个框架。掌握这个框架,你就拥有了解决任何系统设计题目的通用工具。
1.3 核心问题引导
系统设计面试的四个步骤分别应该花多少时间?
功能需求和非功能需求的区别是什么?如何向面试官澄清?
数据规模估算(Back-of-the-envelope calculation)为什么重要?
高层设计应该包含哪些核心组件?
详细设计应该深入到什么程度?
面试官最看重候选人的哪些能力?
二、核心概念详解
2.1 第一步:需求澄清(5分钟)
2.1.1 功能需求
功能需求定义"系统能做什么"——用户可以使用哪些功能。
// 功能需求澄清模板:
// 面试官:"请设计一个 URL 短链服务"
//
// 候选人应该问的问题:
// 1. 短链服务的基本功能是什么?
// → 用户输入长 URL,生成短 URL
// → 访问短 URL,重定向到长 URL
//
// 2. 用户是否可以自定义短链接?
// → 是/否(影响设计复杂度)
//
// 3. 是否需要用户认证?
// → 匿名用户也可以使用?
//
// 4. 是否需要统计功能?
// → 点击次数、访问来源、访问时间
//
// 5. 短链接是否有过期时间?
// → 永久有效 or 可设置过期
//
// 6. 是否支持 URL 删除?2.1.2 非功能需求
非功能需求定义"系统做得多好"——性能、可用性、一致性等。
// 非功能需求澄清模板:
//
// 1. 流量规模:
// → DAU(日活用户)?
// → 每日 URL 缩短次数?
// → 每日重定向次数?
//
// 2. 性能要求:
// → 短链生成的响应时间?(< 200ms)
// → 重定向的响应时间?(< 100ms)
//
// 3. 可用性要求:
// → 99.9% 还是 99.99%?
//
// 4. 一致性要求:
// → 短链生成后立即可用?(强一致)
// → 还是允许短暂延迟?(最终一致)
//
// 5. 特殊需求:
// → 高并发场景?(如社交媒体分享链接)
// → 地理分布?(全球用户 vs 单一地区)2.1.3 数据规模估算
// Back-of-the-envelope 计算:
//
// 假设:
// - 每月新增短链:1亿
// - 每个短链数据:长URL(500B) + 短码(7B) + 创建时间(8B) + 过期时间(8B) ≈ 523B
// - 读写比:10:1(重定向次数远大于创建次数)
//
// 存储估算:
// - 每月存储增量:1亿 × 523B ≈ 50GB
// - 5年存储总量:50GB × 60个月 = 3TB
//
// QPS 估算:
// - 每月新增 QPS:1亿 / (30 × 24 × 3600) ≈ 40 QPS
// - 峰值 QPS:40 × 3 = 120 QPS(假设峰值是均值的3倍)
// - 重定向 QPS:120 × 10 = 1200 QPS
//
// 带宽估算:
// - 写入带宽:120 × 523B ≈ 60KB/s
// - 读取带宽:1200 × 523B ≈ 600KB/s
//
// 结论:
// - 存储需求不大(3TB/5年)
// - 读 QPS 较高(1200),需要考虑缓存
// - 写 QPS 不高(120),单数据库可以承受2.2 第二步:高层设计(15分钟)
2.2.1 核心组件识别
// URL 短链服务的高层设计:
//
// [Client] → [Load Balancer] → [API Server]
// ↓
// [URL Service]
// ↓ ↓
// [Database] [Cache]
//
// 核心组件:
// 1. Load Balancer:分发请求到多个 API Server
// 2. API Server:接收请求,调用 URL Service
// 3. URL Service:核心业务逻辑(生成短码、查找长URL)
// 4. Database:存储长短URL映射
// 5. Cache:缓存热门短链,减少数据库压力
// 数据流:
// 短链生成:
// Client → LB → API Server → URL Service → Database (存储映射)
//
// 重定向:
// Client → LB → API Server → URL Service → Cache/Database (查找长URL)
// ↓
// 301/302 Redirect2.2.2 画图技巧
// 高层设计图的关键原则:
// 1. 只画核心组件(5-8个),不要画太多细节
// 2. 用箭头表示数据流方向
// 3. 标注关键组件的职责
// 4. 标注读写比例和 QPS
// 好的高层设计图:
// [Client] → [LB] → [Web Server × N]
// ↓
// [URL Service]
// ↓ ↓
// [MySQL] [Redis]
// (持久化) (缓存)
//
// 标注:
// - 读QPS: 1200, 写QPS: 120
// - 读写比: 10:1
// - 缓存命中率目标: 80%
// 不好的高层设计图:
// - 画了太多组件(20+个)
// - 没有标注数据流方向
// - 没有标注 QPS 和读写比
// - 过度深入细节(如具体的表结构)2.3 第三步:详细设计(20分钟)
2.3.1 数据库 Schema 设计
-- URL 映射表
CREATE TABLE url_mapping (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
short_code VARCHAR(7) UNIQUE NOT NULL,
long_url VARCHAR(2048) NOT NULL,
user_id BIGINT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
expiration_at TIMESTAMP NULL,
INDEX idx_short_code (short_code),
INDEX idx_user_id (user_id),
INDEX idx_created_at (created_at)
);
-- 设计决策:
-- 1. short_code 使用 VARCHAR(7):62^7 ≈ 3.5万亿种组合,足够使用
-- 2. long_url 使用 VARCHAR(2048):HTTP URL 最大长度
-- 3. user_id 可为空:支持匿名用户
-- 4. expiration_at 可为空:支持永久链接2.3.2 短码生成算法
// 方案1:哈希 + 碰撞处理
// 1. 对长URL计算 MD5/SHA256
// 2. 取前7个字符作为短码
// 3. 如果冲突,追加随机字符重新哈希
//
// 优点:简单
// 缺点:无法预知短码,碰撞时需要重试
// 方案2:Base62 编码(推荐)
// 1. 使用自增ID作为唯一标识
// 2. 将ID转换为Base62编码(a-z, A-Z, 0-9)
// 3. ID=1000 → 短码="gk"
//
// Base62 编码:
// 字符集:0-9 (10) + a-z (26) + A-Z (26) = 62个字符
// 7位短码可以表示:62^7 ≈ 3.5万亿个URL
//
// 优点:短码唯一,无碰撞
// 缺点:短码可预测(安全性低)
// 方案3:预生成短码池
// 1. 预先批量生成随机短码,存入数据库
// 2. 每次请求从池中取出一个使用
// 3. 池低于阈值时补充
//
// 优点:生成速度快,短码不可预测
// 缺点:需要管理短码池
// 推荐方案2(Base62),简单高效2.3.3 API 设计
// RESTful API 设计:
// 1. 创建短链
POST /api/v1/shorten
Content-Type: application/json
{
"long_url": "https://www.example.com/very/long/url",
"custom_alias": "mylink", // 可选
"expiration": "2025-12-31" // 可选
}
Response 201:
{
"short_url": "https://short.ly/abc123",
"long_url": "https://www.example.com/very/long/url",
"created_at": "2024-01-15T10:30:00Z"
}
// 2. 重定向(核心接口)
GET /abc123
Response: 301 Moved Permanently
Location: https://www.example.com/very/long/url
// 3. 查询短链信息
GET /api/v1/shorten/abc123
Response 200:
{
"short_code": "abc123",
"long_url": "https://www.example.com/very/long/url",
"created_at": "2024-01-15T10:30:00Z",
"click_count": 1523
}2.4 第四步:总结与扩展(5分钟)
2.4.1 瓶颈分析
// 系统瓶颈分析:
//
// 1. 数据库瓶颈:
// - 单MySQL写QPS约1000,当前写QPS=120,暂时够用
// - 读QPS=1200,通过Redis缓存(命中率80%)减少到240
// - 如果流量增长10倍,需要数据库分片
//
// 2. 缓存瓶颈:
// - Redis单实例QPS约10万,当前读QPS=1200,完全够用
// - 需要Redis集群保证高可用
//
// 3. 单点故障:
// - API Server:多实例 + 负载均衡
// - 数据库:主从复制 + 自动故障转移
// - Redis:Redis Sentinel 或 Cluster2.4.2 扩展方向
// 可能的扩展方向:
// 1. 统计分析:记录每次点击,生成访问报告
// 2. CDN 集成:热门短链的重定向通过 CDN 处理
// 3. 地理分布:多区域部署,就近访问
// 4. 限流和防滥用:防止恶意生成大量短链
// 5. A/B 测试:同一短链根据条件重定向到不同目标三、实战案例
3.1 案例一:完整面试模拟——设计 Pastebin
// 第一步:需求澄清(5分钟)
// 功能需求:
// 1. 用户可以粘贴文本,生成分享链接
// 2. 访问链接可以看到原始文本
// 3. 文本支持设置过期时间
// 非功能需求:
// 1. 高可用:99.99%
// 2. 低延迟:< 200ms
// 3. DAU:1000万
// 4. 每日新增 Paste:100万
// 第二步:高层设计(15分钟)
// [Client] → [CDN] → [LB] → [API Server × N]
// ↓
// [Paste Service]
// ↓ ↓
// [PostgreSQL] [Redis]
// 第三步:详细设计(20分钟)
// 数据库:
// CREATE TABLE pastes (
// paste_id VARCHAR(8) PRIMARY KEY,
// content TEXT NOT NULL,
// user_id BIGINT,
// created_at TIMESTAMP,
// expiration_at TIMESTAMP NULL
// );
//
// 短ID生成:Base62编码自增ID
// 缓存策略:LRU,缓存最近访问的 Paste
// 第四步:总结(5分钟)
// 瓶颈:大文本存储、CDN缓存策略
// 扩展:语法高亮、密码保护、文件上传3.2 案例二:面试评分标准
// 面试官评估维度:
// 1. 需求澄清(20%)
// - 是否主动澄清功能和非功能需求?
// - 是否进行了合理的数据规模估算?
// 2. 高层设计(30%)
// - 是否识别了核心组件?
// - 数据流是否清晰?
// - 是否考虑了负载均衡和缓存?
// 3. 详细设计(30%)
// - 数据库 Schema 是否合理?
// - API 设计是否 RESTful?
// - 关键算法是否正确?
// 4. 沟通与总结(20%)
// - 是否主动与面试官沟通?
// - 是否分析了瓶颈和扩展方向?
// - 时间管理是否合理?四、本章小结
本章建立了系统设计面试的标准化方法论:
核心知识点:
- 四步框架:需求澄清(5min)→ 高层设计(15min)→ 详细设计(20min)→ 总结扩展(5min)。
- 功能需求定义"做什么",非功能需求定义"做得多好"。
- 数据规模估算(QPS、存储、带宽)决定架构选型。
- 高层设计只画核心组件(5-8个),标注数据流和 QPS。
- 详细设计深入到数据库 Schema、API 设计和关键算法。
- 面试评估维度:需求澄清20%、高层设计30%、详细设计30%、沟通总结20%。
五、思考与练习
思考题
如果面试官在需求澄清阶段就给出了所有需求,你应该怎么做?
数据规模估算的误差范围是多少?如何验证估算的合理性?
高层设计和详细设计之间的边界在哪里?
练习题
使用四步框架,完成"设计一个 URL 短链服务"的完整练习(严格计时45分钟)。
使用四步框架,完成"设计 Pastebin"的完整练习。
对比你的设计和参考答案,找出差距和改进方向。