Skip to content

场景设计题

场景设计题考的是综合能力:需求分析 → 核心功能 → 架构设计 → 关键细节。

答题框架

系统设计面试没有标准答案,但有一套通用的答题套路,按以下步骤展开:

  1. 需求澄清(3-5 分钟):确认核心功能、用户量级、读写比、延迟要求、一致性要求。不要急于画图,先问清楚。
  2. 容量估算:QPS、存储量、带宽、内存。粗算即可,量级对了就行。
  3. 高层架构:画出核心组件和数据流(客户端 → 网关 → 服务 → 存储 → 缓存 → MQ)。
  4. 详细设计:数据模型、API 设计、核心算法、关键流程。
  5. 瓶颈与优化:高并发怎么扛?单点怎么消除?数据怎么扩展?最终一致还是强一致?
  6. 扩展讨论:监控、容灾、灰度发布、成本优化。

Q1: 设计一个短链系统 「🟡 中级」

考察点:经典设计题,考察 ID 生成、存储、跳转。

参考答案

  • 核心功能:长链 → 短链(6-8 位)、短链 → 长链(302 重定向)。
  • 短链生成
    • 自增 ID + Base62 编码(简单高效)。
    • 分布式 ID(Snowflake)+ Base62。
    • 哈希(MD5/CRC32)+ 冲突处理。
  • 存储:短码 → 长链的映射表(Redis 缓存热点短链)。
  • 跳转:301(永久,浏览器缓存)vs 302(临时,可统计点击)。
  • 扩展:过期时间、点击统计、自定义短码。

追问延伸

  • 301 和 302 怎么选?
  • 怎么防止恶意短链?

Q2: 设计一个 Feed 流系统 「🔴 高级」

考察点:社交产品的核心场景。

参考答案

  • 推模式(Push):用户发布内容后,主动推送到所有粉丝的收件箱(写扩散)。优点:读取快;缺点:大 V 写扩散成本高。
  • 拉模式(Pull):用户访问时实时拉取关注者的内容(读扩散)。优点:写入简单;缺点:读取时聚合开销大。
  • 推拉结合:普通用户用推,大 V 用拉(访问时拉取大 V 内容)。
  • 存储:收件箱用 Redis ZSet(score 为时间戳);内容存 MySQL/HBase。
  • 分页:游标分页(避免 offset 性能问题)。

追问延伸

  • 大 V 的写扩散问题怎么解决?
  • Feed 流的排序怎么做?

Q3: 设计一个秒杀系统 「🔴 高级」

考察点:高并发场景的综合设计(详见"高并发设计"篇)。

参考答案

  • 前端:按钮防重、验证码、静态化。
  • 网关:限流、IP 黑名单、风控。
  • 服务:库存预扣减(Redis Lua)、异步下单(MQ)、一人一单。
  • 数据:库存分片、热点隔离。
  • 兜底:降级页面、排队机制。

追问延伸

  • 怎么防止机器人刷单?
  • 秒杀结束后怎么对账?

Q4: 设计一个订单超时取消功能 「🟡 中级」

考察点:延迟任务的实现。

参考答案

  • 延迟队列:RocketMQ 延迟消息、RabbitMQ TTL + 死信、Redis ZSet(score 为超时时间)。
  • 定时任务:每分钟扫描超时订单(简单但有延迟)。
  • 时间轮:Netty HashedWheelTimer(单机高效)。
  • 推荐:MQ 延迟消息(可靠、可扩展)。

追问延伸

  • 订单量大时定时任务扫描的性能问题?
  • 延迟消息的可靠性怎么保证?

Q5: 设计一个红包系统 「🔴 高级」

考察点:并发扣减、随机算法、资金安全。

参考答案

  • 发红包:预扣款(冻结金额)、生成红包记录(总金额、个数)。
  • 抢红包
    • 二倍均值算法:剩余金额 / 剩余人数 * 2 为上限,保证公平。
    • 预拆分:发红包时预先拆好每个红包的金额(存入 Redis List)。
  • 并发控制:Redis Lua 原子拆红包、数据库乐观锁。
  • 资金安全:对账机制、幂等设计、分布式事务。

追问延伸

  • 二倍均值算法怎么保证公平?
  • 红包拆完后怎么通知?

Q6: 设计一个评论系统 「🟡 中级」

考察点:高并发读写、树形结构、审核。

