适用读者:冲架构师/技术专家面,要答"设计一个 XX"的人。
前置:S17(分布式)、S18(架构)、S25-J12(高可用);J02(场景题框架)。
覆盖旧文:3472/3473/3483/3488/3494/3495/3497/3498/3499/3502/3503/3504/3505→ 13 篇 / 约 13 万字符。
扩展点:E-S25-041(设计题的 4 步骨架与容量估算公式)、E-S25-042(限流器三种算法与阈值怎么定)、E-S25-043(读写比例决定架构:短链/排行榜/直播评论)。
下一篇:S25-J14 · Go 语言题库。
1. 一句话结论
设计题没有标准答案,只有"约束下的取舍"。 高分答法四步:估算规模 → 找瓶颈 → 给两三个方案比代价 → 说失效与回滚。跳过估算直接画架构,是新手最典型的特征。
出处:
A-3497(百万 QPS 限流器)、A-3504(十亿短链)、A-3472(百万在线评论)、A-3498(限流阈值)、A-3503(1 秒响应)等。
2. 四步骨架与估算公式(E-S25-041)
① 规模:DAU → QPS(峰值 = 均值 × 3~5)→ 存储/带宽
② 瓶颈:CPU/IO/连接数/单 key 热点/数据库写
③ 方案:至少两个,比代价(复杂度、成本、一致性)
④ 失效:降级、限流、回滚、监控指标
必背估算:
| 量 | 公式 |
|---|---|
| QPS | DAU × 每人请求数 / 86400,峰值再 ×3~5 |
| 存储 | 条数 × 单条字节 × 副本数 × 增长年限 |
| 带宽 | QPS × 平均响应字节 |
| 连接数 | QPS × 平均 RT(s)(Little 定律) |
| 缓存容量 | 热数据条数 × 单条字节 × 1.5(留碎片余量) |
示例(短链 10 亿条):
短码 7 位 Base62 → 62^7 ≈ 3.5 万亿,够用
单条:短码 7B + URL 平均 100B + 元数据 40B ≈ 150B
10 亿 × 150B ≈ 150 GB(单副本)→ 3 副本 450 GB
写 QPS:假设每天新增 100 万 → 均值 12/s,峰值 60/s(很轻)
读 QPS:读写比 100:1 → 1200/s 均值,峰值 6000/s(重点在缓存)
判据:先算清"读多还是写多",架构自然分岔。 短链读多 → 缓存 + CDN;直播评论写多 → 分片 + 异步扇出。
3. 限流:三种算法与阈值(E-S25-042)
| 算法 | 实现 | 优点 | 缺陷 |
|---|---|---|---|
| 固定窗口 | 每分钟计数 | 最简单 | 临界点双倍流量 |
| 滑动窗口 | 分桶/Redis ZSet | 平滑 | 内存/ZSet 开销 |
| 令牌桶 | 匀速放令牌,允许突发 | 允许一定突发 | 参数要调 |
| 漏桶 | 匀速流出 | 绝对平滑 | 不允许突发,浪费容量 |
阈值怎么定(最高频追问):
① 压测求单机容量(不是拍脑袋)
② 集群阈值 = 单机容量 × 实例数 × 0.7(留 30% 余量)
③ 按接口分级:核心 0.8、非核心 0.5
④ 动态调整:按 RT/错误率自动降阈(自适应限流,如 Sentinel 系统规则)
百万 QPS 限流器:单机内存限流(令牌桶)+ 网关分布式限流(Redis Lua 固定窗口/滑动窗口)双层;Redis 侧用分片 key 避免单 key 热点;本地桶承担 90% 流量,Redis 只做全局配额。
判据:限流器本身不能成为瓶颈——用本地计数器兜底,Redis 只做"总量管控"。
4. 三类读写特征不同的系统(E-S25-043)
4.1 短链(读多写少)
写:发号器(Redis INCR / 号段 / Snowflake 截断)→ Base62 → 落库
读:CDN/LocalCache → Redis → DB;302 跳转
热点:短码不可枚举 → 加盐/随机化;防刷 → 频控
一致性:写后读主 + 缓存双删(见 J10)
4.2 排行榜(写多读多、要排序)
| 方案 | 适用 |
|---|---|
| Redis ZSet | 千万级以内,ZINCRBY + ZREVRANGE,天然有序 |
| 分桶 + 合并 | 亿级:按 hash 分桶,查询时合并 TopN |
| 离线批 + 在线增量 | 强实时排行榜:离线全量 + 在线增量覆盖 |
边界:ZSet 单 key 过大(>1 万成员)操作会变慢 → 分桶是必答点。
4.3 直播评论(写多、要扇出、要顺序)
接入层:WebSocket 长连接(心跳 + 断线重连),单机连接数受 fd/内存限制
写入:消息队列削峰 → 分片存储(按 room_id 分区)
扇出:在线用户走推送(按房间订阅),离线用户拉取历史
顺序:同一房间内保序(分区键 = room_id)
限流:每用户发送频率 + 房间总量
百万在线估算:单机 10 万连接需 ~1 GB 级内存 + 调 ulimit/somaxconn;100 万在线 ≈ 10~20 台接入机。
5. 稳定性三题:降级、下游不稳、1 秒响应
| 题 | 答法 |
|---|---|
降级策略怎么选(A-3483) |
按"核心/非核心 × 可缓存/不可缓存"分级;优先关非核心、返回静态/默认值、切只读、限流队列;降级要能一键开关且可演练 |
下游接口不稳(A-3502) |
超时(分层:连接/读/总)+ 重试(指数退避 + 抖动 + 上限)+ 熔断 + 隔离(线程池)+ 兜底数据 |
1 秒内响应(A-3503) |
拆解 RT 预算:网关 20 ms / 业务 200 ms / 缓存 5 ms / DB 50 ms;找最大项优化;并行化独立调用;重活异步化 |
RT 预算表是加分项——把"1 秒"拆成每段预算,才知道该优化谁。
6. 迁移与容量:两个高频"非功能题"
6.1 旧库平滑迁到新库(A-3473)
① 双写(新+旧)→ 校验 → 切读(灰度)→ 停旧写 → 清理
② 数据同步:全量(快照)+ 增量(binlog 订阅)
③ 一致性校验:抽样比对 + 计数/checksum 对账
④ 回滚:保留旧库只读 N 天 + 切回开关
判据:"双写 + 灰度切读 + 可回切"是唯一稳妥路径;一次性割接只在停机窗口可用。
6.2 分库分表容量预估(A-3474)
单表行数上限:经验 500 万~2000 万(看行宽与索引)
分片数 = 预估总行数 / 单表上限,向上取 2 的幂(便于扩容与路由)
分片键:高基数 + 查询必带(用户 ID),避免跨片查询
扩容:成倍扩(2^n),用一致性哈希或双倍分片迁移
7. 反例:五种"画得很漂亮但会挂"的答案
| 说法 | 问题 |
|---|---|
| "上 Kafka 削峰" | 没说消费能力与积压策略;队列会成新瓶颈 |
| "用 Redis 存所有热数据" | 单 key 热点、内存成本、持久化代价未算 |
| "分库分表解决一切" | 跨片查询/事务/聚合代价剧增 |
| "加机器就行" | 受分区数/单 key/DB 连接数限制 |
| "用一致性哈希就无痛扩容" | 仍有数据迁移与热点不均 |
8. 自测
- 四步骨架?QPS 与连接数的估算公式?
- 限流四算法?阈值怎么定?
- 短链、排行榜、直播评论三者的架构分岔点各是什么?
- 旧库迁移的稳妥路径与回滚条件?
- 分片数为什么要取 2 的幂?
答案
- 估算/瓶颈/方案/失效;
DAU×请求/86400、QPS×RT。 - 固定窗口/滑动窗口/令牌桶/漏桶;压测单机容量 ×0.7 × 实例数,分级设定。
- 短链读多→缓存;排行榜要排序→ZSet+分桶;直播评论写多+扇出→MQ+分片+推送。
- 双写 → 校验 → 灰度切读 → 停旧写;保留旧库可回切。
- 便于成倍扩容与路由计算(取模/位运算),减少迁移量。
9. 下一篇
S25-J14 · Go 语言题库 —— 与 Java 的对照:GMP 调度、channel 与 select、GC 三色标记、连接池耗尽排查。
本篇属于系列《S25 · 求职与面试》。旧文来源:A-3472/3473/3483/3488/3494/3495/3497/3498/3499/3502/3503/3504/3505;扩展点 E-S25-041/042/043。容量数字为按公式估算(非线上实测)。