方案分析

根据Feed流中的数据类型,本文分别设计系统存储、同步与元数据方案。不同类型的Feed流产品架构存在差异,本文设计的产品是基于单向关系的时间排序Feed流,类似于微博。

存储

Feed流系统中的存储库主要存放具体的用户Feed消息,而Feed消息具备以下特点:

  • 数据量大,很容易达到100 TB,甚至PB级别。

  • 数据可靠性要求高,不能丢失数据。

因此根据以上特点,存储库有几个问题是设计的关键:

  • 如何能支持100 TB,甚至PB级数据量?

  • 数据量与成本成正比,如何能降低成本?

  • 如何保证Feed不丢失?

  • 确保消息ID在个人发件箱中严格递增,这样读取时只需要范围读取即可。由于个人发布的Feed并发度很低,用时间戳也能满足基本需求,但是当应用层队列堵塞,网络延迟变大或时间回退时,用时间戳还是无法保证严格递增。最好的方法是使用主键自增功能。

最佳的存储库应该是具有主键自增功能的分布式NoSQL数据库,但是在开源系统里没有完全符合特点的数据库,所以有两种存储方案:

对比项

表格存储

关系型数据库(分库分表)

可靠性

极高可靠性,119SLA保障

可靠性低于非关系型数据库,关系型数据库的可靠性通常最多69

运维复杂度

简单,无需分库分表

复杂,需要分库分表,带来了逻辑层和数据层的极大耦合性

主键自增功能

不需要加锁

需要加锁,且表锁会严重限制并发度,影响性能

阿里云的表格存储也属于有序性的分布式NoSQL数据库,具有以下优势:

  • 单表支持10万亿行+、10 PB+的数据量,再快的数据增长速度都无需担心。

  • 数据按主键列排序,可保证有序性和可预期性。

  • key读写延迟在毫秒级别,可保证响应时间。

  • 两种实例类型:高性能实例可提供极佳的读写性能;容量型实例可提供低存储成本。

通过对比分析,表格存储在功能、性能、扩展性以及成本方面都要更加适合存储Feed消息。

使用表格存储后,系统的架构如图所示:

image

同步

方案选择

Feed消息的同步主要有读扩散和写扩散两种方案:

  • 读扩散(拉模式):用户发送消息时存入自己的发信箱,并不主动推送给其他用户。当其他用户获取Feed流时,系统需要去各个用户的发信箱中主动拉取。

  • 写扩散(推模式):用户发送消息时存入自己的发信箱,同时会主动推动给其他用户,写入他们的收件箱。当其他用户获取Feed流时,系统只需按顺序读取收件箱中的消息即可。

image

读扩散和写扩散的对比请参见下表。

对比

读扩散(拉模式)

写扩散(推模式)

网络最大开销时刻

获取Feed流时

发布Feed

读写放大

放大读

放大写

读写比例

99:1

1:99

用户读取延时

毫秒

系统要求

读能力强

写能力强

架构复杂度

复杂

简单

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

因此可以看出,推模式优于拉模式,但是推模式也有一个缺点:数据会极大膨胀。针对这个缺点,可以考虑采用推拉结合模式。具体内容,请参见方案扩展

架构设计

Feed流系统最大的特点是读写严重不平衡,一般读写比例都在10:1,甚至100:1之上。并且刷新Feed时的延时本质上由推送方案决定,其他的任何操作都只能是优化。设计推送系统具有以下关键点:

  • 如何才能提供千万的TPSQPS?

  • 如何保证读写延迟在10ms,甚至2ms以下?读写直接会影响用户发布,刷新Feed流时的延迟,尤其是极其敏感的刷新时的延迟。

  • 如何保证Feed的必达性?

如果要实现一个千万量级的Feed流产品,那么推送系统需要具备:

  • 千万TPS/QPS的能力。

  • 读写链路延迟低。

  • Feed消息的必达性高。

  • 主键自增功能,保证用户收件箱中的Feed ID是严格递增的,保证可以通过Scan读取到最新未读消息。

  • 最好能为用户存储Timeline中所有的Feed。

从上述特点来看,搭建推送系统最优的选择是使用高性能、高可靠,且有自增功能的NoSQL系统。在开源方案中,通常会在选择了关系型数据库作为存储系统的基础上,选择开源Redis,这样既能覆盖上述的几个特征,还能保证Feed流系统正常运行起来,但是也会带来一些其他问题:

表格存储

Redis

存储成本

磁盘性数据库,费用比内存性的要低几个量级。

纯内存系统,内存价格极高,导致整体成本高。

运维复杂度

运维简单,单表可存储十万亿行以上的数据;天然分布式,单表可支持千万级TPS/QPS

属于单机系统,为了支持千万TPS和保证消息必达性,需要使用clusterreplica模式,这样不仅带来了运维的复杂性,而且还需要增加机器,导致成本再次上升。

综上,Feed流系统的消息同步可以选择使用表格存储。在加入同步功能后,系统架构如下图所示:

image

元数据

处理系统基本的存储和推送功能外,还需要对元数据进行处理,元数据包括用户信息和用户关系等。下面以用户关系进行介绍。

用户账号之间的关注关系具有如下特点:

  • 变长链表,长度可达亿级别。

  • 数据量大,但关系简单。

  • 性能敏感。直接影响关注、取关的响应速度。

  • 有序性。不要求具有排序功能,只需要能按照主键排序即可。只要能按照主键排序,那么关注列表和粉丝列表的顺序就固定、可预期。

根据以上特点,最适合存账号关系的方案应该是分布式NoSQL服务。很多企业选择开源HBase来存储账号关系,开源HBase在满足了上述四个特征的同时可以把系统搭建起来,但是仍会有如下问题:

对比项

表格存储

开源HBase

运维复杂度

全托管的分布式NoSQL存储服务,无需任何运维

需要自己运维、调查问题、修复问题,运维成本高

毛刺问题

C++实现,彻底无GC问题,不会由于GC而导致较大的毛刺

GC会导致比较大的毛刺,影响用户体验

以上可见,使用表格存储来存储账号关系是一个比较好的选择。

在加入关系表、用户表后,系统架构如下图所示:

image