参考答案

  • 存储:评论表(内容、用户、时间、父评论 ID)、点赞表。
  • 读优化:热点评论缓存(Redis)、分页用游标。
  • 写优化:异步写入(MQ)、批量入库。
  • 树形结构:平铺 + 父 ID(简单)、嵌套集合(复杂查询)。
  • 审核:先审后发 / 先发后审(MQ 异步审核)。

追问延伸

  • 评论的排序怎么做?(时间 / 热度)
  • 怎么处理垃圾评论?

Q7: 设计一个通知系统 「🟡 中级」

考察点:多渠道、高并发、可靠性。

参考答案

  • 多渠道:短信、邮件、App 推送、站内信。
  • 架构:通知服务 → 渠道路由 → 各渠道网关(短信网关、邮件服务器)。
  • 高并发:异步发送(MQ)、批量发送、限流。
  • 可靠性:重试机制、失败告警、送达回执。
  • 模板管理:动态参数替换、多语言支持。

追问延伸

  • 怎么保证通知不丢失?
  • 多渠道的优先级怎么设计?

Q8: 设计一个排行榜系统 「🟡 中级」

考察点:Redis 数据结构选型、实时排序、分页查询的综合能力。

参考答案

  • 核心功能:实时积分排行榜(Top N)、用户排名查询、分页浏览。
  • 数据结构选型
    • Redis ZSet:score 存积分,member 存用户 ID,天然有序,ZREVRANGEBYSCORE 取 Top N。
    • 粒度控制:按天/周/月/总榜分别建不同的 ZSet key。
  • 实时更新:用户积分变化时 ZINCRBY 原子更新;积分来源(签到、消费等)通过 MQ 异步写入。
  • 查询优化
    • Top N:ZREVRANGE O(logN+M)。
    • 我的排名:ZREVRANK
    • 分页:游标分页(用 score 做游标,避免 offset 深分页问题)。
  • 量级与分片
    • 百万级用户单 ZSet 没问题(Redis 单 key 建议 < 100MB)。
    • 千万级以上:按用户 ID 分片到多个 ZSet,查询时合并多分片 Top N(堆/归并)。
  • 冷热分离:Top 1000 缓存在本地(Caffeine),其余走 Redis。

追问延伸

  • 相同积分怎么保证排名稳定?(score 拼接时间戳做辅助排序)
  • 百亿级用户怎么做全局排行榜?(分片 + 预聚合 + 定时快照)

Q9: 设计一个限流系统 「🔴 高级」

考察点:限流算法、分布式限流、多级防护体系。

参考答案

  • 核心功能:单机限流 + 分布式限流 + 多维度(IP/用户/接口/全局)。
  • 限流算法对比
算法原理优点缺点
固定窗口固定时间窗口内计数简单窗口边界突刺
滑动窗口滑动时间窗口内计数平滑实现略复杂
漏桶固定速率出水流量均匀无法应对突发
令牌桶固定速率发令牌允许突发实现略复杂
滑动日志记录每次请求时间戳最精确内存开销大
  • 单机限流:Guava RateLimiter(令牌桶)、Semaphore(并发数限制)。
  • 分布式限流
    • Redis + Lua:用滑动窗口或令牌桶,Lua 保证原子性。
    • Redis-Cell 模块:原生 CL.THROTTLE 命令。
    • 网关层限流:Sentinel、Nginx limit_req。
  • 多级防护
    • CDN/WAF → IP 限流
    • 网关 → 接口限流
    • 服务 → 用户限流
    • 底层 → 熔断降级(Hystrix/Sentinel)
  • 动态规则:限流规则存配置中心(Nacos/Apollo),运行时热更新。

追问延伸

  • 滑动窗口怎么用 Redis 实现?(ZSet + ZREMRANGEBYSCORE)
  • 限流和熔断的区别?(限流是"入口控制流量",熔断是"下游故障时自我保护")

Q10: 设计一个分布式唯一 ID 生成服务 「🟡 中级」

考察点:分布式 ID 的多种方案对比、Snowflake 原理。

参考答案

  • 核心需求:全局唯一、趋势递增、高性能、高可用。
  • 方案对比
