朋友圈不知你看到的那么简单,千万Feed流系统的存储技术解密

时间:2024-04-08 12:17:32
摘要:阿里巴巴高级技术专家木洛在2018云栖大会·深圳峰会中就Feed流的概念介绍、概念架构以及TableStore场景的Timeline模型等方面的内容做了深入的分析。本文带领大家一起了解并学习如何通过存储系统的性能特性,通过Feed流中的消息存储和推送机制支撑起千万Feed流的并发。

数十款阿里云产品限时折扣中,赶紧点击这里,领劵开始云上实践吧!

以下内容根据演讲嘉宾PPT以及视频整理而成(云栖社区做了不修改原意的编辑)。
朋友圈不知你看到的那么简单,千万Feed流系统的存储技术解密 

本次的分享主要围绕以下三个方面:
一、概念介绍
二、Feed流系统架构
三、TableStore Timeline

一、概念介绍
下图为比较抽象的Feed流系统,系统被分为Feed,Feed流以及Feed订阅三个层次。Feed可以看作消息体,消息体就像我们发送的信息,平时发布的动态,新闻App中的一条新闻,或者推荐的内容,我们将这些统称为Feed。Feed产生之后,通过Feed流被推送到Feed订阅端,这个过程就是典型的Feed三层系统。Feed是一种实时消息,由于消息是实时产生,实时消费,实时推送的,因此满足实时性是关键。另外消息来自于很多不同的消息源,消息的产生属于海量级别。Feed流是实时推送的有序的可扩散的消息流,Feed产生之后,我们通常会将这些Feed推送给Feed的订阅端,推送的过程中需要满足有序,可扩散的原则。消息顺序有时间线类型,即按照消息产生的时间对消息进行排序;也有Rank类型,这种类型主要出现在推荐信息中,根据某些算法或消息所处的类别找到最相关的订阅端。一个消息可能是由单个消息体产生的,而这个消息体可以扩散到很多的订阅端,从消息产生到消息消费产生巨大的读写比。
朋友圈不知你看到的那么简单,千万Feed流系统的存储技术解密
 
下图展示了常见的Feed应用,朋友圈中的Feed就是每个人发布的动态,动态通过朋友圈的Feed流扩散到好友,同时每个人也可以在朋友圈中订阅到好友发布的动态。微博也是较为常见的Feed应用。Pinterest是国外关于图片的社交系统,与其它Feed系统不同的是,Pinterest的Feed就是图片。雪球的动态广场是一个讨论组,大家可以在讨论组里发布消息,讨论组的人也可以订阅组内消息。
朋友圈不知你看到的那么简单,千万Feed流系统的存储技术解密 
二、Feed流系统架构
下面为大家举例介绍主要Feed流整体架构的实现。在讲架构实现的时候,本文会先介绍一个简单且为大家所熟知的案例。如下图所示,朋友圈是大家常用的社交平台,首先定义某个功能实现需要满足什么需求。第一点是朋友圈中的动态:在消息发送方面,消息会存到个人相册,每个人能在个人相册中看到自己发布的所有动态,并且这些动态是永久保存的,我们可以翻到N多年前自己发布的消息,所以这些消息有一个很长时间的保存状态;另外消息会扩散到好友的朋友圈,消息保存在持有好友关系的朋友圈;同时我们的朋友圈也保存着好友发的动态,作为消息保存。朋友圈中不仅仅只有发布的动态,也可能有一些广告,这些广告是由广告系统推荐过来的。以上是朋友圈简单的Feed流功能需求分析。总结功能需求如下图中所示:
 朋友圈不知你看到的那么简单,千万Feed流系统的存储技术解密
