推送方案分两种模式:拉模式(读扩散)、推模式(写扩散)。本章节主要为您对比拉模式和推模式,并介绍搭建推送系统的数据库选择。

设计思路

Feed流系统最大的特点是读写严重不平衡,一般读写比例都在10:1,甚至100:1之上。并且刷新Feed时的延时本质上由推送方案决定,其他的任何操作都只能是优化。设计推送系统具有以下关键点:
  • 如何才能提供千万的TPS和QPS?
  • 如何保证读写延迟在10ms,甚至2ms以下?
  • 如何保证Feed的必达性?

推模式和拉模式对比

拉模式和推模式在很多方面完全相反,并且对Feed流产品的用户而言,刷新Feed流(读取)时的延迟敏感度要远远大于发布(写入)。以下是推模式和拉模式的对比:

对比项 拉模式(读扩散) 推模式(写扩散)
发布 个人页Timeline(发件箱) 粉丝的关注页面(收件箱)
阅读 所有关注者的个人页Timeline 自己的关注页Timeline
网络最大开销 用户刷新时 发布Feed时
读写放大 放大读,读写比例到1万:1 放大写,减小读,读写比例到50:50
个性化 不支持 支持
定向广告 不支持 支持
以上对比可以看出,推模式要远优于拉模式,但是推模式也有一个缺点:数据会极大膨胀。针对这个缺点,可以从两个方面考虑:
  • 以后存储成本会随着硬件技术升级、软件性能优化等继续降低。数据量越大价格越低。
  • 如仍需减少成本,可以继续优化,可以对大V采用拉模式,普通用户使用推模式。对活跃粉丝采用推模式,非活跃粉丝采用拉模式(这种方式可以较好的避免大流量对平台的冲击)。

适用场景

以下是不同模式的适用场景。

模式 适用场景
拉模式(读扩散) 很多Feed流产品的第一版会采用这种方案,但很快就会抛弃。如采用拉模式 + 图计算,重心就会转换为图计算。
推模式(写扩散)
  • Feed流系统中最常用、有效的模式。
  • 用户关系数比较均匀,或者有上限,例如朋友圈。
  • 偏推荐类,同一个Feed对不同用户价值不同,需要为不同用户计算分数,例如Pinterest。
推拉结合 大部分用户的账号关系都是几百个,但是有个别用户是1000万以上,例如微博。

数据库选择

如果要实现一个千万量级的Feed流产品,那么推送系统需要具备:
  • 千万TPS/QPS的能力。
  • 读写链路延迟敏感。读写直接会影响用户发布,刷新Feed流时的延迟,尤其是极其敏感的刷新时的延迟。
  • Feed消息的必达性高。
  • 主键自增功能,保证用户收件箱中的Feed ID是严格递增的,保证可以通过Scan(上次读取的最大ID --->MAX)读取到最新未读消息。
  • 最好能为用户存储Timeline中所有的Feed。
从上述特点来看,搭建推送系统最优的选择是使用高性能、高可靠,且有自增功能的NoSQL系统:
  • 开源Redis
    如果选择开源系统,通常会在选择了关系型数据库作为存储系统的基础上,选择开源Redis,这样既能覆盖上述的几个特征,还能保证Feed流系统正常运行起来,但是也会带来一些其他问题:
    • 纯内存系统,内存价格极高,导致整体成本高。
    • 属于单机系统,为了支持千万TPS和保证消息必达性,需要使用cluster和replica模式,这样不仅带来了运维的复杂性,而且还需要增加机器,导致成本再次上升。
    • 成本上升了以后,需考虑是如何成本。要节省成本只能是减少开源Redis里面存储的数据量,一般有两种做法:在开源Redis中存储Feed ID、不存储Feed内容。采用这两种方法,整体数据量会大量减少,但是在读取的时候需要先读Feed ID,然后在到存储系统里面去读取Feed内容,网络开销增长了一倍,而且是串行的,对用户的刷新延迟有较大影响。只对普通用户或者活跃用户使用推模式,对大V和非活跃用户直接使用拉模式。
    • 上述两个方案虽然可以节省成本,但是是以牺牲用户体验为代价的,最终需要在成本和用户体验之间权衡。
  • 表格存储
    除了使用开源系统外,还可以使用阿里云的表格存储,有不少用户选择表格存储作为推送系统的原因无非下面几点:
    • 天然分布式,单表可支持千万级TPS/QPS。
    • LSM存储引擎极大优化写,高性能实例极大优化读。
    • 写入成功即保证落盘成功,数据可靠性提供10个9的SLA保障。
    • 磁盘性数据库,费用比内存性的要低几个量级。
    • 单表可存储十万亿行以上的数据,价格又低,轻松保存用户Feed流中的所有Feed数据。

上面分析了使用开源Redis和阿里云表格存储的异同,如果使用开源数据库可以用Redis,如果选择阿里云NoSQL数据库,可以选择使用表格存储。