系统设计面试基础课程
结构化系统设计面试课程,覆盖面试路线、容量估算、扩展、数据库、API、微服务、可靠性、可观测性和安全,并配有练习题。
你将学到
- 解释系统设计面试路线并澄清需求。
- 用简单计算估算 QPS、存储和容量。
- 应用负载均衡、缓存和 CDN 扩展服务。
- 使用 CAP 比较数据库、分片和一致性。
- 设计 API、微服务、队列以及可靠可观测的系统。
开始前准备
- 具备基础编程知识
- 了解 HTTP、API 和数据库
- 无需系统设计面试经验
课程 1 系统设计面试路线
系统设计面试考查你如何把一个宽泛的产品想法变成清晰的技术方案。面试官希望看到结构、沟通和权衡意识,而不是背下来的架构图。每次回答先复述问题,再询问用户、规模和限制条件。
先澄清需求:谁使用系统、每秒多少读和写、什么延迟要求、需要存储多少数据、用户分布在哪些地区。把这些数字写下来,因为后面的每个决定都依赖它们。
接着做简单的容量估算:估算日活用户、每秒请求数、存储增长和带宽。像 QPS = DAU x 每人每日操作数 / 秒数 这样的粗略计算,足以判断应该做小型还是大型设计。
然后画出高层设计:客户端、负载均衡、应用服务、缓存、队列和数据库。标注每个组件,在深入细节前先说明主要请求流程。
选择一两个区域深入讨论,比如数据模型、API 设计、分片策略或故障处理。说明你在优化哪个权衡,并在最终选择前比较至少一个替代方案。
最后用简短总结收尾:关键组件、主要风险和需要监控的指标。清晰的结尾能让面试官跟上你的思路,也让回答更容易被记住。
面试流程:复述问题、澄清需求、估算规模、设计高层架构,再深入一两个组件。始终说明权衡,并解释如何衡量成功。
示例
面试题示例:“设计一个短链接系统。”先从需求开始:用户规模、每天创建链接数、每个链接的读取次数、存储量和过期时间。然后说明核心流程:客户端发送长链接,服务生成短 ID,保存映射,读取时用 301 或 302 重定向。
练习回答:QPS = 100 万链接/天 / 86,400 秒 ≈ 每秒 12 次写入,读取量约为写入的 100 倍。这种写入量适合关系数据库,而读取可以通过缓存和 CDN 友好的重定向来优化。
示例:设计短链接服务时,先澄清读写比例、链接长度和分析需求,再画组件。
课程 2 扩展、负载均衡与缓存
扩展是面试官最先考查的内容,因为它连接所有组件。垂直扩展给单台机器增加性能;水平扩展增加更多机器,通常是 Web 系统的选择。
负载均衡位于服务前端,检查健康状态,并用轮询、最少连接等策略分发流量。七层负载均衡还可以按 URL 路径和请求头路由。
缓存把高频读取的数据放在靠近调用方的地方。数据库读取常用 cache-aside:先查缓存,未命中就从数据库加载并写回,设置 TTL。选择 LRU 淘汰,并确定失效时机。
CDN 从边缘节点提供静态资源,降低全球用户的延迟。它最适合图片、JavaScript、CSS 等不可变内容。
面对热点键,单个热门对象可能压垮一个缓存分片。可以把键分散到多个分片,或给缓存键加入随机性,并分别缓存不同层级的聚合结果。
示例:一个读密集的信息流可以把 API 放在负载均衡后,用 Redis 缓存热门内容,用 CDN 提供静态文件,从而降低数据库读取并保持响应稳定。
扩展循环:从单台服务器开始,随负载增加依次加入负载均衡、水平副本、缓存、CDN 和数据库只读副本。用 TTL 缓存热数据,并谨慎失效以保持一致性。
示例
设计决策:一个新闻信息流每秒收到 10,000 次读取。把负载均衡放在 API 服务前面,用 Redis 缓存前 1,000 条热门内容,并用 CDN 提供头像和图片。
追问:“如果某条信息流突然变热怎么办?”把缓存键分散到多个分片,并设置较短的 TTL,避免数据库过载。
示例:个人主页可缓存 5 分钟;与用户相关的内容保持动态。
课程 3 数据库、分片与一致性
数据库选择取决于访问模式。关系数据库适合结构化事务和关联查询;NoSQL 存储适合灵活模式、高写入量或大规模分布式数据。
为常见查询路径添加索引,当连接查询变贵时对读模型做反规范化。只读副本把 SELECT 流量移出主库,故障转移在主库失效时保持写入可用。
分片按键把行拆分到多个节点,可使用范围或哈希分区。哈希分片负载均匀但范围查询困难;范围分片利于局部性但可能出现热点分片。
CAP 定理说明分布式系统在网络分区时必须在一致性和可用性之间选择。强一致性更容易推理,最终一致性扩展性更好,但需要协调。
分布式事务成本很高。优先使用幂等操作、发件箱表或事件驱动流程,而不是让每次写入跨服务原子完成。
面试时说出数据库类型、分片键、副本策略和一致性模型。这四个决定能体现你对规模化数据的理解。
数据选型练习:事务和关联用关系库,灵活或高量数据用 NoSQL,按稳定键分片。用索引、反规范化、只读副本和故障转移匹配访问模式。
示例
设计决策:聊天服务按 conversation_id 存储消息。对该键做哈希分片可以让同一对话保存在同一分片,再用二级索引支持用户收件箱查询。
一致性:消息确认使用强一致性,已读回执使用最终一致性,并通过时间戳进行调和。
示例:聊天应用把会话存在 NoSQL,并按用户 ID 建索引。
课程 4 REST API、微服务与消息队列
清晰的API 设计让系统更容易构建和维护。REST 使用资源和 HTTP 动词:GET 读取、POST 创建、PUT 替换、PATCH 更新、DELETE 删除。使用 201 表示已创建、429 表示被限流等状态码。
大集合使用分页。数据变化时游标分页更稳定;偏移分页更简单,但可能跳过或重复数据。
限流保护 API 不被滥用。令牌桶和滑动窗口是常见算法,通常按用户或 API Key 设置限额。
微服务把产品拆成边界清晰、可独立部署的服务。避免共享一个数据库,并用 API 网关集中处理认证、路由和限流。
消息队列解耦生产者和消费者。至少一次投递可能产生重复消息,所以消费者应保持幂等;死信队列保存反复失败的消息。
示例:订单服务把事件写入队列,支付服务消费它,通知服务监听结果。每个服务都可以独立扩展和部署。
API 练习:用清晰动词和状态码设计资源,大集合分页,API 版本化。按所有权和故障域拆分服务,用队列解耦慢速或突发工作。
示例
API 设计:GET /users/{id}/orders?cursor=... 返回一页订单并附带下一个游标。按用户使用每分钟 100 次的令牌桶限流。
故障处理:如果支付很慢,把订单事件发布到队列,由支付服务消费;失败的支付消息进入死信队列。
示例:创建订单返回 201 并发布事件,支付服务异步消费。
课程 5 可靠性、可观测性与安全
可靠系统会优雅地处理故障。对瞬时错误使用带指数退避和抖动的重试,并加入熔断器,在服务耗尽资源前停止调用失败服务。
舱壁模式隔离资源池,避免一个慢服务占用所有连接。设置超时,并为非核心功能定义降级行为。
可观测性结合指标、日志和链路追踪。指标显示健康状态,日志解释事件,分布式追踪跟踪一个请求跨服务的路径。定义 SLI 和 SLO,让团队知道何时需要处理。
安全应融入设计:传输数据使用 TLS、网关做认证、最小权限访问、密钥管理,以及公开端点限流。
还要讨论成本和容量:合理选择实例规格、使用自动扩缩、把冷数据移到更便宜的存储,并避免闲置资源。
用关联的 50 道题库做模拟复习:限时作答、分类错题,并在 24 小时、3 天和 7 天后重做。
韧性练习:加入带退避和抖动的重试、熔断器、超时和舱壁。跟踪指标、日志和链路,设置警报并定义 SLO。定期做故障转移演练。
示例
可靠性方案:对失败的支付重试三次,使用指数退避和抖动,然后打开熔断器 30 秒。用共享 request_id 追踪请求,当 p99 延迟超过 500 毫秒时告警。
安全:使用 TLS,通过网关认证,把密钥存放在密钥管理服务中,并对登录端点限流。
示例:依赖失败时返回过期缓存而不是 500,并在日志中记录降级。