方案原理优点缺点
UUID随机生成简单、无中心无序、占空间、索引差
数据库自增AUTO_INCREMENT简单有序单点瓶颈
号段模式批量取号DB 压力小、高性能需要中心化发号器
Snowflake时间戳+机器ID+序列号高性能、趋势递增时钟回拨
Redis INCR原子自增简单高性能依赖 Redis 可用性
Zookeeper顺序节点强一致性能差
  • 推荐方案:Snowflake(高性能)+ 号段模式(高可用兜底)。
  • Snowflake 详解
    • 64 位:1 位符号 + 41 位时间戳(可用 69 年)+ 10 位机器 ID(1024 台)+ 12 位序列号(每毫秒 4096 个)。
    • 时钟回拨问题:等待回拨时间过去、用历史最大时间戳、或切换备用机器 ID。
  • 美团 Leaf:号段 + Snowflake 双 buffer,号段模式扛住性能,Snowflake 兜底高可用。
  • 百度 UidGenerator:基于 Snowflake,用环形 buffer 预生成 ID。

追问延伸

  • Snowflake 的时钟回拨怎么解决?
  • 号段模式下 DB 挂了怎么办?(双 buffer 预加载,一个用完切另一个)

Q11: 设计一个 IM 聊天系统 「🔴 高级」

考察点:实时通信、消息可靠性、多端同步、群聊扩散。

参考答案

  • 核心功能:单聊、群聊、消息推送、多端同步、已读回执、离线消息。
  • 通信协议:WebSocket(长连接,浏览器友好)/ TCP 长连接(移动端)。
  • 架构分层
    • 接入层:长连接网关(百万并发),负责连接管理和消息路由。
    • 逻辑层:消息处理(路由、存储、推送)。
    • 存储层:消息存储(MySQL/HBase)+ 离线消息(Redis)。
  • 消息流转
    1. 发送方通过长连接发消息到网关。
    2. 网关路由到消息服务。
    3. 消息服务存储消息(持久化)。
    4. 消息服务查接收方在线状态。
    5. 在线 → 推送到接收方网关 → 接收方;离线 → 存离线消息 + APNs/FCM 推送。
  • 消息可靠性
    • 客户端:发送 → 等待 ACK → 超时重发。
    • 服务端:存消息后才推,推失败存离线。
    • 消息 ID 去重(幂等)。
  • 群聊设计
    • 写扩散(Push):消息写入每个成员的收件箱(小群适用)。
    • 读扩散(Pull):消息写入群的timeline,成员拉取(大群适用)。
    • 混合:小群写扩散,大群读扩散。
  • 多端同步:每个设备维护一个本地 sequence,服务端按 sequence 增量推送。

追问延伸

  • 百万群聊的消息扩散怎么优化?
  • 消息的"已读回执"怎么设计不影响性能?

Q12: 设计一个搜索系统 「🔴 高级」

考察点:ES 倒排索引、分词、相关性排序、搜索架构。

参考答案

  • 核心功能:全文搜索、高亮、分类过滤、排序、聚合统计。
  • 技术选型:Elasticsearch(倒排索引 + 分词 + 相关性打分)。
  • 索引设计
    • 分词器:中文用 IK 分词器(ik_smart 粗粒度、ik_max_word 细粒度)。
    • 字段映射:keyword(精确匹配,不分词)vs text(全文搜索,分词)。
    • 多字段:同一字段既分词搜索又精确匹配(field + field.keyword)。
  • 查询优化
    • 全文搜索:match / multi_match
    • 精确过滤:term / terms(用 filter,不参与打分,可缓存)。
    • 组合查询:bool(must / should / filter / must_not)。
    • 高亮:highlight
  • 架构
    • 数据同步:Canal 订阅 MySQL binlog → MQ → ES 同步(近实时)。
    • 索引别名:零停机重建索引(新索引建好 → 切换别名 → 删旧索引)。
    • 深分页:search_after 替代 from + size(避免 deep paging 性能问题)。
  • 相关性优化
    • function_score:结合销量、评分、时间衰减做业务排序。
    • 自定义打分脚本。

追问延伸

  • ES 的深度分页为什么慢?(coordinate node 需要合并所有 shard 的结果排序)
  • 怎么实现"搜索建议"(自动补全)?(completion suggester / edge ngram)

Q13: 设计一个日志系统 「🔴 高级」

考察点:日志采集、存储、查询、告警的完整链路。

