1. 今天做了什么
- 实现了关注与取消关注功能,逻辑简单,交给 AI 快速完成
- 实现了共同关注功能,使用 Redis Set 集合 + SINTER 命令
- 实现了关注推送(Feed 流)功能,采用推模式 + Redis ZSet + 滚动分页
2. 核心知识点
关注与取消关注
- 关注表存储用户 id 与关注用户 id,建立用户与用户之间多对多的联系
- 关注 / 取消关注接口就是实现关注表的新增与删除
- 获取是否关注就是一次查询操作
共同关注
- 实现方案:用 Redis 的 Set 集合维护每个用户的关注用户
- 共同关注依靠 Redis Set 的 SINTER 命令完成
关注推送 — Feed 流模式
- Feed 流模式分类:时间排序、智能推荐
- 本次关注推送采用时间排序
时间排序的三种实现方案:
- 拉模式:博主发内容存入发件箱,粉丝收件箱默认不存,粉丝查看时,拉取所有关注的发件箱,并按时间排序
- 优点:节省空间,博主发件只写一份
- 缺点:粉丝拉取耗时较久
- 推模式:博主发文,写入所有粉丝收件箱,粉丝查看直接读取收件箱
- 优点:粉丝读取速度快
- 缺点:博主发文写入较多,占用空间
- 推拉结合:
- 根据博主粉丝量、用户活跃度差异性选择
- 小博主推模式
- 大博主:活跃粉丝推,非活跃粉丝拉
- 优点:根据不同情况优化,适应性强
- 缺点:实现复杂
推模式实现细节
- 收件箱使用 Redis 的 Sorted Set
- 每次发文,查询粉丝,向粉丝收件箱添加文章 id
滚动分页
传统角标分页的问题:第一次查询后,有新内容插入到前面,下次分页会查到重复内容。
采用滚动分页方案:
- 前端需要携带
lastTime,首次查询是当前时间戳,下一次查询时是上次的最早消息的时间戳,以时间戳为依据确保不会查到之前查过的元素 - 前端还需要传一个
offset(上次查询与最小时间相同的博文数),因为查询时最大值是包含的,该最大值是上次查询的最小值,已经查询过了,确保查询时能跳过上次查过的几条内容,该值由上次查询时后端返回 - 使用
stringRedisTemplate.opsForZSet().reverseRangeByScoreWithScores(key, 0, max, offset, 3);查询,最小值最大值都是包含的 - 处理数据,查询文章
- 封装时要携带
minTime、offset、Bloglist,返回给前端
3. 深度思考
- 共同关注功能实际上就是为了学习 Redis 而使用 Redis 的 SET 集合,该方案并非优选
- 实际上:
- 该功能不是热点功能,不需要依靠 Redis
- 将所有用户关注表用 Redis 缓存也不实际