综合练习
设计 CodeRoadMap 只读 API 的高可用架构草图。
综合练习
这一课你将能做到
- 独立完成一份完整系统设计答卷:「判题平台支撑 10 万日活」从澄清到深挖 45 分钟闭环
- 产出三阶段演进路线(现状 → 10× → 100×),每阶段写清改动、预期容量、代价与风险
- 用面试官的评分表给自己的设计打分,并完成一轮同伴互审
为什么要学
前 11 课的每个概念(估算、CAP、负载均衡、缓存、消息、分片、网关、云模式、可靠性、反模式)都是零件,这道综合题是把零件装成整机——面试就是这么考的,技术方案评审也是这么写的。
人话:学零件时你是修理工,这道题让你当总工程师。总工程师的标志不是会用所有零件,而是知道每一步的代价、每条路径的故障行为、每个假设的验证方法。
先建立图像
题目(模拟面试原题):
背景:本站在线判题/学习平台,现状单体 Spring Boot 3.5 + MySQL 8,
2 个 API 实例 + 1 台判题机,无 Redis、无 Kafka、Nginx 单层。
现状:峰值 800 QPS,P99 450ms,判题排队高峰 5 分钟。
目标:推广活动后 10 万日活;比赛场景瞬时提交 500 QPS 持续 1 分钟;
SLA 99.9%,判题结果查询 P99 < 300ms,允许排行榜分钟级延迟。
第一反应必须是澄清与估算(第 1 课四步法):
| 项 | 假设 | 推导 | 结论 |
|---|---|---|---|
| 浏览流量 | 人均 30 页/天 | 300 万/天 | 峰值 ~175 QPS |
| 提交流量 | 人均 5 次/天 | 50 万/天 | 峰值 ~30 QPS,比赛瞬时 500 QPS |
| 判题并发 | 10s/次 | 30 QPS × 10s | 300 并发槽,判题机 ≥ 30 台核 |
| 读写比 | 看题为主 | — | 9:1,读路径是优化主战场 |
| 存储 | 2KB/条 | 50 万/天 | 1GB/天,一年 365GB → 100 天单表触顶 |
关键结论先行:浏览量不大(单机都能扛),真正的三座山是判题吞吐、比赛洪峰、提交表增长。设计要对着这三座山打。
跟着做
步骤 1:画目标架构图(每条线标注流量)
浏览器
│
CDN(静态资源 + 题目描述)
│
Nginx L7(限流 + 路由 + 探活) ← 第 4 课
│
┌─────────────┼──────────────┐
│ │ │
题目服务×2 提交API×3 查询API×3 ← 无状态,水平扩展
│ │ │
│ Kafka judge-task │ ← 第 6 课,24 分区
│ │ │
│ 判题机池 ×N(沙箱) │ ← CPU 密集独立池
│ │ │
└──── Redis ──┴──── MySQL ───┘
题目缓存 主从 + 提交表分片 ← 第 5/7 课
排行榜ZSet
标流量:CDN 承接 70% 浏览 → Nginx 进 175 QPS → 提交 API 30 QPS 写库+发消息 → 判题机池 ≥100 QPS 消费能力 → 查询 API 读 Redis 95% 命中、5% 回源从库。
步骤 2:逐组件写清「它解决什么 + 挂了怎么办」
每个组件两句话过审,这是评审与面试的通用纪律:
Redis:解决读路径 95% 命中(题目 JSON + 排行榜 ZSet);
挂了降级直查从库 + 读接口限流,排行榜退回 MySQL 聚合页。 ← 第 5/10 课
Kafka:解决比赛 500 QPS 洪峰削峰,积压 2.4 万条 ≈ 排队 4 分钟可见;
挂了提交降级为「写库 PENDING + 定时扫描」,提交不丢。 ← 第 6 课
判题池:解决 300 并发 CPU 槽,与 API 部署隔离(舱壁思想到物理层);
沙箱限时限内存禁网络,防恶意代码打满池。 ← 第 9 课
MySQL:读写分离 + 提交表按 userId 分 4 片 + 90 天冷热归档;
主库挂半同步切换 RPO=0、RTO 60s。 ← 第 7/10 课