🧩 典型题干
设计一个信息流系统:
- 高性能读写
- 关注关系
- 推荐算法
- 缓存策略
📚 学习正文:信息流系统如何做到既快又准?
交互图:信息流关键链路闭环(点步骤看推拉/缓存/一致性)
核心面试话术:写路径决定成本(扇出/队列/去重),读路径决定体验(缓存/分页/回源),大V 用读扩散防扇出爆炸,普通用户用写扩散保证读快。
1) 发帖写入:先把内容变成“可复用的事实”
- 内容存储:content 表(或内容服务)写入一次,生成 contentId/时间戳。
- 事件驱动:发帖后发 MQ 事件(作者、contentId、发布时间),进入扇出流水线。
- 幂等:防重复发布/重试导致多条记录(clientPostId)。
2) 扇出策略:决定系统成本与热点风险
- 写扩散(push):发帖时写入粉丝收件箱,读快写重。
- 读扩散(pull):只存作者发布列表,读时合并关注列表,写轻读重。
- 混合:普通用户写扩散,大V 读扩散(避免扇出爆炸)。
3) 收件箱写入:异步队列 + 去重 + 限速
- 异步扇出:按粉丝分片写入,worker 可水平扩展。
- 去重:避免重复写入同一 contentId(写扩散重试/回放)。
- 限速:粉丝量巨大的作者做限速分批写入,避免拖垮存储。
4) 读信息流:缓存 + 游标分页保证体验
- 收件箱读:写扩散模式直接读 user_inbox(按 seq/timestamp)。
- 合并读:读扩散模式合并 N 个关注作者的发布列表,取 topK。
- 分页:避免 offset,用 (timestamp,id) 或 seq 做游标。
5) 排序与推荐:时间线是基础,推荐是加成
- 基础排序:朋友圈通常时间线为主(简单、符合预期)。
- 推荐重排:加入互动权重/兴趣分数做二次排序(可灰度)。
- 稳定性:推荐可降级为纯时间线,保证核心可用。
6) 删除/屏蔽/回源:一致性与最终修复
- 删除:内容删除后收件箱可能有“脏数据”,读时需要过滤或回源校验。
- 屏蔽/拉黑:过滤层在读路径生效(不必重写所有收件箱)。
- 回收任务:离线清理无效指针、修复异常扇出(对账/补偿)。
1) 需求澄清与量级
- 用户规模:DAU、平均关注数、平均粉丝数。
- 内容量级:每秒发布数、人均日发布数、内容类型。
- 读写比例:读多写少?读写比例大概是多少?
- 时效要求:新内容多久出现在信息流?是否允许延迟?
2) 核心挑战
写扩散:用户发布时写入所有粉丝时间线(适合大V)
读扩散:用户读取时聚合所有关注者内容(适合普通用户)
混合模式:根据粉丝数动态选择扩散策略
缓存策略:热点内容缓存、冷数据淘汰
3) 数据模型设计
- 内容表:content(内容ID、作者、内容、时间戳、权重)。
- 关注表:follow(用户ID、关注者ID、关注时间)。
- 用户时间线:user_timeline(用户ID、内容ID、时间戳、分数)。
4) 推拉结合策略
1) 大V发布:写扩散,直接推送到粉丝时间线
2) 普通用户发布:读扩散,用户拉取时聚合
3) 动态阈值:根据粉丝数实时选择策略
4) 异步化:所有写操作异步处理,提升响应速度
系统架构图(面试时用它讲全链路)
客户端(App/Web)
|
v
网关/API(鉴权/限流)
|
v
内容服务(写 content 表/存储)
- 生成 contentId/time
- 发出 FeedEvent(MQ)
|
+--> 关注关系服务(follow graph)
|
+--> 扇出服务 Fanout(异步 worker)
| - 普通用户:写扩散 -> user_inbox(收件箱/时间线)
| - 大V:读扩散 -> author_outbox(作者发布列表)
|
+--> 缓存层
- user_inbox 缓存(活跃用户)
- author_outbox 缓存(热点作者)
- 内容详情缓存(contentId -> content)
读路径(Feed API):
- 写扩散:读 user_inbox(游标分页) -> 批量拉 content
- 读扩散:合并关注作者 outbox(topK merge) -> 批量拉 content
过滤与一致性:
- 删除/屏蔽/违规:读时过滤 + 必要回源校验
- 回收任务:清理无效指针/补偿遗漏扇出
观测:扇出延迟、inbox 大小、热点作者 QPS、缓存命中率、P95/P99
5) 缓存架构设计
- 多级缓存:本地缓存 + Redis 分布式缓存。
- 热点内容:热门内容预加载到 CDN 边缘。
- 用户时间线:活跃用户时间线缓存,非活跃用户实时计算。
6) 推荐与排序
时间排序:简单高效,适合朋友圈
兴趣排序:基于用户行为和内容标签
混合排序:时间 + 权重 + 推荐分数
实时更新:用户行为实时影响排序结果