Redis 之 ZSET 实战应用场景,持续更新!

前言

大白话介绍 Redis 五大基本数据类型之一的 ZSET 开发中常见的应用场景

在这里插入图片描述

微信公众号同步不定期同步更新,点击即可访问:同文链接

ZSET 介绍

  • ZSET 与 SET 相同点:都是是 String类型元素的集合,且不允许重复的成员
  • ZSET 与 SET 不同点:ZSET 每个元素都会关联一个 Double 类型的分数,Redis
    通过分数来为集合中的成员进行从小到大的排序。ZSET 的成员是唯一的,但分数 score 却可以重复

ZSET 应用场景

  1. 基于 ZSET 实现的滑动窗口限流
  2. 直播间送礼物排名榜、抖音Feed 流推荐、小红书用户关注列表
  3. 网易新闻、百度热搜,实时新闻、文章类的需求

应用场景非常很广

ZSET 常用 Redis 指令介绍

直接对着控制台简单实操一下,方便大家理解。熟悉指令的读者可自行跳过本章节
在这里插入图片描述

zremrangeByScore

移除 key 为 ranking 且 source 值在 (0,1) 区间的所有数据,返回结果是 3,代表成功移除 3 条数据

zremrangeByScore ranking 0 1

zremrangeByScore ranking 0 1

zcard

统计 key 为 ranking 中剩余元素的个数,移除 3 条数据还剩一条,因此返回结果是 1

zcard ranking

在这里插入图片描述

zrevrangeByScore

ZSET 分页查询,LIMIT 对满足条件的成员列表进行分页。一般会配合 “+inf” 或者 “-inf” 来表示最大值和最小值。这个最大最小值针对于 score 而言。

zrevrangeByScore ranking +inf -inf LIMIT 0 2

在这里插入图片描述

zincrby

没有当前成员则新增、有则修改分数

zincrby ranking 666 "无名黑马"

在这里插入图片描述

zadd

往 ZSET 中添加元素

zadd ranking 5 "王老五"

在这里插入图片描述

基于 ZSET 实现的滑动窗口 Lua 脚本

实现步骤:

  1. 删除固定时间窗口之前的所有的数据
  2. 统计剩余元素数量
  3. 剩余元素数量超过设定阈值,返回 0,没超过返回 1
-- 1. 依赖 redis 中的 zset 类型,zremrangeByScore命令含义:移除0ARGV[1]的所有数据
redis.call('zremrangeByScore', KEYS[1], 0, ARGV[1])
-- 2. 统计剩余元素数量
local res = redis.call('zcard', KEYS[1])
-- 3. 剩余元素是否超过阈值
if (res == nil) or (res < tonumber(ARGV[3])) then
    -- 4.没超过阈值 zadd
    redis.call('zadd', KEYS[1], ARGV[2], ARGV[4])
    return 1
else
    return 0
end

redis.call()表示执行当前的 redis 指令,比方说 redis.call(‘zremrangeByScore’, ‘ranking’, 0, 1) 等价于执行 zremrangeByScore ranking 0 1 这么一条命令。 Java 代码调用代码如下。

 /**
     * unit秒内只能通过qps个请求
     */
    public Object acquire(String key, Integer unit, String qps) {
        long now = System.currentTimeMillis();
        Assert.notNull(unit, "unit不能为 null");
        /**
         * --KEYS[1]: 限流 key
         * --ARGV[1]: 限流窗口(String.valueOf(now - 1000 * unit))
         * --ARGV[2]: 当前时间戳(String.valueOf(now))
         * --ARGV[3]: 阈值 qps
         * --ARGV[4]: score 对应的唯一value(String.valueOf(now))
         */
        return redisTemplate.execute(redisScript,
                Arrays.asList(defaultKeyPrefix + key),
                String.valueOf(now - 1000 * unit),
                String.valueOf(now),
                qps == null ? defaultQps : qps,
                String.valueOf(now));
    }

基于 ZSET实现的热搜文章

也是利用ZSET范围有序查询的特性实现,现在初始化一波数据如下图,先用 Redis 命令演示一波。后续用 Java 代码实现。

在这里插入图片描述
现在需要查最新的 2 条热点数据,执行如下指令。由于 ZSET是有序集合且查询的结果默认是倒序输出,因此最新的俩条数据就被查到了。结果如下

zrevrangeByScore article +inf -inf LIMIT 0 2

在这里插入图片描述
查第二页的数据怎么查?记录每一次查询的最大值,当做下一次查询的游标即可查到第二页数据。

zrevrangeByScore article 20231207 -inf LIMIT 0 2

在这里插入图片描述

对应配套 java 代码

因为 Jedis 的 Api,和原生 Redis 命令命名上很接近,为了方便理解这里用 Jedis 实现。

   @Autowired
    private Jedis jedis;
    private String RANKING_NAME = "ranking";
    private String LIVE_ROME = "liveRoom";
    private String ROOM_NAME = "李佳琦的直播间";

    @ApiOperation("热搜文章分页查询:zrevrangeWithScores 分页查询 0,-1 查全部")
    @PostMapping("rankingList")
    public Result rankingList() {
        return Result.success(jedis.zrevrangeWithScores(RANKING_NAME, 0, -1));
    }

    @ApiOperation("成员当前排名")
    @PostMapping("pos/{member}")
    public Result pos(@PathVariable("member") String member) {
        return Result.success((jedis.zrevrank(RANKING_NAME, member) + 1));
    }

    @ApiOperation("刷礼物(没有当前成员则新增、有则修改分数)")
    @PostMapping("weighting/{member}/{source}")
    public Result pos(@PathVariable("member") String member,
                      @PathVariable("source") String source) {
        jedis.zincrby(RANKING_NAME, Double.parseDouble(source), member);
        return Result.success("ok");
    }

小结 ZSET

由于大家做的业务都不一样,本文只提供实现热点文章排行榜的基本思路。 举2个常见的排行榜开发业务如下

一种是纯 Redis 实现的在线排行榜: 同学 A 做的是直播聊天室业务,里面需要彰显榜一大哥实力,因此需要搞个在线的排行榜,并且还要实现刷礼物、在线人数新增记录、在线人数统计、排名这些需求,为了提升性能,完全就可以用Redis 做数据库。所有操作基于 Redis 完成,至于结果数据的持久化的话,只需在直播间关闭的时候,将数据落库到 Mysql 或者 Oracle 即可。之前写过一个聊天系统,在线人数统计就是每新开一个 Scoket 的时候,人数加 1,我就是这么干的。具体业务不多 bb。

还有一种是通过定时刷新实现的非实时排行榜 同学 b 的公司,不是查实时排行榜,而是通过定时刷数据库同步数据到 redis 中实现的。

另外还有就是Feed 流的应用,采用写扩散的方式实现,例如微信朋友圈的实现、抖音关注推荐模块都是Feed 流系统,这块也可以用Redis 中的Zset 实现需求,后续更新

小咸鱼的技术窝

关注不迷路,分享更多技术干货B站、CSDN、微信公众号同名(小咸鱼的技术窝),更多详情在主页
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小咸鱼的技术窝

你的鼓励将是我最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值