系统设计 面试题
系统设计面试评估你如何界定模糊问题并在规模上权衡利弊。没有唯一正确答案——面试官希望看到清晰的结构化方法。
系统设计 面试涵盖内容
需求与范围
在设计之前明确功能性和非功能性需求。
估算
粗略估算流量、存储和带宽以证明决策的合理性。
概要设计
API、数据模型、核心组件及其间的数据流。
扩展与权衡
缓存、分片、复制、队列、一致性 vs 可用性以及瓶颈。
系统设计 面试题示例
- 设计一个像 bit.ly 的 URL 缩短服务。好回答应覆盖
- 哈希生成与冲突处理
- 数据库选择(如MySQL或Tair)
- 重定向与缓存(Redis)
- 可扩展性与负载均衡
- 自定义短码生成策略
查看范例答案
设计URL缩短服务时,核心是生成短码并建立到原始URL的映射。可采用自增ID加Base62编码生成短码,但需考虑分布式环境下的ID生成(如雪花算法或Redis incr)。存储方面,使用关系型数据库(如MySQL)存映射关系,并通过主键索引快速查询。为应对高并发读写,引入Redis缓存热点数据,设置TTL。重定向时返回301或302,其中302更便于统计点击量。为防止哈希冲突,可先检查DB中是否已存在该原始URL,若存在则返回已有短码。扩展时,将读写分离、数据库分片,并添加CDN加速短码分发。常见陷阱是忽略短码的碰撞概率,需设计冲突重试机制。
- 设计一个信息流(例如 Twitter/Instagram 时间线)。好回答应覆盖
- 推拉模式结合
- 粉丝关系存储(图数据库或Redis)
- 时间线生成和缓存
- 内容分发与热点处理
- 实时性保证(WebSocket或轮询)
查看范例答案
设计信息流系统时,典型方案是推拉结合:对于大V用户采用拉模式,普通用户采用推模式。粉丝关系可存储在Redis或图数据库中,用户发布微博后,将消息推送给在线粉丝的Timeline缓存(如Redis List)。离线用户则在登录时拉取。Timeline生成采用预计算与实时更新,通常每个用户维护一个Timeline队列,使用Redis sorted set按时间戳排序。针对热点用户,可将其粉丝拆分为多个小队列,通过异步worker推送。为减少存储成本,可设置TTL过期历史消息。常见陷阱是推送风暴,需通过削峰填谷(如消息队列)和限流控制。
- 为公开 API 设计一个限流器。好回答应覆盖
- 令牌桶/漏桶算法
- 分布式计数器(Redis + Lua)
- API网关集成
- 限流粒度(IP、用户、端点)
- 错误处理(429 Too Many Requests)
查看范例答案
为公开API设计限流器,常用令牌桶算法:每N个请求消耗一个令牌,系统以固定速率补充令牌。实现上,可使用Redis的原子操作(如Lua脚本)维护每个用户的令牌计数器,支持分布式限流。限流粒度可基于IP、用户ID或API Key,对敏感端点可设置单独配额。响应头返回X-RateLimit-Remaining和Retry-After字段,超出时返回429状态码并拒绝请求。为防止单点瓶颈,限流逻辑应部署在API网关层。常见陷阱是时钟漂移和竞态条件,Redis的WATCH或Lua可保证原子性。若需更精确,可改用滑动窗口算法(如Redis sorted set或滑动日志)。
- 设计一个支持群聊和已读回执的聊天系统。好回答应覆盖
- 消息模型(群组成员与消息表分离)
- 已读回执存储(用户-消息状态表)
- 消息同步(pull vs push)
- WebSocket连接管理
- 离线消息与持久化
查看范例答案
支持群聊和已读回执的聊天系统,核心是消息存储和状态管理。消息表设计为(groupId, messageId, senderId, content, timestamp),按groupId分区。已读回执可使用用户-消息状态表(userId, groupId, lastReadMessageId),或记录每条消息的已读用户列表。对于已读回执的实时推送,可通过WebSocket发送标记已读的事件。消息同步采用推拉结合:在线用户通过WebSocket实时推送,离线用户登录后拉取未读消息。群聊消息写入时可批量拷贝到每个用户的收件箱(写扩散),但大型群组需改为读扩散。常见陷阱是已读回执的存储膨胀,可仅记录每个用户最后读取的消息ID而非逐条记录。
- 如何将服务从 1k 用户扩展到 10M 用户?好回答应覆盖
- 架构演进:单体→微服务
- 数据库读写分离与分片
- 缓存引入(Redis多级缓存)
- 异步处理与消息队列
- 监控与容量规划
查看范例答案
从1k用户扩展到10M用户,需要分阶段重构。初期单体应用即可,1k用户时使用单数据库,可能单机部署。到10k用户,引入Redis缓存和数据库读写分离,前端加负载均衡。达到100万用户,需将服务拆分为微服务(如用户、内容、支付),数据库按业务分片(水平分库),使用消息队列解耦异步任务(如通知、日志)。到10M用户,引入内容分发网络(CDN)缓存静态资源,数据库进一步分片(一致性哈希),使用NoSQL(如Cassandra)处理高写入。缓存方面,使用多级缓存(本地cache + Redis),并预计算热点数据。监控系统(如Prometheus + Grafana)追踪每个组件的瓶颈。常见陷阱是过早优化,应基于数据驱动,逐步扩展。
- 设计一个高可用的分布式键值存储。好回答应覆盖
- 一致性哈希环及虚拟节点
- Quorum机制(N/R/W)
- 向量时钟或版本号解决冲突
- 故障检测与自动恢复
- CAP权衡:最终一致性
查看范例答案
设计高可用分布式键值存储,参考Dynamo架构。使用一致性哈希环分布数据,每个键存储在多个节点(如N=3)上。读和写操作需达到R和W的Quorum(如R=2, W=2)来平衡一致性与可用性。为应对节点故障,引入虚拟节点实现负载均衡,并利用Gossip协议进行故障检测。对于冲突解决,可使用向量时钟检测并发写入,并允许应用层通过最后写入赢(LWW)策略合并。持久化方面,每个节点使用LSM-Tree(如LevelDB)或Bitcask提供高写入吞吐。为降低延迟,可增加Hinted Handoff机制,在节点恢复后重放数据。常见陷阱是忽略部分写入导致的脏读,需结合读修复和反熵机制。
如何准备
- 始终从明确需求和约束开始——不要直接跳到解决方案。
- 使用可重复的框架:需求 → 估算 → API → 数据模型 → 扩展 → 权衡。
- 明确陈述权衡(例如一致性 vs 可用性);很少有唯一正确答案。
- 主导对话并管理时间——先覆盖广度,然后在被问及的地方深入。
常见问题
如何准备系统设计面试?
学习可重复的框架,研究几个经典设计(信息流、聊天、URL 缩短、限流),并练习大声讨论权衡。
需要了解特定技术吗?
了解基础组件(负载均衡器、缓存、队列、SQL vs NoSQL、分片)及其权衡。说出具体产品名称不如推理重要。
最常见的错误是什么?
没有明确需求或进行估算就直接开始设计,并且没有陈述权衡。
系统设计只针对高级岗位吗?
最常见于中高级岗位,但初级候选人可能会遇到关注单个组件的简化版本。
练习 系统设计 题目,即时获取 AI 反馈
上传简历,获得个性化模拟面试,并了解需要改进的地方——免费开始。