阿里妹导读:互联网进入移动互联网时代,最具表明性的产品就是各类信息流,像是朋友圈、微博、头条等。这些移动化联网时代的新产品在过去几年间借着智能手机的风高速成长。这些产品都是Feed流类型产品,因为Feed流通常是按照时间“从上往下流动”,很是适合在移动设备端浏览,最终这一类应用就脱颖而出,迅速抢占了上一代产品的市场空间。
Feed流是Feed + 流,Feed的本意是饲料,Feed流的本意就是有人一直在往一个地方投递新鲜的饲料,若是须要饲料,只须要盯着投递点就能够了,这样就能源源不断获取到新鲜的饲料。 在信息学里面,Feed实际上是一个信息单元,好比一条朋友圈状态、一条微博、一条咨询或一条短视频等,因此Feed流就是不停更新的信息单元,只要关注某些发布者就能获取到源源不断的新鲜信息,咱们的用户也就能够在移动设备上逐条去浏览这些信息单元。算法
当前最流行的Feed流产品有微博、微信朋友圈、头条的资讯推荐、快手抖音的视频推荐等,还有一些变种,好比私信、通知等,这些系统都是Feed流系统,接下来咱们会介绍如何设计一个Feed流系统架构。数据库
Feed流本质上是一个数据流,是将 “N个发布者的信息单元” 经过 “关注关系” 传送给 “M个接收者”。微信
Feed流系统是一个数据流系统,因此咱们核心要看数据。从数据层面看,数据分为三类,分别是:session
针对这三类数据,咱们能够有以下定义:架构
设计Feed流系统时最核心的是肯定清楚产品层面的定义,须要考虑的因素包括:运维
上述是选择数据存储系统最核心的几个考虑点,除此以外,还有一些须要考虑的:分布式
如何实现Meta和Feed内容搜索?优化
虽然Feed流系统自己能够不须要搜索,可是一个Feed流产品必需要有搜索,不然信息发现难度会加大,用户留存率会大幅降低。搜索引擎
Feed流的顺序是时间仍是其余分数,好比我的的喜爱程度?阿里云
接下来,咱们看看整个Feed流系统如何设计。
1. 产品定义
第一步,咱们首先须要定义产品,咱们要作的产品是哪种类型,常见的类型有:
接着,再详细看一下这几类产品的异同:
上述对比中,只对比各种产品最核心、或者最根本特色,其余次要的不考虑。好比微博中互相关注后就是双向关注了,可是这个不是微博的立命之本,只是补充,没法撼动根本。
从上面表格能够看出来,主要分为两种区分:
关注关系是单向仍是双向:
排序是时间仍是推荐:
肯定了产品类型后,还须要继续肯定的是系统设计目标:须要支持的最大用户数是多少?十万、百万、千万仍是亿?
用户数不多的时候,就比较简单,这里咱们主要考虑 亿级用户 的状况,由于若是系统能支持亿级,那么其余量级也能支持。为了支持亿级规模的用户,主要子系统选型时须要考虑水平扩展能力以及一些子系统的可用性和可靠性了,由于系统大了后,任何一个子系统的不稳定都很容易波及整个系统。
2. 存储
咱们先来看看最重要的存储,无论是哪一种同步模式,在存储上都是同样的,咱们定义用户消息的存储为存储库。存储库主要知足三个需求:
因此,存储库最重要的特征就是两点:
综上,能够选为存储库的系统大概有两类:
对于可靠性,分布式NoSQL的可靠性要高于关系型数据库,这个可能有违不少人的认知。主要是关系型数据库发展很长时间了,且很成熟了,数据放在上面你们放心,而分布式NoSQL数据库发展晚,使用的并很少,不太信任。可是,分布式NoSQL须要存储的数据量更多,对数据可靠性的要求也加严格,因此通常都是存储三份,可靠性会更高。目前在一些云厂商中的关系型数据库由于采用了和分布式NoSQL相似的方式,因此可靠性也获得了大幅提升。
水平扩展能力:对于分布式NoSQL数据库,数据自然是分布在多台机器上,当一台机器上的数据量增大后,能够经过自动分裂两部分,而后将其中一半的数据迁移到另外一台机器上去,这样就作到了线性扩展。而关系型数据库须要在扩容时再次分库分表。
因此,结论是:
若是使用Tablestore,那么存储库表设计结构以下:
到此,咱们肯定了存储库的选型,那么系统架构的轮廓有了:
3. 同步
系统规模和产品类型,以及存储系统肯定后,咱们能够肯定同步方式,常见的方式有三种:
推模式(也叫写扩散):和名字同样,就是一种推的方式,发送者发送了一个消息后,当即将这个消息推送给接收者,可是接收者此时不必定在线,那么就须要有一个地方存储这个数据,这个存储的地方咱们称为:同步库。推模式也叫写扩散的缘由是,一个消息须要发送个多个粉丝,那么这条消息就会复制多份,写放大,因此也叫写扩散。这种模式下,对同步库的要求就是写入能力极强和稳定。读取的时候由于消息已经发到接收者的收件箱了,只须要读一次本身的收件箱便可,读请求的量极小,因此对读的QPS需求不大。概括下,推模式中对同步库的要求只有一个:写入能力强。
拉模式(也叫读扩散):这种是一种拉的方式,发送者发送了一条消息后,这条消息不会当即推送给粉丝,而是写入本身的发件箱,当粉丝上线后再去本身关注者的发件箱里面去读取,一条消息的写入只有一次,可是读取最多会和粉丝数同样,读会放大,因此也叫读扩散。拉模式的读写比例恰好和写扩散相反,那么对系统的要求是:读取能力强。另外这里还有一个误区,不少人在最开始设计feed流系统时,首先想到的是拉模式,由于这种和用户的使用体感是同样的,可是在系统设计上这种方式有很多痛点,最大的是每一个粉丝须要记录本身上次读到了关注者的哪条消息,若是有1000个关注者,那么这我的须要记录1000个位置信息,这个量和关注量成正比的,远比用户数要大的多,这里要特别注意,虽然在产品前期数据量少的时候这种方式能够应付,可是量大了后就会事倍功半,得不偿失,切记切记。
推拉结合模式:推模式在单向关系中,由于存在大V,那么一条消息可能会扩散几百万次,可是这些用户中可能有一半可能是僵尸,永远不会上线,那么就存在资源浪费。而拉模式下,在系统架构上会很复杂,同时须要记录的位置信息是天量,很差解决,尤为是用户量多了后会成为第一个故障点。基于此,因此有了推拉结合模式,大部分用户的消息都是写扩散,只有大V是读扩散,这样既控制了资源浪费,又减小了系统设计复杂度。可是总体设计复杂度仍是要比推模式复杂。
用图表对比:
介绍完同步模式中全部场景和模式后,咱们概括下:
若是选择了Tablestore,那么同步库表设计结构以下:
肯定了同步库的架构以下:
4. 元数据
前面介绍了同步和存储后,整个Feed流系统的基础功能完成了,可是对于一个完整Feed流产品而言,还缺元数据部分,接下来,咱们看元数据如何处理:
Feed流系统中的元数据主要包括:
咱们接下来逐一来看。
4.1 用户详情和列表
主要是用户的详情,包括用户的各类自定义属性和系统附加的属性,这部分的要求只须要根据用户ID查询到就能够了。
能够采用的分布式NoSQL系统或者关系型数据库均可以。
若是使用NoSQL数据库Tablestore,那么用户详情表设计结构以下:
4.2 关注或好友关系
这部分是存储关系,查询的时候须要支持查询关注列表或者粉丝列表,或者直接好友列表,这里就须要根据多个属性列查询须要索引能力,这里,存储系统也能够采用两类,关系型、分布式NoSQL数据库。
若是已经有了关系型数据库了,且数据量较少,则选择关系型数据库,好比MySQL等。
若是数据量比较大,这个时候就有两种选择:
若是使用Tablestore,那么关注关系表设计结构以下:
Table:user_relation_table
多元索引Schema:
查询的时候:
4.3 推送session池
思考一个问题,发送者将消息发送后,接收者如何知道本身有新消息来了?客户端周期性去刷新?若是是这样子,那么系统的读请求压力会随着客户端增加而增加,这时候就会有一个风险,好比平时的设备在线率是20%~30%,忽然某天平台爆发了一个热点消息,大量休眠设备登录,这个时候就会出现“查询风暴”,一会儿就把系统打垮了,全部的用户都不能用了。
解决这个问题的一个思路是,在服务端维护一个推送session池,这个里面记录哪些用户在线,而后当用户A发送了一条消息给用户B后,服务端在写入存储库和同步库后,再通知一下session池中的用户B的session,告诉他:你有新消息了。而后session-B再去读消息,而后有消息后将消息推送给客户端。或者有消息后给客户端推送一下有消息了,客户端再去拉。
这个session池使用在同步中,可是本质仍是一个元数据,通常只须要存在于内存中便可,可是考虑到failover状况,那就须要持久化,这部分数据因为只须要指定单Key查询,用分布式NoSQL或关系型数据库均可以,通常复用当前的系统便可。
若是使用Tablestore,那么session表设计结构以下:
5. 评论
除了私信类型外,其余的feed流类型中,都有评论功能,评论的属性和存储库差很少,可是多了一层关系:被评论的消息,因此只要将评论按照被被评论消息分组组织便可,而后查询时也是一个范围查询就行。这种查询方式很简单,用不到关系型数据库中复杂的事务、join等功能,很适合用分布式NoSQL数据库来存储。
因此,通常的选择方式就是:
若是选择了Tablestore,那么“评论表”设计结构以下:
若是须要搜索评论内容,那么对这张表创建多元索引便可。
6. 赞
最近几年,“赞”或“like”功能很流行,赞功能的实现和评论相似,只是比评论少了一个内容,因此选择方式和评论同样。
若是选择了Tablestore,那么“赞表”设计结构同评论表,这里就再也不赘述了。
系统架构中加了元数据系统后的架构以下:
到此,咱们已经介绍完了Feed流系统的主题架构,Feed流系统算是完成了。可是Feed流产品上还未结束,对于全部的feed流产品都须要有搜索能力,好比下面场景:
这些内容搜索只须要字符匹配到便可,不须要很是复杂的相关性算法,因此只须要有能支持分词的检索功能便可,因此通常有两种作法:
因此,选择的原则以下:
若是使用Tablestore,那么只须要在相应表上创建多元索引便可:
系统架构中加了搜索功能后的架构以下:
8. 排序
目前的Feed流系统中的排序方式有两种,一种是时间,一种是分数。
咱们经常使用的微博、朋友圈、私信这些都是时间线类型的,由于这些产品定义中,须要咱们主动关注某些人后才会看到这些人发表的内容,这个时候,最重要的是实时性,而不是发布质量,就算关注人发布了一条垃圾信息,咱们也会被动看到。这种类型的产品适用于按照时间线排序。这一篇咱们介绍的架构都是基于时间类型的。
另一种是不须要关注任何人,咱们能看到的都是系统但愿咱们看到的,系统在后台会分析咱们的每一个人的爱好,而后给每一个人推送差别化的、各自喜欢的内容,这一种的架构和基于时间的彻底不同,咱们在后续的推荐类型中专门介绍。
9. 删除Feed内容
在Feed流应用中有一个问题,就是若是用户删除了以前发表的内容,系统该如何处理?由于系统里面有写扩散,那么删除的时候是否是也要写扩散一遍?这样的话,删除就不及时了,很难应对法律法规要求的快速删除。
针对这个问题,咱们在以前设计的时候,同步表中只有消息ID,没有消息内容,在用户读取的时候须要到存储库中去读消息内容,那么咱们能够直接删除存储库中的这一条消息,这样用户读取的时候使用消息ID是读不到数据的,也就至关于删除的内容,并且删除速度会很快。除了直接删除外,另一种办法是逻辑删除,对于删除的feed内容,只作标记,当查询到带有标记的数据时就认为删除了。
10. 更新Feed内容
更新和删除Feed处理逻辑同样,若是使用了支持多版本的存储系统,好比Tablestore,那么也能够支持编辑版本,和如今的微博同样。
11. 总结
上面介绍了不一样子功能的特色和系统要求,能知足需求的系统主要有两类,一类是阿里云的Tablestore单系统,一类是开源组件组成的组合系统。
开源组件组成的组合系统:包括MySQL、Redis、HBase等,这些系统单个都不能解决Feed流系统中遇到的问题,须要组合在一块儿,各司其职才能完成一个Feed流系统,适用于热衷开源系统,人多且喜欢运维操做的团队。
Tablestore单系统:只使用Tablestore单个系统就能解决上述的全部问题,这时候确定有人要问?你是否是在吹牛? 这里不是吹牛,Tablestore在三年前就已经开始重视Feed流类型业务,以前也发表过多篇文章介绍,功能上也在专门为Feed流系统特别定制设计,因此到今天,只使用Tablestore一款产品,是能够知足上述需求的。选择Tablestore作Feed流系统的用户具备如下一些特征:
若是具备上述四个特征的任何一个,那么都是适合于用Tablestore。
上面咱们介绍了Feed流系统的设计理论,具体到不一样的类型中,会有不一样的侧重点,下面会逐一介绍。
朋友圈
朋友圈是一种典型的Feed流系统,关系是双写关系,关系有上限,排序按照时间,若是有我的持续产生垃圾内容,那就只能屏蔽掉TA,这一种类型就是典型的写扩散模型。
微博
微博也是一种很是典型的Feed流系统,但不一样于朋友圈,关系是单向的,那么也就会产生大V,这个时候就须要读写扩散模式,用读扩散解决大V问题。同时,微博也是主动关注类型的产品,因此排序也只能是时间,若是按照推荐排序,那么效果就会比较差。
头条
头条是最近几年快速崛起的一款应用,在原有微博的Feed流系统上产生了进化,用户不须要主动关注其余人,只要初始浏览一些内容后,系统就会自动判断出你的喜爱,而后后面再根据你的喜爱给你推荐你可能会喜爱的内容,训练时间长了后,推送的内容都会是你最喜欢看的。
私信
私信也算是一种简单的Feed流系统,或者也能够认为是一种变相的IM,都是单对单的,没有群。
本文来自云栖社区合做伙伴“阿里技术”,如需转载请联系原做者。