# 社交信息流 架构模板 > **代表产品**:Twitter / X、Instagram、微博、抖音首页 > **一句话定位**:把海量的「别人发的内容」,按你关心的关系/兴趣排好序,塞进你那一屏「首页信息流」。 --- ## 1. 一句话定位 一个社交信息流产品 = **一台「内容分发引擎」**:无数人在不停地往里发东西,系统要在你刷新的那一刻,从茫茫内容里挑出**「跟你有关的、你最可能想看的」**那几十条,排好序送到你眼前。 架构上最反直觉的一点:这类系统的难点**不在写、不在存,而在「读时如何为每个人组装出一份个性化的列表」**。一条发文很便宜,但「让一亿个人各自看到自己该看的那一版首页」这件事,会把整套架构逼到极限。一切设计,都在回答一个问题:**这份「个性化列表」,到底是发文时就提前算好,还是等用户刷新时现算?** ## 2. 业务本质:它在解决什么问题 用户要的是**「打开 App,不用思考,就有源源不断、跟我有关、还挺好看的内容」**。它取代的是「自己一个个去翻关注对象的主页」这件麻烦事——系统帮你把所有关注/感兴趣的来源,**揉成一条永远刷不到底的流**。 价值与钱从哪来: - **注意力即货币**:用户停留越久、刷得越多,可插入的**广告**就越多; - **信息流广告**:广告本身就是「一条伪装成内容的内容」,无缝混进流里按曝光/点击计费; - **生态绑定**:关系链和内容沉淀越厚,用户越离不开。 **关键事实:发文是一次「写」,但每个粉丝刷新都是一次「读」,而读远远多于写。** 一条发文可能被读几百万次。这意味着**系统的负载几乎全压在「读」这一侧**,这一条决定了后面几乎所有架构取舍——尤其是那个核心难题:**这份首页要不要提前算好。** ## 3. 核心需求与约束 **功能性需求(系统要能做什么):** - [ ] 发布内容:发文字/图/视频,可能 @ 人、带话题。 - [ ] 关注关系(社交图):谁关注了谁,构成一张巨大的关系网。 - [ ] 首页信息流(Home Timeline):聚合「我关注的人/我可能喜欢的内容」并排序。 - [ ] 个人主页流(User Timeline):某个人发过的所有内容,按时间倒序。 - [ ] 互动:点赞、转发、评论(它们本身又会成为新的内容/信号)。 - [ ] 排序:决定「先给你看哪条」——时间倒序,或算法推荐。 - [ ] 通知:有人关注你、@ 你、赞了你。 **非功能性需求 / 质量属性(这才是架构的主战场):** | 质量属性 | 目标 | 为什么对这类系统重要 | |---|---|---| | **刷新延迟(读时延)** | < 几百毫秒 | 用户下拉刷新就盯着看,转圈超过 1 秒就嫌卡。读路径必须极快。 | | **读吞吐(Feed QPS)** | 极高 | 读量是写量的成百上千倍,是整个系统最大的流量来源。 | | **发文到可见的延迟** | 秒级可接受 | 你发完,粉丝**几秒后**刷到是 OK 的;不要求强实时。这是宝贵的「松弛空间」。 | | **可用性** | 99.9%+ | 刷不出内容用户立刻就走。读路径尤其要高可用。 | | **最终一致即可** | 是 | 你少看到一条、或晚几秒看到,无伤大雅。**几乎不需要强一致**——这是巨大的设计自由度。 | **关键约束(不可逾越的边界):** - 🔴 **读远多于写,且读是个性化的**。不能像静态网页那样「算一次、人人共享」,每个人的首页都不一样。 - 🔴 **「大 V 问题」**:粉丝数分布极度不均。普通人几百粉,头部账号几千万粉。**任何「发文时给每个粉丝都做点事」的方案,都会在大 V 身上爆炸。** 这是本架构的头号拦路虎。 - 🔴 **社交图巨大且热点集中**:关系查询(谁关注了谁)频繁,且大 V 的粉丝列表本身就是超级热点。 - 时间线是「无限下拉」的,要支持高效的分页与历史回溯。 ## 4. 架构全景图 ``` 用户(刷新首页 / 发一条内容) │ ▲ 发文 │ 写路径 │ │ 读路径 │ 刷首页 ▼ │ ┌──────────────────────────────────────────────────────────────────────┐ │ 接入层 API 网关 / 边缘 │ │ • 鉴权、限流 • 媒体上传直传对象存储 • 读写分流 │ └──────────┬──────────────────────────────────────────────┬─────────────┘ │ 写 │ 读 ▼ ▼ ┌────────────────────┐ ┌────────────────────────┐ │ 发文服务 │ │ Feed 读取服务 │ │ • 落库(权威内容) │ │ • 取出我的时间线条目 │ │ • 投递扇出(fan-out)│ │ • 回填内容正文(批量) │ └────┬────────┬──────┘ │ • 调排序,组装最终列表 │ │ │ └──────┬──────────┬───────┘ │ │ 查粉丝列表 │ │ │ ▼ │ ▼ │ ┌──────────────┐ ┌───────────────────────┐ │ ┌────────────┐ │ │ 社交图服务 │◀───│ 时间线存储(每人一条) │◀──┘ │ 排序/推荐 │ │ │ (关注关系) │ │ 预计算好的「收件箱」 │ │ 打分服务 │ │ └──────────────┘ │ 内存级 KV / 宽列 │ └────────────┘ │ ▲ └───────────▲───────────────┘ │ 写扩散 │ 普通人:推 │ 大 V:读时拉取并合并 └─────────┴───────────────────────┘ │ ▼ ┌──────────────┐ ┌───────────────────┐ ┌──────────────────────────────┐ │ 内容存储 │ │ 媒体存储 + CDN │ │ 通知服务 │ │ (帖子正文) │ │ (图/视频→边缘分发) │ │ (被关注/被@/被赞 → 推送) │ └──────────────┘ └───────────────────┘ └──────────────────────────────┘ ``` > 灵魂部件是中间那块**「时间线存储(每人一条预计算好的收件箱)」**,以及它两侧的**写扩散 / 读聚合**两条路。整套系统的核心矛盾就藏在这里:**普通人走「推」(发文时写进粉丝收件箱),大 V 走「拉」(读时再合并),两者在 Feed 读取服务里汇合。** 这就是「混合模型」。 ## 5. 组件职责 - **接入层 / API 网关**:鉴权、限流,并**把读和写两条流量分开**(读路径要极致优化、可大量缓存;写路径要可靠落库)。媒体走单独通道直传对象存储,不占业务链路。*为什么需要*:读写在这类系统里是「两个世界」,在最外层就分流,后面才好各自优化。 - **发文服务**:接收发文,**把内容写进权威存储**,然后触发**扇出(fan-out)**——决定这条内容要不要、以及怎样推进粉丝的时间线。*为什么需要*:它是写路径的核心,也是「推 vs 拉」决策的执行者。 - **社交图服务(关注关系)**:维护「谁关注谁」这张巨大的有向图,提供「某人的粉丝列表 / 某人的关注列表」查询。*为什么需要*:扇出要靠它拿粉丝列表;读时拉取要靠它拿「我关注了谁」。它是关系的唯一权威。 - **时间线存储(每人一条预计算收件箱)**:为每个用户维护一条**已经排好序的内容 ID 列表**(注意:存的是**引用/ID,不是正文**)。刷新时直接读这条列表即可。*为什么需要*:把「读时现算每个人的首页」这件昂贵的事,提前在写时做掉——**用空间换读时延**,这是抗住海量读 QPS 的关键。 - **Feed 读取服务**:用户刷新时,取出时间线条目,**批量回填内容正文**,调排序服务打分,组装成最终一屏返回。*为什么需要*:时间线里只有 ID,真正给用户的是带正文、带排序的完整列表,这层负责「组装」。 - **排序 / 推荐打分服务**:决定条目的先后——可以是纯时间倒序,也可以是按「你多大概率会互动」的算法打分。*为什么需要*:内容供给远大于用户能看的量,**排序质量直接决定用户停留时长**,也就是直接决定收入。 - **内容存储(帖子正文)**:存帖子本体(文字、引用的媒体地址、作者、时间)。一次写、海量次读、基本不改。 - **媒体存储 + CDN**:图片/视频存对象存储,通过 CDN 边缘节点分发。*为什么需要*:媒体又大又被反复读,必须靠 CDN 把流量挡在源站之外、把延迟拉到用户身边(详见视频流模板)。 - **通知服务**:被关注、被 @、被赞时,异步生成通知并推送。*为什么需要*:互动反馈是社交粘性的核心,但它不能拖慢发文/读 Feed 的主链路,所以异步。 ## 6. 关键数据流 **场景一:普通用户发一条内容(写扩散 / 推模型)** ``` 1. 用户发文 ──▶ 网关 ──▶ 发文服务 2. 发文服务:把正文写入【内容存储】(这是权威副本) ← 这一步永远要做 3. 发文服务 ──▶ 社交图服务:取出「我的粉丝列表」(比如 800 人) 4. 异步扇出:把这条「内容 ID」逐个写进 800 个粉丝的【时间线收件箱】 粉丝A 收件箱: [新ID, 旧, 旧, ...] 粉丝B 收件箱: [新ID, 旧, 旧, ...] ... (写 800 次) 5. 完成。粉丝下次刷新时,这条已经躺在他的收件箱里了。 ``` > 这叫**写扩散(fan-out on write)**:发文时多干活(写 800 份),把读时变得极简(直接读自己那一条)。**对粉丝不多的普通人,这非常划算**——因为读远多于写,在写侧多花一点,省下海量读侧的开销。 **场景二:用户刷新首页(读路径)** ``` 1. 用户下拉刷新 ──▶ 网关 ──▶ Feed 读取服务 2. 读取服务:取出我的【时间线收件箱】最新 N 条 ID(普通人的内容已预存于此) 3. 【混合关键】再去查我关注的「大 V」们最近发了什么 ── 实时拉取并合并进来 (大 V 的内容没有被推给我,要在这一刻现拉) 4. 批量回填:拿这批 ID 去【内容存储】取正文 + 去媒体/CDN 取图 5. ──▶ 排序服务:对这批候选打分排序(时间序 或 算法推荐) 6. 组装成一屏 ──▶ 返回用户 ``` > 注意第 2、3 步:**普通人的内容是「提前推好、直接读」,大 V 的内容是「读时现拉、临时合并」。** 一次刷新同时用到了「推」和「拉」——这正是混合模型的精髓。 **场景三:大 V 发一条内容(为什么不能写扩散)** ``` 某大 V(5000 万粉丝)发一条文 ──▶ 发文服务 若按「推模型」扇出 ──▶ 要往 5000 万个收件箱各写一次!! → 一条发文 = 5000 万次写,瞬间打爆存储和队列(这就是「扇出爆炸」) ✅ 混合方案:大 V 不扇出,只写自己的【个人主页时间线】 → 由粉丝在「刷新读取」时(场景二第 3 步)主动来拉、来合并 ``` > 这是本架构最重要的一张图:**「大 V 问题」用「推拉分治」破解——普通人推、大 V 拉。** 把「会爆炸的那一小撮」单独切出来走拉模型,其余绝大多数走推模型。 ## 7. 数据模型与存储选择 核心实体:`用户` ─(关注)─▶ `用户`(构成**社交图**);`用户` ──发布──▶ `帖子(post)`;`帖子` ──产生──▶ `互动(赞/转/评)`;`用户` ── 拥有 ──▶ `时间线(timeline,一串帖子 ID)`。 | 数据 | 存储类型 | 为什么 | |---|---|---| | 用户账户 / 资料 | 关系型 | 要事务、强一致(账号、安全相关) | | 关注关系(社交图) | 图 / 宽列(邻接表) | 频繁查「某人的粉丝/关注列表」,本质是图的邻接关系;粉丝列表可能极长 | | 帖子正文 | 文档型 / KV(按 ID 取) | 一次写、海量读、基本不改,按帖子 ID 直接取最快 | | 时间线收件箱(每人一条 ID 列表) | 内存级 KV / 宽列 | 读路径核心,要极低延迟、按用户 ID 直读;只存 ID 不存正文,省空间 | | 媒体(图/视频) | 对象存储 + CDN | 文件大、不可变、被反复读,必须边缘分发 | | 互动计数(赞数/转发数) | 内存级计数器 / KV | 写极频繁、读极频繁,要高速增减,可接受最终一致 | | 排序所需特征 / 信号 | 列存 / 特征存储 | 海量行为日志,供排序模型离线/近线计算 | > 教学点:**时间线收件箱里只存「内容 ID」,不存正文。** 一条爆款被几百万人的收件箱引用,若每条都存一份正文,空间瞬间爆炸;存 ID、读时再批量回填正文,是「引用 vs 拷贝」的经典权衡。**用「内存级 KV」描述时间线存储,是因为它的访问形态是「按用户 ID 极低延迟读一条有序列表」,而不是因为某个具体产品。** ## 8. 关键架构决策与权衡 ⭐ **决策 1:Feed 用推模型(写扩散)、拉模型(读扩散)还是混合?(本架构的命门)** - **拉模型(fan-out on read)**:发文时只存自己的;用户刷新时,**现去查「我关注的所有人」最近发了啥,当场聚合排序**。 - 优点:写极轻(只写一份),没有任何扇出,实现简单,改关注关系立即生效。 - 代价:**读极重**。你关注 2000 人,每次刷新就要去聚合 2000 个人的最新内容——**读放大**严重,刷新延迟高,而读又是最高频操作,扛不住高 QPS。 - **推模型(fan-out on write)**:发文时就把内容 ID **推进所有粉丝的收件箱**;用户刷新时直接读自己那一条,极快。 - 优点:**读极轻**(直读一条预排好的列表),完美匹配「读远多于写」。 - 代价:**写会扇出**;遇到大 V(千万粉丝)直接**扇出爆炸**——一条发文要写千万次,打爆写入与存储。 - **混合(Hybrid)**:**绝大多数普通用户走推**(粉丝少,扇出便宜,享受读极快);**少数大 V 走拉**(粉丝太多,不推,改由粉丝读时来合并)。 - **取向**:**规模化后必然走混合**。因为读远多于写 → 默认想用推;但大 V 让纯推爆炸 → 把大 V 切出来走拉。**「对 99% 便宜的情况做优化、把 1% 会爆炸的情况单独处理」**,是这类倾斜分布系统的通用解法。代价是系统里**同时存在两条路径**,读取服务要做「推来的 + 拉来的」合并,复杂度上升。 **决策 2:「大 V 写扩散爆炸」具体怎么破?** - 问题:粉丝数是**极度长尾**的——绝大多数人粉丝很少,极少数人粉丝上千万。一条大 V 发文若推给所有粉丝,瞬时产生千万级写操作,撑爆队列和存储,还拖慢大 V 的发文响应。 - 破解:**给账号设一个「粉丝数阈值」**。低于阈值=普通人=发文时正常扇出(推);高于阈值=大 V=**不扇出**,内容只留在自己的个人主页时间线里,由粉丝在**读取时主动拉取并合并**进首页。 - **取向**:这是混合模型的落地手段。代价:① 读取服务变复杂(要识别「我关注了哪些大 V」并实时拉取合并);② 阈值要调,且存在「中 V」灰度地带;③ 大 V 内容的读路径更重,需对其内容做**额外缓存**(因为会被海量粉丝同时来拉,是天然热点)。**本质是把「写时爆炸」转移成「读时多一次合并」,而读时我们有缓存可用。** **决策 3:时间线(收件箱)存在哪、存多深?** - 全存进慢速持久库:省内存,但读延迟高,违背「读要极快」。 - 全量、永久地放进高速存储:读极快,但海量用户 × 长历史,内存成本爆炸。 - **取向**:时间线收件箱放**内存级 KV/宽列**以保证读速度,但**只保留最近的有限条数**(比如最近几百条)。用户向下翻很旧的内容时,再走「降级路径」从持久存储慢查。**因为「绝大多数刷新只看最新的一屏」,为冷门的深翻保留全量高速副本不划算。** 又是「为热路径优化、冷路径降级」。 **决策 4:排序——纯时间倒序,还是算法推荐?** - **时间倒序**:最新的在最上面。简单、可预测、所见即关注。但内容多了会淹没好内容,你关注的「话痨」会刷屏。 - **算法推荐**:按「你多大概率会停留/互动」打分排序,可掺入「你没关注但可能喜欢」的内容。 - 优点:停留时长↑、收入↑、能突破关系链推好内容。 - 代价:需要一整套**行为信号采集 + 特征 + 打分模型**的近线/在线管线,算力开销大;还带来「信息茧房 / 不可解释」等产品与伦理问题。 - **取向**:早期用时间序(简单、够用);**成熟期普遍转向算法排序**,因为它直接驱动核心商业指标。架构上这意味着读取服务后面要挂一套**排序子系统**,且排序所需的特征要被持续计算和缓存。**关键:排序是在「读取时对一小批候选(几百条)打分」,而不是「为所有人实时重算全网」**——后者是算力上做不到的误区。 **决策 5:发文到可见,要多实时?** - 追求「发完粉丝立刻可见」:扇出必须同步完成,拖慢发文响应,放大爆炸问题。 - 接受「秒级延迟」:扇出**异步化**(进队列慢慢写),发文服务快速返回。 - **取向**:**几乎一定接受秒级最终一致**。社交流不是金融交易,晚几秒刷到完全可接受。**这份「松弛」是这类系统最宝贵的设计自由度**——它让扇出可以异步、可以削峰、可以失败重试,而不必卡住用户。 ## 9. 规模化与瓶颈 和普通系统不同:**这里的瓶颈集中在「读侧的扇出/聚合」和「大 V 热点」,而不是单纯的数据库容量。** - **第一个瓶颈:Feed 读 QPS 巨大。** 读是写的成百上千倍,每次刷新都要组装个性化列表。 破解:① **预计算时间线**(推模型,把读时现算变成读时直取);② **多级缓存**——热门内容正文、热门用户的时间线、整屏渲染结果都可缓存;③ 时间线只存 ID + 批量回填,减小数据量。 - **第二个瓶颈:大 V 扇出爆炸。** 一条发文要触达千万收件箱。 破解:**推拉混合**——大 V 不扇出,改读时拉取合并(决策 1、2)。这是绕不开的核心手段。 - **第三个瓶颈:社交图查询与热点。** 大 V 的粉丝列表本身是超级热点,频繁被扇出/拉取读取。 破解:① 邻接表分片;② 缓存超大粉丝列表;③ 对超级热点账号的内容单独做**热点缓存层**(因为它会被海量粉丝同时来拉)。 - **第四个瓶颈:排序算力。** 算法推荐要为每次刷新的候选打分。 破解:① 特征**离线/近线预计算**好,在线只做轻量打分;② 候选集先**粗排召回**缩到几百条,再**精排**;③ 排序结果短时缓存。 - **媒体带宽**:图/视频流量巨大 → CDN 边缘分发 + 分层缓存(详见视频流模板)。 ## 10. 安全与合规要点 - **内容审核(头号风险)**:这类系统是**违法/有害/虚假信息**的天然温床。发布链路要接**审核**(自动 + 人工),先审后扩散或边扩散边审,违规内容要能**快速从所有收件箱召回**。 - **隐私与可见性**:私密账号、屏蔽/拉黑、谁能看到我的内容——这些**可见性规则必须在「扇出」和「读取」两侧都强制执行**,不能只在前端隐藏。一个常见漏洞是:内容已经推进了不该看到它的人的收件箱。 - **滥用与垃圾**:机器人刷粉、刷量、批量发垃圾内容。需要限流、行为风控、虚假账号识别。 - **关系链即敏感数据**:「谁关注谁、谁给谁点赞」会暴露社会关系,要做访问控制与最小暴露。 - **排序与操纵**:推荐系统可能被刷量操纵、或被用于不当信息推送,需要可观测与人工兜底。 ## 11. 常见误区 / 反模式 - ❌ **纯推模型,不管大 V** → ✅ 一遇到大 V(千万粉)就**扇出爆炸**。必须对大 V 走拉模型(推拉混合)。 - ❌ **纯拉模型,扛高读 QPS** → ✅ 每次刷新都聚合上千个关注对象,**读放大**严重,刷新慢。普通用户应走预计算的推模型。 - ❌ **每次刷新都为所有人实时重算全网排序** → ✅ 算力上做不到。要**预计算时间线 + 只对一小批候选打分**。 - ❌ **时间线收件箱里存正文** → ✅ 一条爆款被几百万收件箱引用就空间爆炸。应**只存内容 ID,读时批量回填正文**。 - ❌ **扇出同步完成、卡住发文响应** → ✅ 扇出应**异步**,发文快速返回;社交流接受秒级最终一致。 - ❌ **可见性/拉黑只在前端隐藏** → ✅ 必须在扇出与读取两侧强制执行,否则内容会泄漏进不该看到的人的收件箱。 - ❌ **媒体从源站直发** → ✅ 图/视频必须走 CDN 边缘分发,否则带宽和延迟都崩。 ## 12. 演进路线:MVP → 成长期 → 成熟期 | 阶段 | 用户/规模量级 | 架构长什么样 | 此时该操心什么 | |---|---|---|---| | **MVP** | 验证想法 / 几万用户 | **拉模型**:发文只存自己的,刷新时现查关注对象聚合排序;单一数据库;时间倒序;媒体先简单直发或小 CDN | **先验证有没有人发、有没有人看**。拉模型实现最简单,粉丝都不多时读放大还不致命 | | **成长期** | 百万级 | 引入**推模型 + 预计算时间线**抗读 QPS;加**多级缓存**;媒体上 CDN;扇出异步化;开始出现大 V 苗头 | 找到读侧瓶颈,把刷新延迟压下来;盯住第一批大 V,准备推拉混合 | | **成熟期** | 千万~亿级 | **推拉混合**(普通人推、大 V 拉)+ **算法推荐排序**(召回粗排精排)+ **多级/热点缓存** + 全球多区域 + 完整内容审核与风控 | 大 V 热点、排序算力与质量、成本、容灾、内容合规与信息安全 | ## 13. 可复用要点 - 💡 **读写不对称时,把成本搬到「次数少」的那一侧。** 读远多于写 → 在写时多做(扇出、预计算),让读极简。这是「写扩散」背后的通用思想,在任何「写少读多」系统都适用。 - 💡 **倾斜分布(长尾)要分而治之:为大多数的便宜情况优化,把少数会爆炸的情况单独处理。** 普通人推、大 V 拉,就是这条智慧的化身;它同样适用于热点商品、热点房间、超级用户等一切「一小撮极端值」场景。 - 💡 **存「引用」而不是存「拷贝」。** 时间线只存内容 ID、读时回填——避免一份热门内容被复制百万份。这是去重、省空间的通用招式。 - 💡 **预计算是用空间换读时延的利器,但只为热路径预计算、冷路径降级。** 时间线只保留最近 N 条、深翻才慢查,是「别为冷门付全量代价」。 - 💡 **找到系统的「松弛维度」并把它用足。** 这里是「发文到可见可以慢几秒」的最终一致——正是它让扇出可以异步、可削峰、可重试。识别出哪里允许「不那么实时/不那么强一致」,往往就解锁了整套架构的弹性。 ## 🎯 随堂检验 --- ## 参考原型与延伸阅读 > 本模板基于以下**工程剖析**与**真实开源项目**整理。 **📖 工程博客:** - [The Architecture Twitter Uses to Deal with 150M Active Users (High Scalability)](https://highscalability.com/the-architecture-twitter-uses-to-deal-with-150m-active-users/) — 写时扇出(fanout-on-write)把推文推入 follower 的时间线缓存。 - [Scaling Instagram's recommendation system (Meta Engineering)](https://engineering.fb.com/2025/05/21/production-engineering/journey-to-1000-models-scaling-instagrams-recommendation-system/) — 信息流召回 / 排序漏斗在海量规模下的架构。 **🔧 开源原型(可直接读代码):** - [mastodon/mastodon](https://github.com/mastodon/mastodon) — 开源微博社交网络,可读源码的关注图与主页时间线投递实现。 --- > 📌 一句话记住社交信息流:**它不是「存帖子的数据库」,而是「一台为每个人现场组装个性化列表的分发引擎」——核心矛盾永远是『这份首页提前算好(推),还是刷新时现算(拉)』,而答案对普通人和大 V 截然不同。**