大规模 Fanout:Push vs. Pull 策略在分布式系统

发布: (2025年12月21日 GMT+8 20:34)
6 min read
原文: Dev.to

Source: Dev.to

现代系统之所以失败,并不是因为它们无法存储数据,而是因为它们无法在恰当的时间将正确的数据交付给正确的消费者。
Fanout(广播)问题是分布式系统中最基本的挑战之一,尤其在社交媒体信息流、通知系统、消息平台和事件驱动架构中表现突出。

当单个事件发生时,如何高效地将其传递给数百万的消费者?主要有两种策略:

  • 写时广播(Push)
  • 读时广播(Pull)

两者都是有效且被广泛使用的方案,但各自都有严重的权衡取舍。

Fanout 问题

  • 一次写入 → 多次读取
  • 目标:向所有关注者提供低延迟、个性化的动态,即使用户拥有数百万关注者。

朴素的解决方案——“只把帖子发送给所有人”——在以下方面会崩溃:

  • 写放大
  • 存储爆炸
  • 热分区
  • 延迟峰值

写时推送(Fanout‑on‑Write)

当用户创建内容时,系统 立即将 内容推送到每个关注者的预计算时间线。

工作原理

User posts → System pushes post to N follower feeds

优势

  • 超快速的时间线读取
  • 可预测的读取延迟
  • 简单的读取查询(单次查找)

成本 / 权衡

  • 巨大的写放大(例如,拥有 1 亿粉丝的名人发布一条内容就会产生 1 亿条时间线写入)
  • 高存储使用量
  • 热门用户可能导致系统过载

Source:

Fanout‑on‑Read(拉取)

当用户打开他们的动态时,系统 拉取 他们关注的账号的最新帖子,在读取时进行合并、排序和过滤。

工作原理

User opens feed → System pulls content from many sources

优势

  • 写入成本极低(没有针对每个粉丝的写入)
  • 对拥有极高粉丝数的用户(名人)可良好扩展
  • 存储效率高

成本 / 权衡

  • 读取更复杂,成本更高
  • 与推送相比读取延迟更高
  • 更难实现高效缓存

混合 Fanout 策略

纯推送或纯拉取在大规模系统中很少出现;大多数平台采用 混合 方法。

选择性 Fanout

  • 对普通用户使用 Push(受限 Fanout)
  • 对名人或高 Fanout 内容使用 Pull

为什么混合有效

  • 前约 0.01 % 的用户产生极端 Fanout;如果对他们的帖子进行推送会导致存储和队列崩溃。
  • 预计算、排序模型和 Feed 物化会在最能产生价值的地方使用。

典型组成

  • 预计算的 Feed 条目(Push)
  • 动态获取的内容(Pull)——例如,推荐帖子、广告、短视频

行业特定的混合方案

  • 职业图谱(规模较小、密度较高)→ 主要使用 Push
  • 兴趣类 Feed(规模大、稀疏)→ 主要使用 Pull,结合推荐池和机器学习排序的候选集合

超越社交动态的 Fanout

策略典型使用场景关键特性
推送 Fanout移动推送通知、紧急警报、交易警报、缓存失效、安全补丁使用消息队列或基于主题的发布/订阅,需要限流,提供低延迟投递
拉取 FanoutKafka 消费者、Prometheus 抓取、对不常访问资产的惰性获取消费者从分区拉取,支持背压、可重放性和故障隔离
混合价格行情(推送)+ 历史数据(拉取),紧急开关更新(推送)+ 定期一致性检查(拉取)在带宽、延迟和存储约束之间取得平衡

如何选择合适的 Fanout 策略

在以下情况下使用 Fanout‑on‑Write(Push):

  • 读取延迟必须最小化
  • Fanout 大小受限(例如,大多数用户)
  • 存储成本低且充足
  • 可预测的性能至关重要

在以下情况下使用 Fanout‑on‑Read(Pull):

  • Fanout 大小不受限制(例如,名人)
  • 写入必须保持低成本
  • 消费者需求波动剧烈
  • 需要背压来保护下游服务

混合方式适用场景:

  • 需要对大多数用户提供低延迟读取,同时还能可扩展地处理极端 Fanout
  • 可以对部分内容进行预计算,其余内容动态拉取

把 Fanout 想象成物流:

  • Push = 送货上门 – 快速、可预测,但成本更高。
  • Pull = 仓库自提 – 更便宜且灵活,但速度较慢。
  • Hybrid = 亚马逊 Prime – 为高优先级商品提供快速配送,同时以成本有效的方式处理其余商品。
Back to Blog

相关文章

阅读更多 »

数据库分片 vs 分区

数据库分片与分区的区别 什么是数据库分片 - 水平数据分布 – 数据被拆分为多个分片,每个分片存储在不同的…