RSS
菜单
全部文章快讯开发科技深度热点

第 38 章 高频场景设计真题精讲

内容摘要

场景设计题考的是"把需求落成表结构和方案"——给你一个业务,你要能说出表怎么建、索引怎么加、怎么扩展。本篇精选 20 道高频场景设计题,覆盖短链、秒杀、Feed 流、计数器、分布式 ID、缓存、评论、分布式锁、多租户、附近查询、对账、滑动窗口限流等。前置知识:第 9、17、18、23、26 章;本系列示例基于 MySQL 8.0。

📖 本篇简介:场景设计题考的是"把需求落成表结构和方案"——给你一个业务,你要能说出表怎么建、索引怎么加、怎么扩展。本篇精选 20 道高频场景设计题,覆盖短链、秒杀、Feed 流、计数器、分布式 ID、缓存、评论、分布式锁、多租户、附近查询、对账、滑动窗口限流等。前置知识:第 9、17、18、23、26 章;本系列示例基于 MySQL 8.0。

目录

  • 1 场景设计答题框架
  • 题目 1:设计一个短链接系统
  • 题目 2:设计一个秒杀库存系统
  • 题目 3:设计一个Feed时间线
  • 题目 4:设计一个关注关系表
  • 题目 5:设计一个点赞计数器
  • 题目 6:设计订单分库分表方案
  • 题目 7:设计一个优惠券系统
  • 题目 8:设计分布式ID生成
  • 题目 9:设计MQ与DB双写方案
  • 题目 10:设计一个热点数据缓存
  • 题目 11:设计一个评论系统
  • 题目 12:设计一个分布式锁
  • 题目 13:设计一个多租户SaaS库
  • 题目 14:设计附近的人查询
  • 题目 15:设计一个对账系统
  • 题目 16:设计大报表聚合查询
  • 题目 17:设计定时任务调度表
  • 题目 18:设计数据归档方案
  • 题目 19:设计多数据源路由
  • 题目 20:设计滑动窗口限流
  • 速查速记
  • 常见坑与注意事项
  • 复习清单
  • 练习题

1 场景设计答题框架

场景设计别一上来就建表,按这个框架答:需求澄清 → 表结构 → 索引 → 扩展(缓存/分库/异步)→ 一致性与兜底。

| 步骤 | 要回答的问题 |

|---|---|

| 需求 | QPS、读写比、数据量、一致性要求 |

| 表结构 | 核心表、字段、状态机 |

| 索引 | where/order by 列、联合索引 |

| 扩展 | 缓存、分库分表、异步 |

| 兜底 | 幂等、对账、降级 |

题目 1:设计一个短链接系统

考点

  • 短码生成;映射存储。

参考答案

1. 映射表:(short_code, long_url, created_at, expire_at);

2. 短码唯一索引:short_code 主键/唯一;

3. 生成:发号器取 ID 转 62 进制,或哈希;

4. 跳转:查 long_url,302 重定向;

5. 访问统计:异步计数,不阻塞跳转。

-- 短链映射表,本示例基于 MySQL 8.0
CREATE TABLE t_short_link (
  short_code VARCHAR(16) PRIMARY KEY,  -- 短码,唯一
  long_url VARCHAR(2048) NOT NULL,
  expire_at DATETIME,
  created_at DATETIME DEFAULT NOW()
);

追问

  • 问:短码冲突?答:唯一索引 + 生成时冲突重试。
  • 问:访问量大?答:长 URL 结果挡 Redis 缓存。

题目 2:设计一个秒杀库存系统

考点

  • 防超卖;分层拦截。

参考答案

1. 前端限流 + 验证码挡机器人;

2. Redis 预扣:Lua 原子判断+扣减;

3. MQ 异步下单:DB 匀速消费;

4. DB 原子扣:WHERE stock>0 最终核对;

5. 对账:Redis 与 DB 库存定时校正。

追问

  • 问:Redis 扣了下单失败?答:失败回补 Redis,异步补偿。
  • 问:超卖兜底?答:DB 条件扣 + 对账。

题目 3:设计一个Feed时间线

考点

  • 推/拉模式;收件箱。

参考答案

1. 发件箱:用户自己发的动态;

