内容型产品架构:推模型还是拉模型?


  1. 模型
    1. 推模型(写扩散)
    2. 拉模型(读扩散)
  2. 产品形态
  3. 存储系统
  4. 总结

无论是信息流、论坛、信箱,还是私聊、群聊、通知,推拉模型是内容型(包括:社交型)产品架构的核心。做出正确选择的关键在于对 产品形态 和系统组件 清晰的认识

模型

push vs pull

推模型(写扩散)

为每个内容消费者维护订阅列表,记录订阅的内容索引(一般为内容ID、类型、发表时间等索引数据)。每当内容生产者发布内容时,都会写入所有内容消费者的订阅列表。

  • 优点:读很轻。仅需要读取订阅列表即可。
  • 缺点:写很重。内容生产者每发布一条内容,会导致大量的写操作。

拉模型(读扩散)

为每个内容生产者维护一个内容列表,记录该用户所有生产的内容索引。

  • 优点:写很轻,节省空间。内容生产者每发布一条内容,仅需写入自己的内容列表。
  • 缺点:读很重,计算量大。假设内容消费者订阅了 1k 个生产者,则每次读取都需要从 1k 个生产者的内容列表拉取内容,以获得最新的 n 条内容。

产品形态

产品形态 粉丝数量上限 时间线 排序方式
微博 秒~分 时间
短视频推荐,例如 TikTok 秒~分 推荐
社交分享,例如 微信朋友圈 5000 秒级 时间
私信,例如 微信聊天 1 秒级 时间

所有该类型的产品,都有三个核心的角色:内容生产者、内容、内容消费者。后台系统要做的事情就是保障内容从内容生产者快速、可靠的分发给内容消费者。系统架构的难点在于:

  1. 将一条内容投递给一个消费者,还是投递给亿级的消费者(例如,微博、抖音)
  2. 投递数条内容,还是投递数亿条内容(例如,微信群聊)

产品形态不同,会放大一些技术方案的缺点,最终导致难以扩展或者成本难以接受。对于推模型

  • 订阅上限过高,则会放大写扩散的问题
  • 内容顺序不确定,写扩散同样毫无意义

存储系统

内容生成之后要首先通过写入落地到存储系统中,然后当内容消费者需要的时候再读取出来。不同的存储系统使用了不同的存储模型,首先看下常见的存储模型:

  • B-tree:读取友好,数据有序。LIRS算法,将缓冲池分为两级,数据首先进入第一级,如果数据在较短的时间内被访问两次或者以上,则成为热点数据进入第二级,每一级内部还是采用LRU替换算法。例如:关系型数据库
  • Bitcask:写入友好,数据无序。在内存中存储了主键和value的索引信息,磁盘文件中存储了主键和value的实际内容。需要定期执行合并(Compaction)操作以实现垃圾回收。Bitcask通过索引文件(hint file)来提高重建哈希表的速度。例如:Beandb
  • LSM:写入友好,数据有序。将对数据的修改增量保持在内存中,达到指定的大小限制后将这些修改操作批量写入磁盘,读取时需要合并磁盘中的历史数据和内存中最近的修改操作,需要定期执行合并(Compaction)操作以实现垃圾回收。例如:LevelDB、RocksDB、Bigtable

回过头再看推模型和拉模型,两者对读写性能的要求大不相同:

类型 推模型 拉模型 推-拉模型
读延迟 毫秒
读写比 1:99 99:1 50:50
系统要求 健壮的写入能力 健壮的读取能力 平衡的读写能力
常见系统 采用 LSM 架构的分布式 NoSQL,如 Bigtable 缓存系统如 Redis 和 Memcached 或 搜索系统(推荐场景) 两者结合
架构复杂度 简单 复杂 更复杂

除此之外,由于数据量快速增涨,内容存储还需要方便进行快速的扩容,而不同的存储系统对扩展性的支持存在较大的差异:

特点 分布式 NoSQL 关系数据库 (分库/分表)
扩展性 线性 需要重构
扩展速度 毫秒 N/A
常见系统 Table Store、Bigtable MySQL

总结

选择推模型还是拉模型,需要考虑产品特征,以及存储系统。放眼业界

微信朋友圈使用写扩散:

  • 产品层面:订阅者最多只有5000 (最多 5000 好友)
  • 存储层面:分布式 NoSQL QuorumKVPaxosStore

微博使用读扩散:

  • 产品层面:订阅数没有上限
  • 存储层面:Redis + MySQL

推特

最终,微信很多时间都花费到在了写扩散带来的成本问题;微博很多时间都在应对关系型数据库导致的扩展性问题,以及读扩散导致的”挂了又挂”。Twitter 很多时间都在“纠结”,前期使用写扩散,最后不得不结合读扩散,拥抱 Nosql 最终又回到 MySQL。

推拉模型对于互联网产品的影响至此,重要程度可见一斑

本文作者 : cyningsun
本文地址https://www.cyningsun.com/04-19-2021/content-products-push-or-pull.html
版权声明 :本博客所有文章除特别声明外,均采用 CC BY-NC-ND 3.0 CN 许可协议。转载请注明出处!