# Feed流系统特点
Feed流本质上是一个数据流,是将 “N个发布者的信息单元” 通过 “关注关系” 传送给 “M个接收者”。
Feed流系统是一个数据流系统,所以我们核心要看数据。从数据层面看,数据分为三类,分别是:
-
发布者的数据:发布者产生数据,然后数据需要按照发布者组织,需要根据发布者查到所有数据,比如微博的个人页面、朋友圈的个人相册等。
-
关注关系:系统中个体间的关系,微博中是关注,是单向流,朋友圈是好友,是双向流。不管是单向还是双向,当发布者发布一条信息时,该条信息的流动永远是单向的。
-
接收者的数据:从不同发布者那里获取到的数据,然后通过某种顺序(一般为时间)组织在一起,比如微博的首页、朋友圈首页等。这些数据具有时间热度属性,越新的数据越有价值,越新的数据就要排在最前面。
针对这三类数据,我们可以有如下定义:
-
存储库:存储发布者的数据,永久保存。
-
关注表:用户关系表,永久保存。
-
同步库:存储接收者的时间热度数据,只需要保留最近一段时间的数据即可。
-
设计Feed流系统时最核心的是确定清楚产品层面的定义,需要考虑的因素包括:
-
产品用户规模:用户规模在十万、千万、十亿级时,设计难度和侧重点会不同。
-
关注关系(单向、双向):如果是双向,那么就不会有大V,否则会有大V存在。
上述是选择数据存储系统最核心的几个考虑点,除此之外,还有一些需要考虑的:
- 如何实现Meta和Feed内容搜索?
虽然Feed流系统本身可以不需要搜索,但是一个Feed流产品必须要有搜索,否则信息发现难度会加大,用户留存率会大幅下降。
- Feed流的顺序是时间还是其他分数,比如个人的喜好程度?
双向关系时由于关系很紧密,一定是按时间排序,就算一个关系很紧密的人发了一条空消息或者低价值消息,那我们也会需要关注了解的。
单向关系时,那么可能就会存在大V,大V的粉丝数量理论极限就是整个系统的用户数,有一些产品会让所有用户都默认关注产品负责人,这种产品中,该负责人就是最大的大V,粉丝数就是用户规模。
接下来,我们看看整个Feed流系统如何设计。
# Feed流系统设计
上一节,我们提前思考了Feed流系统的几个关键点,接下来,在这一节,我们自顶向下来设计一个Feed流系统。
1. 产品定义
第一步,我们首先需要定义产品,我们要做的产品是哪一种类型,常见的类型有:
-
微博类
-
朋友圈类
-
抖音类
-
私信类
接着,再详细看一下这几类产品的异同:
上述对比中,只对比各类产品最核心、或者最根本特点,其他次要的不考虑。比如微博中互相关注后就是双向关注了,但是这个不是微博的立命之本,只是补充,无法撼动根本。
从上面表格可以看出来,主要分为两种区分:
- 关注关系是单向还是双向:
如果是单向,那么可能就会存在大V效应,同时时效性可以低一些,比如到分钟级别;
如果是双向,那就是好友,好友的数量有限,那么就不会有大V,因为每个人的精力有限,他不可能主动加几千万的好友,这时候因为关系更精密,时效性要求会更高,需要到秒级别。
- 排序是时间还是推荐:
用户对feed流最容易接受的就是时间,目前大部分都是时间。
但是有一些场景,是从全网数据里面根据用户的喜好给用户推荐和用户喜好度最匹配的内容,这个时候就需要用推荐了,这种情况一般也会省略掉关注了,相对于关注了全网所有用户,比如抖音、头条等。
确定了产品类型后,还需要继续确定的是系统设计目标:需要支持的最大用户数是多少?十万、百万、千万还是亿?
用户数很少的时候,就比较简单,这里我们主要考虑 亿级用户 的情况,因为如果系统能支持亿级,那么其他量级也能支持。为了支持亿级规模的用户,主要子系统选型时需要考虑水平扩展能力以及一些子系统的可用性和可靠性了,因为系统大了后,任何一个子系统的不稳定都很容易波及整个系统。
2. 存储
我们先来看看最重要的存储,不管是哪种同步模式,在存储上都是一样的,我们定义用户消息的存储为存储库。存储库主要满足三个需求:
-
可靠存储用户发送的消息,不能丢失。否则就找不到自己曾经发布到朋友圈状态了。
-
读取某个人发布过的所有消息,比如个人主页等。
-
数据永久保存。
所以,存储库最重要的特征就是两点:
-
数据可靠、不丢失。
-
由于数据要永久保存,数据会一直增长,所以要易于水平扩展。
综上,可以选为存储库的系统大概有两类:
-
对于可靠性,分布式NoSQL的可靠性要高于关系型数据库,这个可能有违很多人的认知。主要是关系型数据库发展很长时间了,且很成熟了,数据放在上面大家放心,而分布式NoSQL数据库发展晚,使用的并不多,不太信任。但是,分布式NoSQL需要存储的数据量更多,对数据可靠性的要求也加严格,所以一般都是存储三份,可靠性会更高。目前在一些云厂商中的关系型数据库因为采用了和分布式NoSQL类似的方式,所以可靠性也得到了大幅提高。
-
水平扩展能力:对于分布式NoSQL数据库,数据天然是分布在多台机器上,当一台机器上的数据量增大后,可以通过自动分裂两部分,然后将其中一半的数据迁移到另一台机器上去,这样就做到了线性扩展。而关系型数据库需要在扩容时再次分库分表。
所以,结论是:
-
如果是自建系统,且不具备分布式NoSQL数据库运维能力,且数据规模不大,那么可以使用MySQL,这样可以撑一段时间。
-
如果是基于云服务,那么就用分布式NoSQL,比如Tablestore或Bigtable。
-
如果数据规模很大,那么也要用分布式NoSQL,否则就是走上一条不归路。
如果使用Tablestore,那么存储库表设计结构如下:
到此,我们确定了存储库的选型,那么系统架构的轮廓有了:
3. 同步
系统规模和产品类型,以及存储系统确定后,我们可以确定同步方式,常见的方式有三种:
-
推模式(也叫写扩散):和名字一样,就是一种推的方式,发送者发送了一个消息后,立即将这个消息推送给接收者,但是接收者此时不一定在线,那么就需要有一个地方存储这个数据,这个存储的地方我们称为:同步库。推模式也叫写扩散的原因是,一个消息需要发送个多个粉丝,那么这条消息就会复制多份,写放大,所以也叫写扩散。这种模式下,对同步库的要求就是写入能力极强和稳定。读取的时候因为消息已经发到接收者的收件箱了,只需要读一次自己的收件箱即可,读请求的量极小,所以对读的QPS需求不大。归纳下,推模式中对同步库的要求只有一个:写入能力强。
-
拉模式(也叫读扩散):这种是一种拉的方式,发送者发送了一条消息后,这条消息不会立即推送给粉丝,而是写入自己的发件箱,当粉丝上线后再去自己关注者的发件箱里面去读取,一条消息的写入只有一次,但是读取最多会和粉丝数一样,读会放大,所以也叫读扩散。拉模式的读写比例刚好和写扩散相反,那么对系统的要求是:读取能力强。另外这里还有一个误区,很多人在最开始设计feed流系统时,首先想到的是拉模式,因为这种和用户的使用体感是一样的,但是在系统设计上这种方式有不少痛点,最大的是每个粉丝需要记录自己上次读到了关注者的哪条消息,如果有1000个关注者,那么这个人需要记录1000个位置信息,这个量和关注量成正比的,远比用户数要大的多,这里要特别注意,虽然在产品前期数据量少的时候这种方式可以应付,但是量大了后就会事倍功半,得不偿失,切记切记。
-
推拉结合模式:推模式在单向关系中,因为存在大V,那么一条消息可能会扩散几百万次,但是这些用户中可能有一半多是僵尸,永远不会上线,那么就存在资源浪费。而拉模式下,在系统架构上会很复杂,同时需要记录的位置信息是天量,不好解决,尤其是用户量多了后会成为第一个故障点。基于此,所以有了推拉结合模式,大部分用户的消息都是写扩散,只有大V是读扩散,这样既控制了资源浪费,又减少了系统设计复杂度。但是整体设计复杂度还是要比推模式复杂。关注微信订阅号码匠笔记,回复架构获取一些列的架构知识。
用图表对比:
介绍完同步模式中所有场景和模式后,我们归纳下:
-
如果产品中是双向关系,那么就采用推模式。
-
如果产品中是单向关系,且用户数少于1000万,那么也采用推模式,足够了。
-
如果产品是单向关系,单用户数大于1000万,那么采用推拉结合模式,这时候可以从推模式演进过来,不需要额外重新推翻重做。
-
永远不要只用拉模式。
-
如果是一个初创企业,先用推模式,快速把系统设计出来,然后让产品去验证、迭代,等客户数大幅上涨到1000万后,再考虑升级为推拉集合模式。
-
如果是按推荐排序,那么是另外的考虑了,架构会完全不一样,这个后面专门文章介绍。
如果选择了Tablestore,那么同步库表设计结构如下:
确定了同步库的架构如下:
4. 元数据
前面介绍了同步和存储后,整个Feed流系统的基础功能完成了,但是对于一个完整Feed流产品而言,还缺元数据部分,接下来,我们看元数据如何处理:
Feed流系统中的元数据主要包括:
-
用户详情和列表。
-
关注或好友关系。
-
推送session池。
我们接下来逐一来看。
4.1 用户详情和列表
主要是用户的详情,包括用户的各种自定义属性和系统附加的属性,这部分的要求只需要根据用户ID查询到就可以了。
可以采用的分布式NoSQL系统或者关系型数据库都可以。
如果使用NoSQL数据库Tablestore,那么用户详情表设计结构如下:
4.2 关注或好友关系
这部分是存储关系,查询的时候需要支持查询关注列表或者粉丝列表,或者直接好友列表,这里就需要根据多个属性列查询需要索引能力,这里,存储系统也可以采用两类,关系型、分布式NoSQL数据库。
-
如果已经有了关系型数据库了,且数据量较少,则选择关系型数据库,比如MySQL等。
-
如果数据量比较大,这个时候就有两种选择:
-
使用具有索引的系统,比如云上的Tablestore,更简单,吞吐更高,扩容能力也一并解决了。
-
需要分布式事务,可以采用支持分布式事务的系统,比如分布式关系型数据库。
如果使用Tablestore,那么关注关系表设计结构如下:
Table:user_relation_table
多元索引的索引结构:
查询的时候:
-
如果需要查询某个人的粉丝列表:使用TermQuery查询固定user_id,且按照timestamp排序。
-
如果需要查询某个人的关注列表:使用TermQuery查询固定follow_user_id,且按照timestamp排序。
-
当前数据写入Table后,需要5~10秒钟延迟后会在多元索引中查询到,未来会优化到2秒以内。
除了使用多元索引外,还可以使用GlobalIndex。
4.3 推送session池
思考一个问题,发送者将消息发送后,接收者如何知道自己有新消息来了?客户端周期性去刷新?如果是这样子,那么系统的读请求压力会随着客户端增长而增长,这时候就会有一个风险,比如平时的设备在线率是20%~30%,突然某天平台爆发了一个热点消息,大量休眠设备登陆,这个时候就会出现“查询风暴”,一下子就把系统打垮了,所有的用户都不能用了。
解决这个问题的一个思路是,在服务端维护一个推送session池,这个里面记录哪些用户在线,然后当用户A发送了一条消息给用户B后,服务端在写入存储库和同步库后,再通知一下session池中的用户B的session,告诉他:你有新消息了。然后session-B再去读消息,然后有消息后将消息推送给客户端。或者有消息后给客户端推送一下有消息了,客户端再去拉。
这个session池使用在同步中,但是本质还是一个元数据,一般只需要存在于内存中即可,但是考虑到failover情况,那就需要持久化,这部分数据由于只需要指定单Key查询,用分布式NoSQL或关系型数据库都可以,一般复用当前的系统即可。
如果使用Tablestore,那么session表设计结构如下:
5. 评论
除了私信类型外,其他的feed流类型中,都有评论功能,评论的属性和存储库差不多,但是多了一层关系:被评论的消息,所以只要将评论按照被被评论消息分组组织即可,然后查询时也是一个范围查询就行。这种查询方式很简单,用不到关系型数据库中复杂的事务、join等功能,很适合用分布式NoSQL数据库来存储。
所以,一般的选择方式就是:
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
如果你觉得这些内容对你有帮助,可以扫码获取!!(备注Java获取)