2. 收件箱:粉丝各自的时间线;

3. 推模式:发动态写进粉丝收件箱,读快;

4. 大V 走拉模式:避免写放大;

5. 存储:收件箱缓存 + 分表,正文存 MySQL/OSS。

追问

  • 问:大V发动态?答:大V走拉模式,粉丝读时聚合。
  • 问:已读未读?答:存上次拉取时间,不存逐条。

题目 4:设计一个关注关系表

考点

  • 双向索引;唯一约束。

参考答案

1. 一行一条:(user_id, followee_id);

2. 主键 (user_id, followee_id) 防重复;

3. 反向索引 followee_id 查粉丝;

4. 好友:双向都有记录;

5. 分页:按 ID 游标。

追问

  • 问:要冗余粉丝表吗?答:高频大流量可冗余,接受异步同步。
  • 问:拉黑怎么存?答:单独关系类型字段。

题目 5:设计一个点赞计数器

考点

  • 计数高频写;合并。

参考答案

1. 点赞明细:(obj_id, user_id) 唯一,防重复赞;

2. 计数:Redis 维护点赞数,高频写;

3. 异步回写:计数定时刷 DB 汇总表;

4. 谁赞了:明细分页查;

5. 取消赞:明细删除 + Redis 减。

-- 点赞明细表,本示例基于 MySQL 8.0
CREATE TABLE t_like (
  obj_id BIGINT, user_id BIGINT, created_at DATETIME DEFAULT NOW(),
  PRIMARY KEY (obj_id, user_id)  -- 一个对象一人只赞一次
);

追问

  • 问:计数放 DB 行不行?答:高频写热点行锁,放 Redis。
  • 问:Redis 丢计数?答:定时从明细 count 重建校正。

题目 6:设计订单分库分表方案

考点

  • 分片键;路由。

参考答案

1. 按 user_id 哈希分 8/16 库;

2. 单表千万级;

3. 分布式 ID:趋势递增;

4. 商家维度:路由表/ES;

5. 扩容:双写迁移。

追问

  • 问:跨分片查询?答:避免,复杂检索走 ES。
  • 问:分片数怎么定?答:预留 2 的幂,控制单表千万内。

题目 7:设计一个优惠券系统

考点

  • 模板 + 用户券;库存。

参考答案

1. 模板表:面额、库存、有效期;

2. 用户券表:谁领了、状态;

3. 领券原子扣库存;

4. 一人一单:UNIQUE(user_id, tpl_id);

5. 过期定时处理。

追问

  • 问:用券幂等?答:WHERE status=未用,用过不能再用。
  • 问:超发?答:库存条件扣 + 对账。

题目 8:设计分布式ID生成

考点

  • 全局唯一;趋势递增。

参考答案

1. 号段模式:DB 一段段取,简单;

2. 雪花算法:时间戳+机器+序列,本地生成;

3. 时钟回拨:记录上次时间,回拨报错/等待;

4. 趋势递增:B+ 树顺序插入;

5. 高可用:号段库主从,雪花多机房机器位隔离。

追问

  • 问:雪花机器位怎么分配?答:ZK/配置中心分配,避免冲突。
  • 问:号段缺点?答:号段库是单点(主从兜底)。

题目 9:设计MQ与DB双写方案

考点

  • 本地消息表。

参考答案

1. 同事务写业务表 + 消息表;

2. 后台扫消息表投递 MQ;

3. 消费幂等:按消息 ID;

4. 失败重试 + 死信;

5. 对账兜底。

追问

  • 问:消息表和业务表不同库?答:用事务消息,不能本地事务。
  • 问:消息顺序?答:同分片有序。

题目 10:设计一个热点数据缓存

考点

  • Cache-Aside;防穿透击穿雪崩。

参考答案

1. 读:缓存 miss 查库回填;

2. 写:更库 + 删缓存;

3. 穿透:空值缓存/布隆;

4. 击穿:热点 key 互斥重建;

5. 雪崩:TTL 加随机。

追问

  • 问:先更库还是先删缓存?答:先更库再删缓存。
  • 问:删缓存失败?答:重试队列/binlog 订阅。

题目 11:设计一个评论系统

考点

  • 按对象分片;分页。

