Feed 流 —— Timeline
Timeline
本文介绍基于关注关系并按时间排列的 Feed 流
Feed 流有两种工作模式,推模式和拉模式
拉模式
在用户查询时应该首先查询用户关注的所有博主的 uid
查询他们发布的作品,最后按照发布时间降序排列
拉模式用户每打开一次 “关注页” 系统就需要读取 N 个人的文章(N 为用户关注的博主数)所以拉模式又被称为读扩散
拉模式不需要额外存储数据
- 发布文章在
articles
表增加一条数据 - 用户关注在
followings
表中增加一条数据
在粉丝数特别多的博主发布内容时,不需要进行特殊处理,等到用户进入关注页再计算就好
但是每次进入关注页都要进行大量读取和排序操作,如果用户关注的人比较多,一次拉取耗时会很大
推模式
博主在发布文章的时候就要把新文章写入粉丝的 Timeline
中,用户每次只需要到自己关注的 Timeline
中
推模式每次发布文章都要写入 M 条数据(M 是粉丝数)所以推模式也叫写扩散
在粉丝数比较多的博主,每次发布作品都要推送很多,体验不够友好
一般发布文章之后,前端返回成功,用 MQ 异步向粉丝 Timeline
推送
在线推,离线拉
Timeline
实际上就是一个缓存
给 Timeline
的存储设置过期时间,如果用户一段时间没有打开 APP,Timeline
会失效,在他回归之后通过拉模式重建缓存即可
判断用户是否在线,也就可以通过 Timeline
缓存是否存在作为判断依据
并且用户总是关心关注页中最新的内容,所以 Timeline
也没必要存完整的数据,存最近一段时间的即可,旧数据等用户翻阅时重建
存储
用 ZSet 存储,article_id
作为集合的 member,发布时间戳作为 score
推送的时候对目标 Timeline
的 ZSet 进行 ZAdd 操作,若缓存没有某个 Timeline
就用拉模式重建
存在的问题
如果没有某个
Timeline
的缓存时,无法判断缓存是否失效了,还是这个用户的Timeline
本来就是空的,只能通过读取 MySQL 数据才能判断,会造成缓存穿透由于只存储一段时间的
Timeline
所以当读完了 Redis 中的数据之后,无法判断数据库中是否有更久的数据
解决办法:
- 在 ZSet 中放一个
noMore
标志,表示数据库中没有更多的数据了,对于Timeline
本来就为空的用户,他们 ZSet 中只有一个noMor
标志