面试官说:「设计一个 1 亿 DAU 的图文 Feed(类 Instagram)。」在画任何方框之前,你得先回答一个问题:这套系统是一台机器的活,还是一千台机器的活? 答案决定架构形态——单库还是分片、同步 fanout 还是异步、缓存放多大。容量估算(capacity estimation / back-of-the-envelope)就是用几个假设和数量级常数,在 2 分钟内把 QPS、存储、带宽、内存推算到正确的 10 倍以内,从而把无数种架构砍到一两种。
它的目的不是精确——精确是压测和真实指标的事。它的目的是排除明显不可行的设计:如果算出来写入要 200 GB/s 带宽,那「单机 + 本地磁盘」的方案当场出局。先固定本期的输入假设:
50:2 = 25:1,典型读多写少——Feed/社交几乎都是。容量估算不是一团数字,而是一条有向的推导链:所有量都从 DAU 和「人均行为」两个根假设流出。下图是这条链——每个箭头是一次乘除,记住链路就不会漏算。
graph TD
DAU["DAU = 1亿
+ 人均行为假设"]
W["写请求/天
2亿"]
R["读请求/天
50亿"]
AQ["平均 QPS
÷ 1e5 s/day"]
PQ["峰值 QPS
× 峰值因子 2~3"]
ST["存储
writes × 对象大小 × 留存"]
BW["带宽
QPS × payload"]
MEM["缓存内存
热数据 × 80/20"]
DAU --> W --> AQ
DAU --> R --> AQ
AQ --> PQ
W --> ST
R --> BW
R --> MEM
classDef root fill:#2a1530,stroke:#ff7ab6,color:#e8eef5
classDef mid fill:#1a2530,stroke:#64c8ff,color:#e8eef5
classDef out fill:#0e2030,stroke:#5eead4,color:#e8eef5
class DAU root
class W,R,AQ mid
class PQ,ST,BW,MEM out
两个根假设(规模 + 人均行为)决定一切;QPS 决定算力,存储/带宽/内存决定形态
核心 trade-off:记住一小撮常数 → 心算速度,换取 ±2 倍以内的误差。 估算的地基是三组「免背公式」的数字。第一组是 2 的幂与数据单位:2^10≈10^3=KB、2^20=MB、2^30=GB、2^40=TB、2^50=PB。第二组是 时间常数:一天 ≈ 86400 ≈ 10^5 秒(这个近似让「每天 N 次」直接除以 10 万得 QPS,是估算里用得最多的一步)。第三组是 Jeff Dean 的延迟数字:它告诉你哪一步是瓶颈。
| 操作 | 量级 | 含义 |
|---|---|---|
| L1 / 内存引用 | ~1 ns / ~100 ns | CPU 本地,几乎免费 |
| 内存顺序读 1 MB | ~微秒级(µs) | 内存带宽很大 |
| SSD 随机读 | ~16 µs | 比内存慢百倍 |
| 同数据中心往返 (RTT) | ~0.5 ms | 一次 RPC 的下限 |
| 磁盘寻道 / SSD 顺序读 1 MB | ~ms 级 | 批量优于随机 |
| 跨洲往返 (CA↔NL) | ~150 ms | 光速决定,无法优化 |
核心 trade-off:用平均 QPS 估算简单,但按平均部署的系统会在高峰当场挂掉。 推导分三步:① 每天请求数 = DAU × 人均次数;② 平均 QPS = 每天请求数 ÷ 10^5;③ 峰值 QPS = 平均 × 峰值因子。峰值因子来自流量的日内不均匀——晚高峰、午休、突发热点,社交类常取 2~3×,秒杀/直播开播可达 10× 以上。
# 本期数字(1 亿 DAU)
写: 1e8 × 2 = 2e8 /day → 平均 2000 QPS → 峰值 ~5k 写 QPS
读: 1e8 × 50 = 5e9 /day → 平均 5万 QPS → 峰值 ~10万 读 QPS
读写比 ≈ 25:1 → 读路径才是设计重心(缓存、读副本、fanout)
核心 trade-off:把『元数据』和『大对象/媒体』分开估,否则一个数量级的错算会让整张表失真。 三个量各有公式,关键是选对乘子。
# 存储 = 写入量/天 × 对象大小 × 留存时长
元数据: 2e8/day × 1KB × 365 × 5年 ≈ 365 TB → 分片 + 冷热分层
媒体: 假设 30% 帖子带图, 每图 200KB
2e8 × 0.3 × 200KB ≈ 12 TB/day → 对象存储(S3)+CDN, 不进 DB
# 带宽 = 峰值 QPS × 每次响应字节
读出口: 10万 QPS × (20条 × 1KB) = 2 GB/s ≈ 16 Gbps (仅元数据)
媒体带宽走 CDN, 由边缘扛, 不压源站
# 缓存内存 = 热数据量 × 命中目标
热 timeline: 20% DAU = 2000万活跃 × 每人缓存200条id × ~50B
≈ 200 GB → 一个中等 Redis 集群放得下
核心 trade-off:估算的可信度不在于小数点,而在于假设是否被讲清、是否经得起『换个数会怎样』。 一个好的估算把每个输入数字显式写出来并标注来源:哪些是题目给的(DAU)、哪些是行业常识(读写比)、哪些是你拍的(峰值因子)。然后做敏感性检查——哪个假设错一倍会让结论翻盘?那个就是要和面试官确认、或在生产里重点监控的。
# 假设清单(estimation 的真正交付物)
DAU = 1e8 [题目给定]
帖/人/天 = 2 [假设 · 类 IG 中位用户]
刷feed/人/天 = 50 [假设 · 偏高, 是敏感项] ← 错一倍 → 读QPS翻倍
峰值因子 = 2.5 [假设 · 晚高峰经验值]
对象大小 = 1 KB [元数据, 媒体另算]
留存 = 5 年 [产品决策, 待确认]
敏感性: 读QPS 对「刷feed次数」线性敏感 → 优先核实
存储 对「留存」线性敏感 → 优先和产品确认
高频追问:① 一天大概多少秒,为什么能近似成 10^5?② 这个系统单机扛得住吗,你怎么一眼判断?③ 如果 DAU 涨 10 倍,哪个量先撑爆、架构要怎么变?④ 你这个峰值因子哪来的,错一倍结论会怎样?⑤ 存储要不要算副本和留存,怎么估冷热分层?
真实是 86400 ≈ 8.64×10^4,用 10^5 高估了约 16%。这在估算里恰好是良性的:用 10^5 当分母会让平均 QPS 偏低约 16%,但我们紧接着乘 2~3 的峰值因子,这点偏差被峰值因子的不确定性完全淹没——你对峰值因子的把握远没到 16% 的精度。所以数量级层面零影响。
它咬你的场景:当流量不是按天均摊,而是高度集中——比如一个每天只在 8 点开抢 5 分钟的秒杀。这时「÷10^5」算出的平均 QPS 毫无意义,真实瞬时 QPS = 当天总量 ÷ 300 秒,可能是「平均」的几百倍。教训:均摊到秒只在流量大致均匀时成立,集中型负载必须按实际活跃窗口做分母。
根源是读写比和放大效应叠加。其一,人均读次数(刷 50 次)天然就比写次数(发 2 条)高一个数量级。其二,一次「读 feed」在后端往往是一次请求 → 拉 N 条帖子 + 计数 + 关注关系的扇出,读放大让后端实际读操作更多。其三,写有天然上限(人一天发不了几百条),读却可以无聊地刷——产品形态决定读几乎不封顶。
所以社交/内容系统几乎全是「写库轻松、读路径吃紧」。这正解释了为什么这类系统的核心武器是缓存、读副本、预计算 timeline(fanout-on-write),而不是写分片。反例是 IoT/日志摄入——写远大于读,架构重心就完全反过来,落到 Kafka + LSM 分片写。一句话:读写比决定你往哪边堆机器。
不能直接拿 365 TB ÷ 单盘容量。要先把逻辑量放大成物理占用:① ×3 副本(高可用)→ ~1.1 PB;② 加索引、WAL/redo、碎片与预留空间,工程上常再 ×1.3~2;③ 磁盘不能填满,留 30% headroom。这样物理需求可能逼近 2 PB 量级。
再除以单机有效容量,并且瓶颈未必是容量:单台数据库节点的限制往往先到 IOPS/连接数/内存,而不是磁盘空间——一台塞 10 TB 数据但扛不住 QPS 是常态。所以正确答案是「按容量和 QPS 两个约束取较紧的那个定节点数,再 ×副本」。只报「365 TB ÷ 16 TB ≈ 23 台」是典型失分点,因为它同时漏了副本、开销和 QPS 约束。
因为架构选项之间往往差不止一个数量级,而决策只需要分辨数量级。「单机能扛 vs 要一千台」「写主库够用 vs 必须分布式存储」「数据进内存 vs 必须落盘分层」——这些分叉点之间是 10×、100× 的鸿沟,估算的 ±3 倍误差根本跨不过去,所以足够把你推到正确的那一侧。
反过来,估算不能回答的是数量级内部的精调:要 8 台还是 12 台、缓存设 50 GB 还是 80 GB——这些差异在估算精度内不可分辨,必须交给压测和生产指标。所以正确用法是:用估算选架构形态(粗决策),用压测和监控定具体容量(细决策)。把估算当精确预算用,或反过来嫌它不精确而不用,都是误用。
总用户数 1 万 × 500 = 500 万,比 C 端小两个数量级,但方法的重心要变。其一,B2B 的「人均行为」完全不同——工作时间内高频、夜间几乎为零,峰值因子更极端(工作日 9-18 点集中),但跨时区可削峰,要按租户时区分布修正。其二,关键约束从「总量」变成「单租户上限和租户间隔离」:最大租户可能比中位数大 100 倍(power-law),按平均估算会让大租户压垮共享资源,所以要估「最大租户」而非「平均租户」。其三,多租户存储要算每租户开销(独立 schema/索引的固定成本 × 1 万),小租户的固定开销总和可能超过数据本身。一句话:C 端估算看总量与峰值,B2B 估算看租户分布的尾部与隔离成本(呼应 Day 27 多租户与成本工程)。