Lesson 0011 · 系统设计 · Phase 3 权衡

Feed 流:推 vs 拉

⏱ 预计 30 分钟 🎯 经典题「设计 Twitter/朋友圈」,推拉权衡是灵魂 📖 前置:Lesson 0005 · Lesson 0006 · Lesson 0007
与你的 Mission 的关系

「设计 Twitter timeline」是出场率最高的面试题之一,因为它的核心矛盾(粉丝量级差异 8 个数量级)逼你做真正的权衡——没有标准答案,只有按数字说话。本课的主要依据是 Twitter 工程负责人 Raffi Krikorian 的经典分享《Timelines at Scale》[1]

§1 · 题目与本质

题目:设计 Twitter/微博式 timeline——用户打开 App,看到「关注的所有人」的推文按时间排序。本质矛盾一句话:

发一条推文是 1 次写,但可能需要让 1 亿人的 timeline 更新;读 timeline 却是每天几十亿次。—— 写读两边的量级差异横跨 8 个数量级

怎么处理这个不对称,就是「推 vs 拉」之争。

§2 · 两种极端扇出写 vs 扇出读

方案机制代价
(扇出写)
Fan-out on write
发推时,立刻写入每个粉丝的收件箱(Redis List,每人保留最近 K 条)。读时只读自己的收件箱,O(1) 大 V 之痛:1 亿粉丝 = 一次写放大 1 亿次;僵尸粉白白消耗写入;删除推文要追遍收件箱
(扇出读)
Fan-out on read
发推只写自己的「发件箱」;读时现场遍历关注列表,合并 K 个人的最新推文(k 路归并) 读之痛:关注 1000 人 = 一次读扇出 1000 次查询;大 V 的推文被反复重复读
直觉换算

推 = 把成本压在写侧(发推的人买单);拉 = 把成本压在读侧(看 timeline 的人买单)。读比写多几个数量级(Lesson 0002 直觉)→ 所以纯拉很少见,纯推是主流起点。成本压到量级小的那侧,是通用架构直觉。

§3 · 工业答案混合推拉

Twitter 的经典方案(正是为了解决「Justin Bieber 问题」——他的粉丝比系统里一半用户还多)[1]

  1. 普通用户发推 → 推:异步扇出(发事件进 MQ,L7;worker 写入各粉丝收件箱),粉丝量 < 阈值(如 1 万);
  2. 大 V 发推 → 不推:只写自己的发件箱;
  3. 读 timeline → 合并:自己收件箱(已含普通用户推文)∪ 关注的大 V 发件箱(现场拉取),按推文 ID 排序(ID 里带时间戳,Snowflake 类设计)。

关键工程细节:

面试常见翻车点

① 忘了问「粉丝量分布」就选纯推——大 V 场景直接爆炸;② 推的过程做成了同步——发推接口延迟由最慢粉丝决定;③ 只顾推文本体,忘了 timeline 的「翻历史」与「 timeline 是另一个存储」。先问分布,再选方案。

§4 · 随堂检测

§5 · 检索练习

场景题:1 亿日活、平均关注 200 人、1% 用户粉丝超 100 万(最大 8 千万)。凭记忆写出你的推拉混合方案:谁推谁不推、读侧怎么合并、收件箱怎么存。

对照参考要点

① 粉丝 < 阈值(如 1 万)→ 异步推收件箱(MQ 扇出,worker 写 Redis List);大 V 只写发件箱不推。② 读 = 自己收件箱 ∪ 现场拉关注的大 V 发件箱,按 ID(含时间戳)k 路归并。③ 收件箱每人截断最近 ~800 条 + 活跃度分级过滤。数字不同结论可能不同——关键是你先要到了「粉丝分布」这个数字。

§6 · 本周行动

行动任务(约 20 分钟)

在你常用的社交 App 上做个侦探实验:关注一个大 V,等 TA 发新内容,观察你的 timeline 更新延迟(刷新才出现?推通知?延迟几秒还是几分钟?)。再转发一条大 V 的内容,观察它出现在粉丝 timeline 的方式——用本课知识反推背后的推拉策略,写两句你的推理。

§7 · 延伸资源

💬 你按 §5 写的方案可以直接贴给我,我按「粉丝分布可能变化」出三个追问考你。