人与人之间组建好友关系,朋友圈用于查看好友圈内的人发送的所有消息,按照动态发布的时间进行时间排序;广告系统可向朋友圈内插入广告消息,这是一个rank的消息;个人相册用于查看个人发送的所有消息。并且,个人相册和朋友圈是有所区别的,个人相册中需要永久保存个人发布的动态,但是朋友圈可以只看最近一段时间的消息,这点在我们之后设计消息系统时,会有所区别。
针对上文所说的朋友圈场景,下文为大家介绍一个简单的Feed流系统架构大概会分为哪几个模块。如下图所示,首先会设计一个端,用来发送消息或者接收消息,这就是消息的入口。其次,会有接入层,我们通常把它叫做消息服务器,这些消息服务器通常是由一组无状态的服务器组成的,主要职能是接收消息,处理消息以及当端读消息时的同步消息。接入层算是比较简单的实现,通常都是一些API网关,提供特定消息处理的API,并且涉及到消息协议中的特定实现,包括数据加密,优化的通信等。最核心的是后台服务,如下图所示,把后台服务简单化为两块,第一块是消息系统,消息系统是整个Feed流架构中最核心的部分,负责对消息进行持久化,个人的消息会先持久化都自己的库中;其次负责对消息进行同步,将消息同步给自己的好友或者抽取某些好友订阅自己的消息。广告系统会找到和广告最关联的人群,向这些人推送消息。消息系统下面最核心的是两个库的设计,一个是消息存储库,另外一个是消息同步库。这两个库的区别在于,消息存储库往往是用于永久存储所有人发布的所有消息;消息同步用来将一条消息向该同步的人同步。因为广告系统需要将广告推动给关联的人群,所以广告系统会和消息同步库打交道,同时,由于广告是不需要永久存储的,所以不需要和消息存储打交道。下图中最核心的是消息系统的设计,它的设计与实现和Feed流中的消息发送,订阅以及特征非常相关。
朋友圈不知你看到的那么简单,千万Feed流系统的存储技术解密 
接下来我们看一下,当我们设计一个消息系统时,一定要足够了解系统的场景,了解在这个场景里面,这个消息系统需要满足什么要求。
如下图所示,将要求归为三:
类,第一类我们需要了解Feed流系统中消息的特征是什么:第一个特征是典型的读多写少,读多写少的含义就是我们在朋友圈中通常是读动态,很少人去发消息,读写比大概为100:1;第二个消息模型比较简单,就是消息体,或者消息,消息里面可能会有发送人,接收人,消息时间等属性。在消息确定时模型中的数据已经确定了,而且消息与消息之间是没有关联的;第三个是弱关系型数据,就是消息不会和其他数据产生关联,只是流式产生的一条条消息;第四个是波峰波谷式访问,指消息系统承载的流量呈现出波峰波谷式访问的特征,因为Feed流系统通常属于社交类系统,社交系统的活跃度取决于人群的活跃度,人群的活跃度会有很明显的波峰波谷。上述四种特征对于我们以后设计消息系统时选择消息存储的数据库是至关重要的,也具有参考意义。
第二类是关于消息存储,个人相册是需要永久存储的,存储量随着时间的推移会越来越大。因为消息的读写是在线的,不可能用一个本地存储,所以消息存储要求拥有在线永久存储的能力。同时,朋友圈中的动态需要保证高可靠性,不能轻易丢失。当应用达到很大的用户量时存储的消息容量会很巨大,处在PB级,属于万亿行的规模。
第三类关于消息同步,消息的产生与推送都对消息库产生很大的压力,需要能够应对海量消息;需要实现实时同步,多端同步;同步模型包括写扩散和读扩散。下面举一个例子理解一下写扩散和读扩散。一个人有100个好友,他在朋友圈中发布了一条动态,动态是如何同步到100个好友的朋友圈的呢?解决方案有两种,第一,每个人都有一个收件箱,向每个人的收件箱中投递一个消息。这种方案的好处在于,因为每个人都有一个收件箱,所有我们只需要查看收件箱,就可以看到别人给我传递的消息,对读有很大的优化,相对而言缺点是消息的写操作是需要扩散的,扩散的比例就是好友的个数,以上是写扩散的优劣。第二,采用读扩散,读扩散的好处在于数据只需要写一份,比如说将消息存储在我们自己的库中就行了,坏处是当我们需要拉取新的消息时,假设要获取100个好友的新信息,我们就需要从100个人那边拉取新消息,这对系统产生较大的读压力。以上是写扩散和读扩散的主要区别。
实际上,Feed流系统读写比例是100:1,读操作是非常多的,在这种数据特征下,如果我们继续采用读扩散,将会把读写比拉的更大,有可能将100:1拉到1000:1,这会导致在设计消息系统容量时,取读或者写的最高上限,上限拉高之后,对系统要求的能力也会变高,对系统的成本要求也越高。这时,如果采用写扩散,将把写的比例拉高,使读写比取得均衡,对系统的预留资源要,所以在Feed流系统中通常采用写扩散这个模式。但是,写扩散有一个缺点,写会扩散很多份,当朋友圈中有1万个好友,写扩散缺点会很明显,因此可以采用混合模式进行优化,例如大部分消息采用写扩散,对于扩散比例很高的消息可以采用读扩散。有一个优化方式,
朋友圈不知你看到的那么简单,千万Feed流系统的存储技术解密 
在了解了消息的特征,存储和同步后,我们接下来就要选择合适的数据库,下图展示了NoSQL的解决方案。NoSQL的解决方案关注容量,服务能力,分布式支持,售卖模式以及数据模型。在容量方面,传统关系型数据库的容量在TB级别,而NoSQL采用分布式,所以容量在10PB级别。服务能力方面,十万TPS对应于千万TPS。分布式支持方面,对于这样海量数据的系统来说,必须采用分布式,在图中,分库分表对原生支持。售卖模式方面,按规格计费对按量计费,由于Feed流系统是一个具有波峰波谷式特征的系统,按量模式的售卖模式能帮助节约很多成本。数据模型方面,关系型对弱关系型,弱关系型在Feed流系统下也是满足需求的。
 朋友圈不知你看到的那么简单,千万Feed流系统的存储技术解密
