微服务Spring Boot 整合 Redis 实现好友关注 – Feed流实现推送到粉丝收件箱
阿里云国内75折 回扣 微信号:monov8 |
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6 |
文章目录
⛄引言
本博文参考 黑马 程序员B站 Redis课程系列
在点评项目中有这样的需求如何 Redis 实现好友关注 – Feed流实现推送到粉丝收件箱 功能
采用 Feed流实现推送到粉丝收件箱
Redis 如此强大
一、Redis 实现好友关注 – Feed流实现推送到粉丝收件箱
⛅Feed 流实现方案
假设我们关注了用户这个用户发布了动态那么就应该把当前用户发布的动态推送给他的粉丝如何实现呢这个我们把它叫做Feed流关注推送也叫做 Feed流 直译为投喂为用户持续的提供 ”沉浸式“ 的体验通过五险下拉刷新获取新的信息。
传统模式是我们需要用户去通过搜索引擎或者是其它的方式去解锁想要看的内容
新型的Feed流 不需要用户再去推送消息而是系统分析用户到底想要什么然后直接把内容推送给用户从而使用户能够更加的节约时间不用主动寻找。
Feed流主要分为两种实现方式
TimeLine 不做内容筛选简单的按照内容发布时间排序常用于好友或关注。例如朋友圈
- 优点信息全面不会有缺失。并且实现也相对简单
- 缺点信息噪音较多用户不一定感兴趣内容获取效率低
智能排序利用智能算法屏蔽掉违规的、用户不感兴趣的内容。推送用户感兴趣信息来吸引用户
- 优点投喂用户感兴趣信息用户粘度很高容易沉迷
- 缺点如果算法不精准可能起到反作用
本次实现的功能中是基于好友 来做Feed流因此采用 TimeLine 模式。 该模式的实现方案分为三种
- 拉模式
- 推模式
- 推拉结合
拉模式也叫做读扩散
该模式的核心含义就是当张三和李四和王五发了消息后都会保存在自己的邮箱中假设赵六要读取信息那么他会从读取他自己的收件箱此时系统会从他关注的人群中把他关注人的信息全部都进行拉取然后在进行排序
优点比较节省空间因为用户在读取信息时并没有重复读取而是读取完后可以把他的收件箱进行清除
缺点比较延迟当用户读取数据时才去关注的用户的人里面读取数据假设用户关注了大量的用户那么此时就会拉取海量的数据内容对服务器压力比较大。
推模式也叫做写扩散
推模式是没有写邮箱的当张三写了一个内容此时会主动的把张三写的内容发送到他的粉丝收件箱中去假设此时李四再来读取就不用再去临时拉取了
优点时效快不用临时拉取
缺点内存压力大假设一个大V写信息很多人关注他就会写很多的数据到粉丝收件箱加大服务器压力。
推拉结合模式也叫做读写混合兼具推和拉两种模式的优点
推拉模式是一个折中的方案站在发件人这一段如果是个普通的人那么我们采用写扩散的方式直接把数据写入到他的粉丝中去因为普通的人他的粉丝关注量比较小所以这样做没有压力如果是大V那么他是直接将数据先写入到一份到发件箱里边去然后再直接写一份到活跃粉丝收件箱里边去现在站在收件人这端来看如果是活跃粉丝那么大V和普通的人发的都会直接写入到自己收件箱里边来而如果是普通的粉丝由于他们上线不是很频繁所以等他们上线时再从发件箱里边去拉信息。
⚡推送到粉丝收件箱
需求
- 修改新增探店笔记的业务在保存blog到数据库的同时推送到粉丝的收件箱
- 收件箱满足可以根据时间戳排序必须用Redis的数据结构实现
核心当我们保存完笔记后获取当前用户的粉丝然后把数据推送到粉丝的Redis中。
@Override
public Result saveBlog(Blog blog) {
// 1.获取登录用户
UserDTO user = UserHolder.getUser();
blog.setUserId(user.getId());
// 2.保存探店笔记
boolean isSuccess = save(blog);
if(!isSuccess){
return Result.fail("新增笔记失败!");
}
// 3.查询笔记作者的所有粉丝 select * from tb_follow where follow_user_id = ?
List<Follow> follows = followService.query().eq("follow_user_id", user.getId()).list();
// 4.推送笔记id给所有粉丝
for (Follow follow : follows) {
// 4.1.获取粉丝id
Long userId = follow.getUserId();
// 4.2.推送
String key = FEED_KEY + userId;
stringRedisTemplate.opsForZSet().add(key, blog.getId().toString(), System.currentTimeMillis());
}
// 5.返回id
return Result.ok(blog.getId());
}
进行测试
发布笔记
查看粉丝收件箱
三、Redis 实现好友关注 – 实现分页滚动查询 实时获取信息
滚动分页查询思路分析
Feed流中的数据会不断更新所以数据的角标也在变化因此不能采用传统的分页模式。
传统了分页在feed流是不适用的因为我们的数据会随时发生变化
假设在t1 时刻我们去读取第一页此时page = 1 size = 5 那么我们拿到的就是10~6 这几条记录假设现在t2时候又发布了一条记录此时t3 时刻我们来读取第二页读取第二页传入的参数是page=2 size=5 那么此时读取到的第二页实际上是从6 开始然后是6~2 那么我们就读取到了重复的数据所以feed流的分页不能采用原始方案来做。
Feed流的滚动分页
我们需要记录每次操作的最后一条然后从这个位置开始去读取数据
举个例子我们从t1时刻开始拿第一页数据拿到了10~6然后记录下当前最后一次拿取的记录就是6t2时刻发布了新的记录此时这个11放到最顶上但是不会影响我们之前记录的6此时t3时刻来拿第二页第二页这个时候拿数据还是从6后一点的5去拿就拿到了5-1的记录。我们这个地方可以采用sortedSet来做可以进行范围查询并且还可以记录当前获取数据时间戳最小值就可以实现滚动分页了
实现滚动分页查询
需求
- 查询收件箱数据时可以实现滚动分页查询
- 在个人主页的 ”关注“ 卡片中查询并展示推送的Blog信息
具体操作
1、每次查询完成后我们要分析出查询数据的最小时间戳这个值会作为下一次的查询条件
2、 我们需要找到与上一次查询相同的查询个数作为偏移量下次查询后跳过这些查询过的数据拿到需要的数据
核心 我们的请求参数中 就需要携带 lastId上一次查询的 最小时间戳 和 偏移量 这两个参数
这两个参数第一次由前端来指定以后的查询就根据后台结果作为条件再次传递给后台。
核心源码
一、定义出 具体的 返回实体类
@Data
public class ScrollResult {
private List<?> list;
private Long minTime;
private Integer offset;
}
BlogController
RequestParam 表示接受url地址栏传参的注解当方法上参数的名称和url地址栏不相同时可以通过RequestParam 来进行指定
@GetMapping("/of/follow")
public Result queryBlogOfFollow(@RequestParam("lastId") Long max, @RequestParam(value = "offset", defaultValue = "0")
Integer offset) {
return blogService.queryBlogOfFollow(max, offset);
}
BlogServiceImpl
@Override
public Result queryBlogOfFollow(Long max, Integer offset) {
// 1.获取当前用户
Long userId = UserHolder.getUser().getId();
// 2.查询收件箱 ZREVRANGEBYSCORE key Max Min LIMIT offset count
String key = RedisConstants.FEED_KEY + userId;
Set<ZSetOperations.TypedTuple<String>> typedTuples = stringRedisTemplate.opsForZSet()
.reverseRangeByScoreWithScores(key, 0, max, offset, 2);
// 3.非空判断
if (typedTuples == null || typedTuples.isEmpty()) {
return Result.ok();
}
// 4.解析数据blogId、minTime时间戳、offset
List<Long> ids = new ArrayList<>(typedTuples.size());
long minTime = 0; // 2
int os = 1; // 2
for (ZSetOperations.TypedTuple<String> tuple : typedTuples) { // 5 4 4 2 2
// 4.1.获取id
ids.add(Long.valueOf(tuple.getValue()));
// 4.2.获取分数(时间戳
long time = tuple.getScore().longValue();
if(time == minTime){
os++;
}else{
minTime = time;
os = 1;
}
}
os = minTime == max ? os : os + offset;
// 5.根据id查询blog
String idStr = StrUtil.join(",", ids);
List<Blog> blogs = query().in("id", ids).last("ORDER BY FIELD(id," + idStr + ")").list();
for (Blog blog : blogs) {
// 5.1.查询blog有关的用户
queryBlogUser(blog);
// 5.2.查询blog是否被点赞
isBlogLiked(blog);
}
// 6.封装并返回
ScrollResult r = new ScrollResult();
r.setList(blogs);
r.setOffset(os);
r.setMinTime(minTime);
return Result.ok(r);
}
结果测试
⛵小结
以上就是【Bug 终结者】对 微服务Spring Boot 整合 Redis 实现好友关注 – Feed流实现推送到粉丝收件箱 的简单介绍微服务Spring Boot 整合 Redis 实现好友关注 – Feed流实现推送到粉丝收件箱功能也是 利用Set集合、ZSet集合实现这样一个需求同时采用Redis来实现更加的快速减少系统的消耗更加快速的实现数据展示
如果这篇【文章】有帮助到你希望可以给【Bug 终结者】点个赞👍创作不易如果有对【后端技术】、【前端领域】感兴趣的小可爱也欢迎关注❤️❤️❤️ 【Bug 终结者】❤️❤️❤️我将会给你带来巨大的【收获与惊喜】💝💝💝