参考答案

  • 核心功能:日志采集、实时查询、告警、可视化大盘。
  • 架构(ELK / EFK)
    • 采集层:Filebeat / Fluentd / Vector(轻量 agent 部署在每个机器)。
    • 缓冲层:Kafka(削峰填谷,防日志暴增打爆 ES)。
    • 处理层:Logstash / Fluentd(过滤、解析、富化)。
    • 存储层:Elasticsearch(全文搜索 + 聚合分析)。
    • 展示层:Kibana / Grafana(可视化、仪表盘、告警)。
  • 日志类型与索引策略
    • 按天建索引(logs-2026.08.23),便于按时间范围查询和删除过期索引。
    • 不同日志类型分不同索引模板(access log、error log、业务 log)。
    • ILM(Index Lifecycle Management):热-温-冷-删,自动管理索引生命周期。
  • 采集可靠性
    • Filebeat 有 ack 机制,至少一次送达。
    • Kafka 作为缓冲,ES 不可用时日志不丢。
  • 查询优化
    • 缩小时间范围(ES 按时间分片,时间范围小查的分片少)。
    • 用 keyword 过滤代替 text 搜索。
    • 大范围聚合用 datafeed + transform 预计算。
  • 告警:ES Watcher / Kibana Alerting / Grafana Alerting。

追问延伸

  • ES 存日志太贵怎么办?(冷数据归档到 S3/OSS,用可搜索快照)
  • 怎么防止日志暴增打爆系统?(Kafka 削峰 + ES 背压 + 采样降级)

Q14: 设计一个文件上传和下载系统 「🟡 中级」

考察点:大文件处理、断点续传、秒传、分布式存储。

参考答案

  • 核心功能:文件上传、下载、断点续传、秒传、分片上传。
  • 小文件上传
    • 前端上传 → 后端接收 → 存对象存储(OSS/S3/MinIO)→ 返回 URL。
  • 大文件分片上传
    1. 前端计算文件 MD5,请求服务端检查是否已存在(秒传)。
    2. 不存在 → 文件分片(如每片 5MB)→ 并发上传分片。
    3. 服务端记录已上传分片(断点续传:中断后查已上传分片,只传缺失的)。
    4. 全部分片上传完 → 通知服务端合并分片。
  • 断点续传
    • 前端上传前请求服务端获取已上传分片列表。
    • 只上传缺失的分片。
    • 用分片 MD5 校验完整性。
  • 秒传
    • 文件 MD5 作为唯一标识,已存在则直接返回 URL,不重新上传。
  • 存储
    • 对象存储(OSS/S3/MinIO):海量文件、按量计费、CDN 加速。
    • 分片直接存对象存储,最后用 CompleteMultipartUpload 合并。
  • 下载
    • 小文件直接下载。
    • 大文件支持 Range 请求(断点下载)。
    • 私有文件用预签名 URL(有时效性)。

追问延伸

  • 大量并发上传同一个文件怎么处理?(MD5 去重 + 分布式锁防并发写入)
  • 怎么保证上传的文件不含恶意内容?(文件类型校验、病毒扫描、内容审核)

Q15: 设计一个抢红包/优惠券发放系统 「🔴 高级」

考察点:高并发扣减、库存防超卖、公平性、资金安全。

参考答案

  • 核心功能:发券/发红包 → 抢券 → 核销/使用 → 对账。
  • 发券阶段
    • 运营创建活动,预生成券码批次(批量写入 Redis + DB)。
    • 优惠券总量存 Redis(库存计数器)。
  • 抢券阶段(核心高并发)
    • 前置校验:用户限流(一人一张)、活动时间校验、风控(黑名单、设备指纹)。
    • 库存扣减:Redis Lua 原子扣减(GET → 判断 → DECR → 记录用户),保证不超卖。
    • 异步落库:扣减成功后发 MQ,异步写入 DB(券记录、用户券表)。
    • 降级:Redis 挂了 → 降级到 DB 限流模式(串行扣减,性能差但保安全)。
  • 库存防超卖
    • Redis Lua 脚本:判断 + 扣减原子执行。
    • 兜底:DB 乐观锁(UPDATE coupon_stock SET remain = remain - 1 WHERE id = ? AND remain > 0)。
  • 公平性
    • 先到先得(Redis 排队)。
    • 防刷:一人一券(Redis SETNX 标记)、IP 限流、设备指纹。
  • 资金安全
    • 优惠券和红包涉及金额 → 对账机制(每日核对发放量和核销量)。
    • 幂等设计(券码唯一、操作去重)。
    • 审计日志(谁发的、谁抢的、谁核销的)。

追问延伸

  • Redis 挂了怎么办?(DB 乐观锁兜底 + 限流降级)
  • 券码被预测/遍历怎么防?(随机券码 + 短时效 + 防枚举)