场景三 · Feed 流 / 推荐
高并发场景 · Scenario 03

场景三:社交 Feed 流 / 短视频推荐

你每天下拉刷新的朋友圈、微博、抖音首页,背后是高并发领域最经典的"读写扩散"难题:一个人发帖,千万人要看——这份内容到底该"送货上门"还是"到店自取"?

读多写少 推拉结合 大V效应 多级缓存
100:1典型读写比
亿级日活用户刷新次数
<200ms首屏加载体验红线
千万级头部大 V 粉丝数
📑 本页目录
01

场景描述与业务特征

Feed 流的本质是:每个用户都有一份"专属报纸",内容来自 TA 关注的人(关注流)或算法推荐(推荐流)。难点在于这份报纸不是印好的——每次下拉刷新都要现场"排版":从几百个关注对象的动态里挑出最新的,按时间或算法排序,200 毫秒内送到手机上。

QPS 一天 → 早高峰通勤 晚8-11点黄金档(峰值) 深夜退潮
潮汐型流量:有规律的早晚高峰,可预测、可提前扩容——比秒杀温柔,但基数大得多。

📖 读写极度失衡

发帖的人少、刷的人多,读写比常在 100:1 以上。架构火力应全部倾斜到"读"这一侧。

🎭 大 V 效应

普通人 200 个粉丝,头部大 V 5000 万粉丝——同一个"发帖"动作,成本相差 25 万倍,一套逻辑不可能通吃。

⏳ 容忍延迟,不容忍卡顿

偶像的帖子晚 30 秒出现在你的流里,你毫无感觉;但下拉刷新转圈 3 秒,你马上退出 App。典型的"弱一致、强性能"。

🔄 无限下滑

分页拉取 + 预加载,用户手指一滑就是一次请求,单用户一天可产生上千次读

🧮 排序即业务

时间序只是起点,推荐流还要过召回→粗排→精排的算法流水线,每一次刷新都是一次小型计算风暴。

🌡️ 内容有热度生命周期

一条内容 80% 的阅读发生在发布后几小时内——新内容放缓存,老内容沉数据库天经地义。

02

整体运作流程

Feed 流的核心机制是"推模式 vs 拉模式"的选择,行业最终答案是"推拉结合"。用快递做类比:推模式 = 送货上门(发帖时就复制到每个粉丝的信箱),拉模式 = 到店自取(刷新时现场去关注列表挨个取件)。

👤 普通用户发帖 粉丝 ≤ 1万 ⭐ 大 V 发帖 粉丝 ≥ 1万 📬 推模式(写扩散) MQ 异步把帖子ID 写进每个粉丝的收件箱 (Redis ZSet 每人一份) 📮 拉模式(读扩散) 帖子只写进自己的发件箱 粉丝刷新时实时来取 (大V发件箱是热点,重点缓存) 🔀 读时合并排序 自己收件箱(推来的) + 关注的大V发件箱(拉的) 归并排序 → 补全内容 → 返回 📱 刷新 <200ms 首屏到手 推拉结合:普通人"送货上门",大 V "到店自取" —— 按粉丝量分流,两头的成本都可控
🧠
推荐流(抖音式)呢?把"关注列表"换成"算法候选池":刷新请求先召回(从亿级内容捞几千条候选)→ 粗排(轻模型砍到几百)→ 精排(重模型打分排序)→ 返回十几条。读扩散被算法流水线替代,但"多级缓存 + 毫秒级预算分配"的骨架完全一致。
03

核心瓶颈与数据一致性挑战

✍️ 写扩散风暴:大 V 一发帖,系统抖三抖

纯推模式下,5000 万粉丝的大 V 发一条帖 = 5000 万次收件箱写入。写完要几十分钟、占满 MQ、拖垮 Redis——这就是必须"推拉分流"的根本原因。

📚 读扩散陷阱:关注500人的重度用户

纯拉模式下,刷新一次要实时查询 500 个发件箱再归并,一次刷新扇出 500 次读。关注越多的活跃用户,体验反而越差。

👻 幽灵帖:删帖与取关的一致性

推模式把帖子 ID 复制进了千万个收件箱,作者一删帖/被拉黑,这些副本没法瞬间清完。解法:读时校验——展示前检查内容状态,已删就跳过(懒删除)。

🕳️ 缓存击穿与雪崩

顶流明星官宣,全网同时拉 TA 的发件箱,缓存一旦失效,海量请求直穿数据库。热点多副本 + 逻辑过期 + 请求合并是标配防线。

💥
事故现场还原:某明星深夜官宣恋情,微博瞬时流量暴涨数倍——热点内容的缓存副本、转发/评论的写入队列、推荐流的补位逻辑同时承压,服务大面积超时近一小时。教训:Feed 系统的容量规划必须按"顶流突发"设计,且要有一键"热点应急预案"(热点内容静态化、非核心功能降级)。
04

优化手段、获益与代价

① 推拉结合(按粉丝量分流) 核心

粉丝数低于阈值(如1万)走推模式,超过阈值的大V走拉模式,读取时归并两路结果。

