主题
界面
主题
系统设计题考的不是「你背过多少架构图」,而是结构化思考 + 用数字做决策 + 会说权衡。
★ 本节把 《高并发系统设计》 的方法论做成演练器:对两道经典题生成带真实计算的答题骨架 ✓✓:
短链服务:写 58 QPS / 读峰值 2894 QPS、存储 ≈ 170 GB/年、缓存 ≈ 1.9 GB
→「读峰值 < 3000 QPS → 单库 + 缓存就够,不要过度设计」✓✓
秒杀系统:10 万请求 / 60 秒 = 1667 QPS、1000 件 → **99% 流量必须在到达数据库前挡掉** ✓✓★ 工具:python -X utf8 scripts/career/system_design_drill.py ✓
★ 系统设计题的三个常见死法 ✗✗:
| 死法 | 表现 |
|---|---|
| 上来就画架构图 ✗✗ | 不澄清需求,画的东西可能完全不对路 |
| 只报组件名 ✗✗ | 「用 Redis、用 Kafka」——不说为什么、不估量级 |
| 没有权衡 ✗✗✗ | 说不出「为什么不选另一个」,被判定为背答案 |
★★ 破解方式 ✓✓✓:澄清 → 计算 → 画数据流 → 给权衡 —— 其中「计算」是本知识库与其他资料的差异点(《高并发系统设计》 的 M/M/1 曲线直接解释了压测拐点)✓✓。
| 步骤 | 时间 | 要点 |
|---|---|---|
| ① 澄清 | 30-60 秒 | 把需求变成可计算的假设(读写比、量级、一致性要求)✓ |
| ② 容量 | 2 分钟 | 算 QPS / 存储 / 缓存,用数字选方案 ✓✓ |
| ③ 高层设计 | 5 分钟 | 画数据流(写入路径 / 读取路径),先不抠细节 ✓ |
| ④ 深挖与权衡 | 剩余时间 | 面试官挑点,你给方案对比与取舍 ✓✓✓ |
【第 2 步:容量估算】
写入:日活 1,000,000 × 每人 5 条 = 5,000,000/天 → 平均 58 QPS,峰值(×5)289 QPS
读取:50,000,000/天 → 平均 579 QPS,峰值 2894 QPS
存储:5,000,000/天 × 365 天 × 100B ≈ 170.0 GB/年
缓存:热点 20% × 日读 50,000,000 × 200B ≈ 1.9 GB
★ 数字先给「量级」,再据此选方案:读峰值 < 3000 QPS → 单库 + 缓存就够,不要过度设计 ✓✓
【第 3 步:高层设计】
写入路径:请求 → 发号器(唯一 ID)→ Base62 编码 → 写 MySQL(短码唯一索引)→ 写缓存
读取路径:请求 → 布隆过滤器(防穿透)→ Redis → MySQL → 回填缓存
【第 4 步:深挖与权衡】
- 短码生成:自增 ID 转 62 进制(可预测)vs 雪花/号段 + Base62(扩展好、不可预测)
- 碰撞处理:唯一索引 + 重试,还是预生成?
- 301 vs 302:301 被浏览器缓存 → 省流量但丢统计;**302 保统计,选它** ✓
- 热点 key:本地缓存 + 多级;短链雪崩:TTL 随机 ✓([S4-008](../../04-advanced/redis/S4-008))★ 素材映射(面试可直接引) ✓✓✓:S6-015 发号器与时钟回拨|S4-008 缓存三病|S3-003 索引|S6-016 容量与限流 ✓。
【容量估算】
峰值请求:10 万请求 / 60 秒 ≈ 1667 QPS(瞬时更高)
有效成交:1000 单 → **99% 的流量必须在到达数据库前被挡掉** ✓✓
【高层设计:分层漏斗】
静态化(CDN)→ 网关限流 → 缓存预扣(Redis 原子扣减)→ MQ 削峰 → 数据库落单
每一层把量级降一个数量级:10 万 → 1 万 → 1000(真实成交)
【深挖与权衡】
- Redis 预扣与数据库一致性:**条件 UPDATE 兜底 + 对账**([S6-014](../../06-java-deep/distributed/S6-014))✓✓
- 少卖 vs 超卖:**宁可少卖(可补),不可超卖(赔付)** ✓✓✓
- 限流:**令牌桶**(允许蓄力突发)而不是固定窗口(临界双倍)✓✓★★★ 本节的「杀手锏」:把实测数据讲成证据 ✓✓✓:
空说法:「我们做过秒杀,用了 Redis 和 MQ」✗
有数据:「压测发现拐点在并发 ×64:QPS 只 +25% 而 P99 涨 36 倍;
定位为池化资源与缓存击穿后,改用 Redis 预扣 + 消息削峰,超卖为 0」✓✓✓
更狠的:能解释「并发 ×64 而 QPS 不涨」是**排队论**现象(ρ→1 时延迟爆炸)✓✓✓★ 为什么这是杀手锏 ✓✓:普通候选人证明「我知道」,你证明「我验证过」 —— 面试官对「一手数据」的信任度远高于「二手结论」 ✓✓✓。
| 纪律 | 说明 |
|---|---|
| 先说结论,再说理由 ✓ | 面试官在听结构,不是听你推导 |
| 每个方案都给「为什么不选另一个」 ✓✓ | 权衡 = 设计能力 |
| 主动引用项目实测数据 ✓✓✓ | 把知识库的实测变成你的证据 |
✗ 不澄清就画图(需求假设全错)
✗ 只报组件名(无理由、无数字)
✗ 细节过早(一上来讨论 Redis 参数,没讲数据流)
✗ 不会收尾(时间到了,容灾/监控/演进一句没提)
✗ 被追问就改口(**应该给出对比:什么情况下选 A、什么情况下选 B**)✓✓# 编辑 scripts/career/system_design_drill.py:加一个函数
def your_problem() -> None:
dau = 300_000
...
# 在 main() 里调用★ 通用模板 ✓✓:澄清清单 → 参数化估算 → 两条数据流 → 三组权衡 → 素材映射 ✓。
QPS = 日请求数 / 86400;峰值 = 平均 × (3~5)
存储 = 日新增 × 保留天数 × 单条大小
缓存 = 热点比例 × 日读 × 单条大小
并发 = QPS × RT(Little 定律,[S6-016](../../06-java-deep/architecture/S6-016))「我们用了高并发架构」✗✗(问了就知道没数据)
→ 改成:「峰值 1667 QPS、99% 流量在库前被挡、压测拐点定位在并发 ×64」✓✓✓工具:scripts/career/system_design_drill.py
运行:
python -X utf8 scripts/career/system_design_drill.py实测输出(节选):
===== 题 1:设计一个短链服务(如 t.cn)=====
写入:日活 1,000,000 × 每人 5 条 = 5,000,000/天 → 平均 58 QPS,峰值(×5)289 QPS
读取:50,000,000/天 → 平均 579 QPS,峰值 2894 QPS
存储:5,000,000/天 × 365 天 × 100B ≈ 170.0 GB/年
缓存:热点 20% × 日读 50,000,000 × 200B ≈ 1.9 GB
===== 题 2:设计一个秒杀系统 =====(你可能有真实数据)
峰值请求:10 万请求 / 60 秒 ≈ 1667 QPS(瞬时更高)
有效成交:1000 单 → **99% 的流量必须在到达数据库前被挡掉** ✓✓| # | 错误 | 说明 |
|---|---|---|
| 1 | 不澄清就开画 ✗✗ | 假设错了,后面全错 ✓✓ |
| 2 | 估算全靠感觉 ✗✗ | 用公式,量级对就行 ✓✓ |
| 3 | 只报组件不说权衡 ✗✗✗ | 背答案的气息 ✓✓ |
| 4 | 细节过早 ✗ | 先数据流,后参数 ✓ |
| 5 | 没有收尾(容量/容灾/监控/演进) ✗ | 收尾体现系统性 ✓ |
| 6 | 不敢说「不确定」 ✗ | 正确的姿势:给假设 + 给验证方式 ✓✓ |
system_design_drill.py,对着骨架口述一遍并录音 ✓✓✓;验收方式:任一经典题,能 15 分钟内完成「澄清 → 估算 → 数据流 → 三组权衡」。
扩展任务:把「项目 B」写成一道系统设计题的参考答案(含实测数据与取舍),作为面试的固定弹药 ✓✓✓
《模拟面试与面试复盘》 模拟面试与面试复盘 —— 把前面所有准备合成一次完整演练。
暂无