参考答案

1. 按 obj_id 分表;

2. 评论游标分页;

3. 热门评论缓存;

4. 晒图 OSS;

5. 计数冗余:comment_count。

追问

  • 问:评论数怎么统计?答:Redis 计数 + 冗余字段。
  • 问:嵌套评论?答:二级回复树状/平铺。

题目 12:设计一个分布式锁

考点

  • 加锁;释放;超时。

参考答案

1. Redis SET NX EX:加锁带过期;

2. 唯一 value:释放时校验 value 防误删;

3. Lua 原子释放;

4. 看门狗续期:业务长时自动续;

5. DB 锁:SELECT ... FOR UPDATE 也可但性能差。

-- Redis 分布式锁(伪代码)
SET lock:order:123 <uuid> NX EX 10   -- 加锁,10秒自动释放
-- 释放时Lua: if get==uuid then del

追问

  • 问:锁超时业务没执行完?答:看门狗续期。
  • 问:Redis 主从切换丢锁?答:RedLock 或接受极小概率。

题目 13:设计一个多租户SaaS库

考点

  • 隔离级别。

参考答案

1. 独立库:隔离最强、成本高;

2. 共享库独立 schema:折中;

3. 共享库共享表 + tenant_id:成本低,所有查询带 tenant_id;

4. 行级隔离:tenant_id 建索引;

5. 选型:大客户独立库,小客户共享表。

追问

  • 问:共享表怎么防串数据?答:所有 SQL 强制带 tenant_id。
  • 问:大租户影响小租户?答:资源隔离/独立库。

题目 14:设计附近的人查询

考点

  • 地理空间;Redis GEO。

参考答案

1. 实时用 Redis GEO:GEOADD/GEOSEARCH;

2. MySQL BBox 粗筛:经纬度范围 + 空间索引;

3. 精算距离:筛后 ST_Distance;

4. GeoHash 网格:查周边网格;

5. 缓存热门区域。

追问

  • 问:为什么不全 MySQL?答:全表算距离慢,实时用 GEO。
  • 问:网格跨边界?答:查自己+周围8格。

题目 15:设计一个对账系统

考点

  • 三方核对;差异处理。

参考答案

1. 权威源:以交易/流水为准;

2. T+1 全量:夜间比对;

3. 差异清单:自动输出;

4. 自动补偿:可修的自动订正;

5. 人工工单:复杂差异。

追问

  • 问:对账压在线库?答:迁从库/离线。
  • 问:差异率高?答:停自动补偿,人工查根因。

题目 16:设计大报表聚合查询

考点

  • 别在线库跑大聚合;预聚合。

参考答案

1. 别在 OLTP 跑大报表:拖垮在线;

2. 预聚合表:定时按天/维度汇总;

3. 数仓/ClickHouse:分析走列存;

4. 实时:流式预聚合;

5. 缓存结果:报表结果缓存。

追问

  • 问:非要实时?答:预聚合 + 缓存,别现算。
  • 问:预聚合表怎么建?答:按维度 group by 提前算好落表。

题目 17:设计定时任务调度表

考点

  • 状态;防重;分片。

参考答案

1. 任务表:任务 ID、状态、下次执行时间;

2. 抢占执行:UPDATE ... SET status=执行中 WHERE id=? AND status=待执行;

3. 防重:状态条件抢占;

4. 失败重试;

5. 分片:多实例按 ID 取模抢不同任务。

-- 抢占一个待执行任务,本示例基于 MySQL 8.0
UPDATE t_job SET status = 1, update_time = NOW()
WHERE id = (SELECT id FROM t_job WHERE status = 0 LIMIT 1)
  AND status = 0;  -- 条件防多个实例抢到同一任务

追问

  • 问:任务执行中宕机?答:超时扫描重置状态重新调度。
  • 问:重复执行?答:状态条件抢占天然幂等。

题目 18:设计数据归档方案

考点

  • 冷热分离;可恢复。

参考答案

1. 在线只留近 N 月;

2. 按时间分区:DROP 老分区;

3. 迁移校验后删;

4. 归档库可查;

5. 备份兜底。

追问

  • 问:DELETE 大表?答:优先 DROP 分区/分批删。
  • 问:归档后查不到?答:归档库提供只读入口。