总结
面试难免让人焦虑不安。经历过的人都懂的。但是如果你提前预测面试官要问你的问题并想出得体的回答方式,就会容易很多。
此外,都说“面试造火箭,工作拧螺丝”,那对于准备面试的朋友,你只需懂一个字:刷!
给我刷刷刷刷,使劲儿刷刷刷刷刷!今天既是来谈面试的,那就必须得来整点面试真题,这不花了我整28天,做了份“Java一线大厂高岗面试题解析合集:JAVA基础-中级-高级面试+SSM框架+分布式+性能调优+微服务+并发编程+网络+设计模式+数据结构与算法等”
且除了单纯的刷题,也得需准备一本【JAVA进阶核心知识手册】:JVM、JAVA集合、JAVA多线程并发、JAVA基础、Spring 原理、微服务、Netty与RPC、网络、日志、Zookeeper、Kafka、RabbitMQ、Hbase、MongoDB、Cassandra、设计模式、负载均衡、数据库、一致性算法、JAVA算法、数据结构、加密算法、分布式缓存、Hadoop、Spark、Storm、YARN、机器学习、云计算,用来查漏补缺最好不过。
《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!
题,这不花了我整28天,做了份“Java一线大厂高岗面试题解析合集:JAVA基础-中级-高级面试+SSM框架+分布式+性能调优+微服务+并发编程+网络+设计模式+数据结构与算法等”
[外链图片转存中…(img-fNJF68yX-1712855515730)]
且除了单纯的刷题,也得需准备一本【JAVA进阶核心知识手册】:JVM、JAVA集合、JAVA多线程并发、JAVA基础、Spring 原理、微服务、Netty与RPC、网络、日志、Zookeeper、Kafka、RabbitMQ、Hbase、MongoDB、Cassandra、设计模式、负载均衡、数据库、一致性算法、JAVA算法、数据结构、加密算法、分布式缓存、Hadoop、Spark、Storm、YARN、机器学习、云计算,用来查漏补缺最好不过。
[外链图片转存中…(img-5ScrmLCa-1712855515730)]
《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!