面对千万级关系链与实时推送挑战,腾讯频道如何构建高性能Feeds流系统?本文深度解析三层架构设计策略,揭秘读写扩散混合方案与扩散量剪枝优化,破解超大社区场景下的空拉难题,为复杂社交产品架构提供实战经验。
关注腾讯云开发者,一手技术干货提前解锁👇
周五晚7:30,还将会有腾讯工程师、资深 AI 专家漫谈 DeepSeek,记得预约直播~👇
腾讯频道是一种基于爱好、话题或者因为现实中的某个组织,比如大学,将一群人聚集在一起,以帖子为内容载体,并辅以实时消息、音视频、直播、开黑、日程、机器人等能力的社区。
既然是以帖子为内容载体,那帖子系统如何实现则是频道的架构设计中重要的一环。
2.1 业界对比
频道作为一个用户社区,同时也是一个 Feeds 流产品,和同为社区或者 Feeds 流的产品相比,复杂度都是非常高的。
QQ 群&朋友圈:和 QQ 群还有朋友圈相比,虽然都是实时的同步模式,和强关系链,但是 QQ 群和朋友圈关系链的规模都是千级别,而频道则是千万级别的超大关系链。
贴吧&微博&小红书:贴吧、微博、小红书相比,虽然都是同为超大规模的关系链,但是这三款产品是关注的弱关系,内容的同步方式更多的还是异步的,小红书核心场景都是基于推荐和搜索,微博和贴吧则是关系和推荐都有,而频道则是基于超大关系链的带有实时推送的内容流。
同时频道相比于其他产品有更加复杂的功能和权限,综上所述频道在所有维度都有更高的复杂度,而这些对于 Feeds 流都有着直接的关联影响。
2.2 整体架构设计
2.2.1 功能介绍
频道的内容功能非常多,常规的所有的能力如帖子、评论、回复等等都有,除此之外,还有非常繁杂的 Feeds 流。
其他我发表的、我点赞的、我浏览的帖子列表则是字面意思,不一一展开介绍。
除此之外还有帖子的评论列表,评论的回复列表,个人的互动消息列表等等也不一一展开。
2.2.2 架构设计
那这么多复杂的功能,我们应该如何设计呢?
我们不要被这么多的功能吓到,所有功能的底层逻辑都是相通的,只要我们遵从后台的设计理念分而治之,再多的功能都能轻松厘清。
以下是一个极简版的频道 Feeds 系统的结构图:
整体遵从3个原则:
大多数的功能只要遵循这3个原则,基本都能比较容易的拆解和实现。
2.2.3 Feeds 流设计
2.2.3.1 方案选型
频道作为一个 Feeds 流社区,Feeds 流必然是其最关键的设计,Feeds 流作为业界相对比较常见的产品,无论是国内还是国外都有比较多的同类产品,方案也都相对比较明确,那么频道和这些产品相比有什么不同吗?
以下业界产品普遍的最简单的映射单元:
这是一种基于关注关系的 Feeds 流,如微博和小红书的关注列表,内容生产者发表内容,一群内容消费者关注内容生产者消费内容,同时每个消费者还会关注若干个生产者。
以下是频道的最简单的映射单元:
从对比中很明显可以看出频道是一种多层级的映射关系,生产者发表内容在各个子频道内,而子频道又归属不同的频道,子频道还有复杂的权限限制,消费者通过加入或者浏览这些频道来消费内容。频道明显更加复杂,业界方案肯定是没有办法直接搬过来用的,那我们应该如何设计呢?
2.2.3.2 方案设计
虽然上面说是最小的映射单元了,但是只是为了和业界其他产品在同一个维度上进行对比,实际上还有进一步简化的空间。
1)子频道帖子列表
先复杂到简单:先把复杂的映射关系进一步简化,我们就能得到如下模型。
这就是频道内某个子频道下帖子列表的模型,和业界其他的模型就基本一致了,我们就可以选择业界比较常见的读扩散或者写扩散简单的实现。实现方式如下:
这里我们选择写扩散(或者也可以不叫扩散),简单的实现了频道下 C1、C2、C3 三个子频道帖子列表,其中 C1 为私密子频道,仅部分用户可见。
2)帖子广场
再简单到复杂:实现了简单的模型后,再在简单模型的基础上慢慢复杂化,实现更加复杂的帖子列表。
我们已经实现了子频道帖子列表了,下一步单个频道下的帖子广场(前文有介绍帖子广场是什么)应该如何设计?依然是先设计模型:
模型进一步复杂后依然还是三层映射,这里我们选择同子频道帖子列表通过读扩散的方式聚合实现:
于是我们就得到了用户 U1 和 U2 在频道 G1 内的帖子广场列表,而由于可见权限不同,U1 和 U2 看到的列表也不同,这也是为什么我们不用写扩散生成一个频道内所有帖子列表的原因。
3)个人动态
我们继续将模型复杂化,于是得到了个人动态(前文有介绍)的模型:
依然得到了一个简单的映射关系,很容易想到利用前面实现的帖子广场就能很容易的实现的个人动态的帖子列表。于是:
这里我们依然选择读扩散,可能又有人会问这里为什么不把我关注的所有的频道的帖子写一份给我,像微信朋友圈一样的设计,这样我就可以简单的查询自己的列表就可以了。那是因为频道是一个超大关系链社区,单频道人数可超千万,这样的超大关系链,写扩散的时效性,一致性,成本都是问题,反而我们更像微博大V的场景,所以我们选择了微博大V一样的读扩散的设计。
上面介绍了频道内最关键的3个帖子列表的设计思路,其他的列表大家可以自行参考上面的思路去设计。
2.2.3.3 方案优化
那么按照上面的设计就可以很好的实现产品的功能了吗?并不能,上面只是一些最基础的设计,这其中还存在一些问题。
1)子频道帖子列表
前面介绍了子频道帖子列表我们是通过写扩散实现的,但是我们的需求中还有个能力,被安全打击的内容需要仅自己可见(干扰黑产),审核中的内容也需要仅自己可见(提升用户体验)。
大家可以想象一个场景,我们先从索引层获取了一页10个帖子的 FeedID,然后去查询 Feed 详情的时候,发现8个甚至10个都处于审核中(由于我们的内容是按发表时间从新到旧排序,这种情况很常见),全被过滤掉了,这个时候你有两种选择,直接返回空给客户端,这样的体验非常糟糕,或者继续拉下一页,这样会增加接口耗时,同时也没有办法保证下一页一定能拉到足够的内容,这就是空拉问题。所以简单的写扩散没有办法满足我们的诉求。
于是我们通过读写结合的方式进行了优化,方案如下:
子频道列表索引只存公开可见的帖子,另外和用户的个人发表帖子列表通过读扩散的方式合并成一个新的 Feeds 列表,就得到了一个安全仅自见的千人千面的子频道帖子列表。
2)帖子广场&个人动态
读扩散相比于写扩散,它的读逻辑会非常复杂,同时也有个非常关键的问题,就是扩散量如何优化。以下是一个比较基础的读扩散方案:
这里的读扩散的扩散量为:单页数量*查询的页数*子频道数*频道数。
假定单页数量为10,平均每个频道子频道数为10,平均每个用户加入5个频道,那么我们需要查询这么多帖子,才能得到我们想要的帖子:
第一页:10*1*10*5=500
第二页:10*2*10*5=1000
.....
第十页:10*10*10*5=5000
...
第N页:10*N*10*5=500*N
我们看到随着页数越多,我们需要查询的帖子越来越多,急需对读扩散进行剪枝:
于是我们得到了如下的读扩散方案:
这个方案的优势在于,无论查第几页,都只需要查单页数量*单页数量的帖子,按照前面的假定,每次都只需要查询100条,在第十页的时候,相比于基础方案可以降低50倍扩散量。
到这我们整体的 Feeds 流的关键的设计理念就讲的差不多了,其他的各种细节大家可以结合自己的业务自行实现。
本篇文章主要分享了频道 Feeds 流的一些设计理念,写得比较简单,旨在抛砖引玉,大家也可以结合自己的业务场景设计自己的方案。
好的架构离不开良好的设计理念,但也是在不断发展的业务中生长而成,希望每位同学都能构建出健壮的 IT 架构!
-End-
原创作者|崔明哲