题目 19:设计多数据源路由

考点

  • 读写分离;分片路由。

参考答案

1. 主写从读:按 SQL 类型路由;

2. 分片路由:按分片键选库表;

3. 路由层:中间件或 SDK;

4. 写后读主:一致性读走主;

5. 故障切流:从库延迟大切回主。

追问

  • 问:路由怎么实现?答:ShardingSphere 或自研动态数据源。
  • 问:跨分片?答:业务规避,复杂检索走 ES。

题目 20:设计滑动窗口限流

考点

  • 计数;窗口;Redis。

参考答案

1. 固定窗口:简单但临界突刺;

2. 滑动窗口:Redis ZSET 记录每次请求时间戳;

3. ZREMRANGEBYSCORE:清窗口外;

4. ZCARD:窗口内计数;

5. 超限拒绝。

追问

  • 问:固定窗口缺点?答:窗口边界瞬间 2 倍流量。
  • 问:更省内存?答:漏桶/令牌桶,或滑动日志近似。

速查速记

| 场景 | 核心方案 | 兜底 |

|---|---|---|

| 短链 | 短码映射表 | 唯一索引冲突重试 |

| 秒杀 | Redis预扣+MQ | DB条件扣+对账 |

| 计数器 | Redis+明细 | 定时重建 |

| 分布式锁 | SET NX EX+Lua | 看门狗续期 |

| 附近查询 | Redis GEO | BBox粗筛 |

| 限流 | ZSET滑动窗口 | 超限拒绝 |

| 报表 | 预聚合+数仓 | 别在线跑 |

| 对账 | T+1三方核对 | 差异工单 |

常见坑与注意事项

  • 坑 1:计数器直接高频写 DB——热点行锁竞争,应放 Redis 异步回写;
  • 坑 2:分布式锁不设过期——持有者宕机死锁,必须带 EX;
  • 坑 3:大报表直接在线库跑聚合——拖垮 OLTP,预聚合/数仓;
  • 坑 4:所有查询不带 tenant_id——多租户串数据;
  • 坑 5:附近查询全表算距离——慢,用 Redis GEO/BBox;
  • 注意:本题为通用场景设计,结合公开高频题型,不涉及具体公司业务。

复习清单

| 场景 | 关键 | 易错点 |

|---|---|---|

| 短链 | 短码唯一 | 跳转别阻塞 |

| 秒杀 | 分层拦截 | 别把洪峰打DB |

| 计数器 | Redis+明细 | 别高频写库 |

| 分布式锁 | NX+EX+校验value | 别误删别人锁 |

| 多租户 | tenant_id | 别漏条件 |

| 对账 | 权威源比对 | 别压在线库 |

| 归档 | 校验后删 | 别DELETE大表 |

| 限流 | 滑动窗口ZSET | 固定窗口临界突刺 |

练习题

练 1:设计一个点赞系统,要求防重复赞、能查点赞数、高并发不被热点行锁拖垮。

<details>

<summary>参考答案</summary>

点赞明细表 (obj_id, user_id) 主键唯一防重复赞;点赞计数放 Redis(INCR/DECR)抗高频写,定时从明细 count 回写 DB 汇总表;取消赞删除明细并 Redis 减计数;Redis 计数异常时用明细重建校正。

</details>

练 2:要求设计一个分布式锁,说明加锁和释放的关键细节。

<details>

<summary>参考答案</summary>

加锁:SET lock:key <唯一uuid> NX EX 10,NX 保证只有一个客户端拿到,EX 防死锁。释放:用 Lua 脚本先 GET 比对 uuid 再 DEL,避免误删别人的锁;业务执行时间可能超过锁过期时用看门狗自动续期。Redis 主从切换极端情况可能丢锁,强一致场景可用 RedLock 或接受极小概率。

</details>

下一篇预告:第 39 章 高频性能优化真题精讲

— 全文完 —回到顶部 ↑
下载推广海报

文章推广海报

《第 38 章 高频场景设计真题精讲》完整推广海报
DISCUSSION

文章回复

0 条公开回复
未登录回复需要审核后公开
还没有回复,欢迎参与讨论。