三、TableStore Timeline
TableStore为了简化Feed流系统的开发,之后就推出了TableStore Timeline。下图是Timeline简单逻辑模型。如下图所示,消息会有一个发送端(A),消息会有订阅端(B1,B2,B3),消息同步通过队列,是一个虚拟的队列,消息需要同步给谁,就将消息发到队列中。队列提供的功能有以下几个:
每个消息都有一个顺序ID,用来完成消息的同步,由于每个接收端同步的速度是不同的,每个接收端会保留自己的同步位点,在进行消息同步时,只需要通过同步位点,到消息列表中随机定位,定位之后拉取所有需要同步的消息,这是一个简单的模型。对于每个人的收件箱以及发件箱,都是一个独立的Timeline,在底层数据库中存储的内容就变成了每个人的收件箱以及发件箱,如果有1000万的用户,数据库中就需要存储1000万的timeline,在这种情况下,数据库就要达到千亿万亿的规模。
 朋友圈不知你看到的那么简单,千万Feed流系统的存储技术解密
下面我们一起看下,基于Timeline的消息系统的架构实现,如下图所示。图中有几条关键路径,首先是消息的写操作,消息是如何写的,写完如何做同步。;第二个是消息的读。对于消息的写,首先端上发送一个消息到消息服务器;通常消息服务器为了异步化批量处理消息,都会将消息写进消息队列;消息队列中的消息会进行专门的消息处理;每个消息上传到服务器之后,将消息存储到个人相册中,个人相册存储在消息存储库中,其中存储着每个人的timeline,每个人读自己对应的timeline就可以读取自己的动态;在存储timeline之后,需要将消息同步到自己所有的好友,采取写扩散的消息同步模型;最后,选定所有的好友,将自己的消息发送到所有好友的收件箱,因此消息同步库中存储的是所有好友的收件箱。同步消息通常会看两个地方,一个是个人相册,从消息存储库中根据同步位点拉取内容。同时,我们只需要从消息同步库中拉取自己的收件箱,就可以看到还有发送的所有消息。消息存储库与消息同步库有不同的要求,消息存储库要求PB级数据低成本永久存储,消息同步库需要提供高并发及低延迟读,另外,需要存储每个用户的收件箱数据,数据生命周期为半年。TableStore提供的功能为容量型提供低成本存储,高性能提供低延迟读,以及PB级存储,毫秒级延迟。
 朋友圈不知你看到的那么简单,千万Feed流系统的存储技术解密
下图展示了Timeline性能的实验分析结果,可以看到在同步100万扩散写时,比如说我将消息发给100万个人,在8核机器上,只需要3.7s的时间。在16核机器上,并发读取数据能达到4万QPS。
 朋友圈不知你看到的那么简单,千万Feed流系统的存储技术解密
本文由云栖志愿小组沈金凤整理,编辑百见