feed流 读扩散和写扩散 2022-06-28
feed流
微信朋友圈、微博、小红书,都是典型的feed流应用
通俗的说就是用户拥有发布者和粉丝两种角色,依据用户的关注关系展示的信息流就是feed流
一条独立的消息就是一个feed基本单元
feed业务特点
用户与用户之间存在明显的好友关系
用户可以看到的信息流依据好友follow关系得到
核心业务动作是什么?
(1)关注,取关;
(2)发布feed;
(3)拉取自己的主页feed流
设计feed流应用的架构
要说在前面的是,任何情况下,要么以时间换空间,要么以空间换时间,一般难以二者兼顾
比如一些常规业务中,数据库冗余一些字段可以方便地提高查询效率,但是额外牺牲了存储空间
最基本框架
显然,对于每一个用户,最起码需要记录【用户-粉丝】和【用户-已关注人】、【用户-本人消息】这3种关联关系
对于好友关系
如果只记录【用户-粉丝】而 不记录【用户-已关注人】,也可以
但是这种情况下,如果需要获取用户U的关注人列表,那就得遍历所有用户,筛选出粉丝中有用户U的若干用户。用户量一大,这个时间成本是不能接受的,因此需要记录【用户-已关注人】关系
实际上,【用户-粉丝】和【用户-已关注人】是互相冗余的,知一推一。但是为了效率,需要冗余一份
读扩散和写扩散
看下不同架构下,完成3个核心动作的具体实现差异
- 只记录【用户-本人消息】
- 关注、取关。update【用户-粉丝】和【用户-已关注人】表
- 发布、删除feed。insert into / delete from【用户-本人消息】
- 拉取自己的主页feed流。当用户U拉取主页feed信息流时,需要从每个已关注人的消息列表中拉取、排序、整合后展示
关注,取关,发布、删除feed的业务流程非常简单,存储消耗小
读取feed流需要实时拉取、排序和整合
用户发布一个Feed单元,后台会扩散为N次读操作(N为粉丝人数)以及一次聚合操作,因此称为读扩散。每次读Feed流相当于去关注者的收件箱主动拉取帖子,因此也得名——拉模式。这就是读扩散模式,也叫拉feed模式
读扩散的优点:
写操作(发消息)很轻量,只需要往相应的消息存储写一次就好了
读扩散的缺点:
唯独读操作(读消息)很重
如果用户关注的人很多,那么一次拉取的时延将很高,用户体验受到影响
那么,为了换取良好的用户体验,一个自然的想法就是当别人发消息的时候,往所有粉丝的“收件箱”都投递一份消息副本,这样每个粉丝可以直接从自己的“收件箱”拉取消息,而无需去每个关注人的发件箱翻查并整合消息。于是:
- 如果在【用户-本人消息】基础上, 额外记录【用户-可见消息】(也是一种冗余)
- 关注、取关。update【用户-粉丝】和【用户-已关注人】表,and insert into 新关注人的【用户-可见消息】 / delete from 被取关人的【用户-可见消息】
- 发布、删除feed。insert into / delete from【用户-本人消息】,and 异步 insert into / delete from 所有粉丝的【用户-可见消息】
- 拉取自己的主页feed流。当用户U拉取主页feed信息流时,直接从【用户-可见消息】拉取
关注,取关,发布、删除feed的业务流程复杂度变高,存储消耗大(一份消息要推送给所有的粉丝,产生大量副本)
但是读取feed流非常简单
但是,如果一个用户上亿粉丝,写扩散模式下异步投递feed消息到【粉丝-可见消息】是非常重且高时延的操作,可能要几分钟后才能给所有的粉丝发完
这就是写扩散模式,也叫推feed模式
写扩散优点:
读操作很轻量
写扩散缺点:
写操作很重,尤其是对于群聊来说
通常写扩散适用于好友量不大的情况,比如微信朋友圈正是写扩散模式。每一名微信用户的好友上限为5000人,也就是说你发一条朋友圈最多也就扩散到5000次写操作
读写扩散的消息通知时机
写扩散模式用户可以自动收到最新消息通知而无需额外操作,类似于回调。像朋友圈点赞、评论的通知,就是写扩散
而读扩散模式则需要用户登录或刷新动作才能知道是否有新内容,类似主动轮询