Redis ZSet 的几种使用场景
1. 延时队列
zset 会按 score 进行排序,如果 score 代表想要执行时间的时间戳。在某个时间将它插入 zset 集合中,它变会按照时间戳大小进行排序,也就是对执行时间前后进行排序。
起一个死循环线程不断地进行取第一个 key 值,如果当前时间戳大于等于该 key 值的 score 就将它取出来进行消费删除,可以达到延时执行的目的。
发送消息
代码如下:
public void sendMessage(long messageId, String message) {System.out.println("发送消息");Jedis client = jedisPool.getResource();Pipeline pipeline = client.pipelined();// score 设置成当前时间戳 + 延迟时间pipeline.zadd(DELAY_QUEUE, System.currentTimeMillis() + DELAY_TIME * 1000,String.format(MEMBER_PREFIX, messageId));Map<String, String> map = new HashMap<>();map.put(String.format(MEMBER_PREFIX, messageId), message);pipeline.hset(DELAY_MESSAGE, map);pipeline.syncAndReturnAll();pipeline.close();client.close();System.out.println("发送消息 over");}
采用 pipeline 的方式,同时写入 zset 和 hash 中
消费消息
代码如下:
public void consumer() {System.out.println("消费消息开始");Jedis client = jedisPool.getResource();Set<Tuple> tupleSet = client.zrangeByScoreWithScores(DELAY_QUEUE, 0, System.currentTimeMillis());for (Tuple t : tupleSet) {long messageId = Long.valueOf(t.getElement().replaceAll("[^0-9]", ""));messageHandler(messageId);}client.close();System.out.println("消费消息 over");
}public void messageHandler(long messageId) {System.out.println("===");pool.execute(() -> { // 放到线程池处理Jedis client = jedisPool.getResource();String message = client.hget(DELAY_MESSAGE, String.format(MEMBER_PREFIX, messageId));System.out.println("处理消息体" + message);System.out.println("处理消息体成功");Pipeline pipeline = client.pipelined();pipeline.multi();pipeline.hdel(DELAY_MESSAGE, String.format(MEMBER_PREFIX, messageId));pipeline.zrank(DELAY_QUEUE, String.format(MEMBER_PREFIX, messageId));pipeline.exec();pipeline.close();client.close();});
}
问题
没有 ack 机制,当消费失败的情况下队列如何处理?
这是 topic 模式,广播模式如何搞
示例代码是 demo,简单应用,投入生产中还需要考虑各种细节问题
2. 排行榜
经常浏览技术社区的话,应该对 “1小时最热门” 这类榜单不陌生。如何实现呢?如果记录在数据库中,不太容易对实时统计数据做区分。我们以当前小时的时间戳作为 zset 的 key,把贴子ID 作为 member ,点击数评论数等作为 score,当 score 发生变化时更新 score。利用 ZREVRANGE
或者 ZRANGE
查到对应数量的记录。
记录回复数
代码如下:
/*** 模拟每次针对贴子的回复数加 1** @param id
*/
public void post(long id) {Jedis client = jedisPool.getResource();client.zincrby(POSTLIST, 1, String.format(MEMBER_PREFIX, id));client.close();
}
获取列表
代码如下:
/*** 获取 Top 的贴子列表 ID** @param size* @return
*/
public List<Integer> getTopList(int size) {List<Integer> result = new ArrayList<>();if (size <= 0 || size > 100) {return result;}Jedis client = jedisPool.getResource();Set<Tuple> tupleSet = client.zrevrangeWithScores(POSTLIST, 0, size - 1);client.close();for (Tuple tuple : tupleSet) {String t = tuple.getElement().replaceAll("[^0-9]", "");result.add(Integer.valueOf(t));}return result;
}
模拟用户发帖的行为
代码如下:
public void test() throws InterruptedException {int threadSize = 200;long[] ids = {100, 102, 103, 104, 105, 106, 101, 108, 107, 200, 109, 201, 202};CountDownLatch countDownLatch = new CountDownLatch(threadSize);for (int i = 0; i < threadSize; i++) {pool.execute(() -> {for (int j = 0; j < 3; j++) {Random r = new Random();int index = (int) (r.nextDouble() * ids.length);post(ids[index]);}countDownLatch.countDown();});}countDownLatch.await();
}
问题
数量过大时会占用大量内存,需要清理很多冷数据
适合处理点击数、访问量之类,处理发帖回复这种还需要考虑,帖子审核不通过的情况
3. 限流
滑动窗口是限流常见的一种策略。如果我们把一个用户的 ID 作为 key 来定义一个 zset ,member 或者 score 可以都为访问时的时间戳。我们只需统计某个 key 下在指定时间戳区间内的个数,就能得到这个用户滑动窗口内访问频次,与最大通过次数比较,来决定是否允许通过。
滑动窗口
代码如下:
/**** @param userId* @param period 窗口大小* @param maxCount 最大频次限制* @return
*/
public boolean isActionAllowed(String userId, int period, int maxCount) {String key = String.format(KEY, userId);long nowTs = System.currentTimeMillis();Jedis client = jedisPool.getResource();Pipeline pipe = client.pipelined();pipe.multi();pipe.zadd(key, nowTs, String.format(MEMBER, userId, nowTs));pipe.zremrangeByScore(key, 0, nowTs - period * 1000);Response<Long> count = pipe.zcard(key);pipe.expire(key, period + 1);pipe.exec();pipe.close();client.close();return count.get() <= maxCount;
}
思路是每一个请求到来时,将时间窗口外的记录全部清理掉,只保留窗口内的记录。zset 中只有 score 值非常重要,value 值没有特别的意义,只需要保证它是唯一的就可以了
问题
需要清理额外的数据
限制的请求量过大时,会占用大量内存
Redis ZSet 的几种使用场景相关推荐
- Redis源码-ZSet:Redis ZSet存储原理、Redis ZSet命令、 Redis ZSet两种存储底层编码ziplist/dict+skiplist、Redis ZSet应用场景
Redis源码-ZSet:Redis ZSet存储原理.Redis ZSet命令. Redis ZSet两种存储底层编码ziplist/dict+skiplist.Redis ZSet应用场景 Red ...
- redis zset怎么排序_redis(set、zset)类型使用和使用场景
Redis的数据类型 Redis的数据类型共有五种:string,list,hash,set,zset: String 字符串相对来说做平常,key-value,类似是hashmap的用法: List ...
- Redis的20种使用场景
本文介绍Redis除了缓存以外的使用场景. 测试源码:https://github.com/vehang/ehang-spring-boot/tree/main/spring-boot-011-red ...
- Redis 几种应用场景
Redis 几种应用场景 字符串缓存 <?php$redis = new Redis();$redis->connect('127.0.0.1',6379);$strKey = 'test ...
- 数据类型_分享redis中除5种基础数据类型以外的高级数据类型
众所周知,在redis中的数据类型有String(字符串).hash(哈希).list(列表).set(集合).zset(有序集合)五种.但在这5种之外还有高级数据类型. 今天和大家介绍下常用的高级数 ...
- Redis专题-底层数据结构与使用场景
Redis介绍 Redis是一种基于键值对的NoSQL数据库,是一个基于内存中的数据结构存储系统,可以用作数据库.缓存和消息中间件.它支持以string(字符串),hash(哈希),list(列表), ...
- Redis支持的数据类型以及使用场景,持久化,哨兵机制,缓存击穿,缓存穿透
Redis支持的数据类型以及使用场景,持久化,哨兵机制,缓存击穿,缓存穿透 简单介绍一个redis? redis是内存中的数据结构存储系统,一个key-value类型的非关系型数据库,可持久化的数据库 ...
- php redis新增数据类型,Redis有哪几种数据类型
Redis支持五种数据类型:string(字符串),hash(哈希),list(列表),set(集合)及zset(sorted set:有序集合).(推荐学习:Redis视频教程) String(字符 ...
- 深入理解 Redis Template及4种序列化方式__spring boot整合redis实现RedisTemplate三分钟快速入门
概述 使用Spring 提供的 Spring Data Redis 操作redis 必然要使用Spring提供的模板类 RedisTemplate, 今天我们好好的看看这个模板类 . RedisTem ...
最新文章
- 计算机与控制学院优秀学生,三好学生主要事迹:计算机与控制工程学院王天琪事迹.doc...
- worker进程和task进程区别_celery 每个 worker 在执行任务时,如何配置一定数量的 task?...
- c语言程序设计第四版十二五,C语言程序设计/普通高等教育十二五规划教材
- busybox arm-linux-gcc 4.4.4库的路径,BUSYBOX编译错误及解决方法总结
- Spring5参考指南:组件扫描
- MybatisPlus学习(四)条件构造器Wrapper方法详解
- 使用Vysper,TomEE和PrimeFaces将XMPP服务器嵌入JSF Web应用程序内部
- MapReduce:处理数据密集型文本处理–局部聚合第二部分
- vue2 父子组件传参 回调函数使用
- Windows下DNS ID欺骗的原理与实现
- java排序算法 sort_Java排序算法之SleepSort排序示例
- 适合MySQL master/slave模式的JDBC driver: lbpool
- 请求并操作指定url处的xml文件
- iOS平台下闪退原因汇总(一):Ran out of trampolines of type 0/1/2 运行时间错误
- 可观测性平台下的低代码技术实践
- 一款好用的国产软件源代码缺陷分析平台 — CodeSense
- 直流电机驱动模块介绍
- 镶锆石、侧边指纹、双屏翻盖机,三星的这款2万块手机,只有土豪能懂
- STAR法则修改简历
- 基于matlab山脊线,基于Matlab的标记分水岭分割算法
热门文章
- 去年下半年blog文章导入完毕
- docker安装以及部署springboot项目
- Linux学习笔记(四)账号管理之管理用户账号
- Linux学习笔记(三):系统运行级与运行级的切换
- git常用命令+git规范(附merge合并及冲突解决)
- vue —— UI组件库
- java hung_java – Hung JVM消耗100%的CPU
- js基础--变量、数据类型、循环、判断、函数定义
- BZOJ3238:[AHOI2013]差异——题解
- 《中国人工智能学会通讯》——11.64 基于成对约束的属性特征选择