✅ 获益:写扩散上限被封顶(最多推1万份),读扩散也可控(只实时拉少数大V)——两头的爆炸都拆掉了。
⚠️ 代价:两套逻辑并存,读路径要归并排序;阈值附近的账号切换模式时需要迁移处理。

② 收件箱只存 ID + 多级缓存 读优化

收件箱(Redis ZSet)只存帖子 ID 和时间戳,内容本体单独缓存;本地缓存 → Redis → DB 三级兜底。

✅ 获益:收件箱体积缩小 10 倍以上;热门内容在本地缓存命中,Redis 压力大降;内容更新只改一处。
⚠️ 代价:读时需要二次查询"补全内容"(batch mget 缓解);本地缓存存在短暂的多节点不一致。

③ MQ 异步写扩散 写优化

发帖只同步写"发件箱"即返回成功,粉丝收件箱的扩散由 MQ 消费者慢慢完成。

✅ 获益:发帖响应稳定在几十毫秒,与粉丝量无关;扩散洪峰被 MQ 抹平。
⚠️ 代价:粉丝看到新帖有秒级延迟(业务上完全可接受);消费失败需重试+幂等,避免收件箱重复。

④ 收件箱截断 + 冷数据回源 成本

每人收件箱只保留最近 N 条(如 2000 条),翻页翻到底的极少数请求回源数据库拼装。

✅ 获益:Redis 内存占用封顶,成本可预算;99.9% 的请求都落在缓存内。
⚠️ 代价:深度翻页体验骤降(回源慢);不活跃用户的收件箱可能整体过期,唤回时要重建(懒加载重建)。

⑤ 热点探测 + 多副本缓存 抗热点

实时统计 Key 访问频率,超阈值自动升级为"热点":复制多份缓存副本分散读取,甚至推到应用本地内存。

✅ 获益:顶流内容不再打爆单个 Redis 分片;应对突发热点从"人肉救火"变自动化。
⚠️ 代价:多副本更新时的一致性窗口拉长;热点探测本身有延迟,前几秒仍靠限流硬顶。
🛡️
降级策略:① 推荐算法超时 → 返回兜底列表(热榜/缓存的上一次结果),用户无感知;② Redis 压力告警 → 关闭"在线状态""已读回执"等锦上添花功能;③ 极端情况 → Feed 流降级为纯时间序(跳过精排),保住"能刷"的底线。Feed 流的三角站位:性能+可用性最大化,一致性放到最松。
05

多种解决方案对比与选型建议

方案发帖成本刷新成本实现复杂度适用场景
纯拉模式(读扩散)
刷新时实时聚合关注列表
极低 · 写1次高 · 扇出N次读简单用户量小、关注数少的早期产品
纯推模式(写扩散)
发帖时复制进所有粉丝收件箱
高 · 写粉丝数次极低 · 读1次简单无大V的熟人社交(粉丝量均匀)
推拉结合
按粉丝量阈值分流 · 本页主推
可控(封顶)可控(少量归并)中等有大V生态的社交平台标准答案
纯算法推荐流
召回-粗排-精排流水线
低 · 入库进候选池高 · 每刷都算很复杂内容消费型产品(短视频/资讯)
🎯
选型口诀:创业期用户少,纯拉模式最省事(一张关注表+一条SQL就能跑);用户上百万且出现粉丝量分化,切推拉结合;做内容消费产品直接对标推荐流架构但先用"热度榜+简单个性化"起步。切记:推拉阈值不是拍出来的,用真实的粉丝分布和读写比压测出来才靠谱。
06

推演检验:换个条件还成立吗?

背下架构图不算学会,能判断"条件变了方案还成不成立"才算。先自己推,再展开参考。

推演 1:如果产品规则限制每人最多关注 200 人(类似早期朋友圈),纯拉模式够不够?

💡 参考推演

够。拉模式的成本≈关注数×单次查询,上限 200 意味着聚合成本有天花板,再配合发件箱缓存完全可控——微信朋友圈就是类似思路。推拉结合是为"关注数不设限 + 粉丝量极度分化"准备的。产品规则本身就是架构参数:能用规则把问题域缩小,就不要用架构硬扛。

推演 2:如果要求千万粉大V发帖后 1 秒内全部粉丝可见,推模式(写扩散)还成立吗?

💡 参考推演

不成立——千万次收件箱写入不可能 1 秒内完成,写扩散天然放弃"发布即全网可见"的强时效。这正是大V走拉模式的根本原因:帖子只写一次发件箱 + 热点缓存多副本,粉丝刷新时拉取,时效由读方触发。如果业务硬要"秒级触达",那是推送通知(push)的职责,不该由 Feed 收件箱承担——别把两种需求塎在一套架构里。

推演 3:如果数据显示用户 90% 的消费来自推荐流而非关注流,还要继续维护收件箱吗?

💡 参考推演

收件箱(写扩散)只为关注流服务,推荐流走的是召回+排序的算法链路,两套架构本就独立。关注流使用率低到一定程度,可以把收件箱降级成纯拉(省掉大量存储和写扩散算力),把资源投给推荐侧——架构资源要跟着用户行为迁移,而不是跟着历史设计走。定期用数据审视"当年的架构前提还成不成立",本身就是架构工作的一部分。