redis(六)---- 简单延迟队列
延迟队列的应用场景也很常见,例如:session的超时过期、自动取消未付款订单等等。redis中有一种数据结构叫做zset,即有序集合。元素类型为String类型,且元素具有唯一性不能重复,每个元素可附带float类型的score即分值。从zset中获取元素的时候可以通过分值进行排序后获取某个分值范围内的元素或所有元素。
public class DelayQueue {
private String redisHost = "10.5.31.155";
private int redisPort = 6379;
private Jedis redis;
private String queueMapKey = "DelayQueueMap";
private String queueSetKey = "DelayQueueSet";
private int delaySecond = 3;
@Before
public void before() {
redis = new Jedis(redisHost, redisPort);
}
@Test
public void pub() throws InterruptedException {
for (int i = 1; i <= 100000; i++) {
String messageId = UUID.randomUUID().toString().replace("-", "");
String messageBody = "第" + i + "条消息:" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(new Date());
redis.hset(queueMapKey, messageId, messageBody);
redis.zadd(queueSetKey, System.currentTimeMillis() + (delaySecond * 1000), messageId);
Thread.sleep(Math.round(Math.floor(Math.random() * 2000)));
}
}
@Test
public void sub() throws InterruptedException {
while (true) {
Set<Tuple> messages = redis.zrangeByScoreWithScores(queueSetKey, System.currentTimeMillis() - (delaySecond * 1000), System.currentTimeMillis());
for (Tuple message : messages) {
Long zrem = redis.zrem(queueSetKey, message.getElement());
if (zrem > 0) {
String messageBody = redis.hget(queueMapKey, message.getElement());
redis.hdel(queueMapKey, message.getElement());
System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(new Date()) + ":" + messageBody);
}
}
Thread.sleep(1000);
}
}
@After
public void after() {
redis.close();
}
}
输出结果:可以看到pub的消息都是延迟3秒被消费的。
2018-09-28 15:02:58.863:第1条消息:2018-09-28 15:02:52.891
2018-09-28 15:02:58.866:第2条消息:2018-09-28 15:02:54.240
2018-09-28 15:02:59.870:第3条消息:2018-09-28 15:02:56.011
2018-09-28 15:02:59.872:第4条消息:2018-09-28 15:02:56.373
2018-09-28 15:02:59.874:第5条消息:2018-09-28 15:02:56.587
上面的代码模拟了一个简单的延迟队列,思路如下:
- 在redis中建立一个hash类型数据,用来存储消息id及消息内容
- 在redis中建立一个zset类型数据,用来存储消息id及对应的分数(该消息的过期时间)
- pub端推送消息时候,先写hash数据,再写zset数据。
- sub端定时按照分数从zset中获取消息id,获取到消息id后逐个删除,删除成功后再处理消息。
缺点:
- sub端需要定时轮训,所以会出现不及时消费的情况
- 如果pub端的生产能力大于sub端的消费能力,则会导致redis内数据越来越多
需要注意的是:
- sub端获取消息、删除消息、处理消息不是一个原子操作,在高并发的情况下,获取到的消息可能被其他服务删除。所以在删除、处理消息的时候,不能一次性删除所有获取到的消息,而是要逐条删除后判断是否删除成功再处理消息。以免消息被重复消费。
- 为什么要用消息id呢,不能直接把消息内容放在zset里吗?答案是不可以。消息内容是可能重复的,而zset中的String是不能重复的。
- 存在消息id及消息内容的数据不能直接使用redis的String数据结构吗?答案是不建议。因为这样会导致redis的key急剧曾多。
redis(六)---- 简单延迟队列的更多相关文章
- 灵感来袭,基于Redis的分布式延迟队列(续)
背景 上一篇(灵感来袭,基于Redis的分布式延迟队列)讲述了基于Java DelayQueue和Redis实现了分布式延迟队列,这种方案实现比较简单,应用于延迟小,消息量不大的场景是没问题的,毕竟J ...
- PHP基于Redis实现轻量级延迟队列
延迟队列,顾名思义它是一种带有延迟功能的消息队列. 那么,是在什么场景下我才需要这样的队列呢? 一.背景 先看看一下业务场景: 1.会员过期前3天发送召回通知 2.订单支付成功后,5分钟后检测下游环节 ...
- 灵感来袭,基于Redis的分布式延迟队列
延迟队列 延迟队列,也就是一定时间之后将消息体放入队列,然后消费者才能正常消费.比如1分钟之后发送短信,发送邮件,检测数据状态等. Redisson Delayed Queue 如果你项目中使用了re ...
- 你知道Redis可以实现延迟队列吗?
最近,又重新学习了下Redis,深深被Redis的魅力所折服,我才知道Redis不仅能快还能慢(我想也这么优秀o(╥﹏╥)o),简直是个利器呀. 咳咳咳,大家不要误会,本文很正经的啦! 好了,接下来回 ...
- 使用netty HashedWheelTimer构建简单延迟队列
背景 最近项目中有个业务,需要对用户新增任务到期后进行业务处理.使用定时任务定时扫描过期时间,浪费资源,且不实时.只能使用延时队列处理. DelayQueue 第一想到的是java自带的延时队列del ...
- Redis实现简单消息队列
http://www.jianshu.com/p/9c04890615ba 任务异步化 打开浏览器,输入地址,按下回车,打开了页面.于是一个HTTP请求(request)就由客户端发送到服务器,服务器 ...
- redis实现简单延时队列(转)
继之前用rabbitMQ实现延时队列,Redis由于其自身的Zset数据结构,也同样可以实现延时的操作 Zset本质就是Set结构上加了个排序的功能,除了添加数据value之外,还提供另一属性scor ...
- 用redis实现简单的队列
在工作中,时常会有用到队列的场景,比较常见的用rabbitMQ这些专业的组件,官网地址是:http://www.rabbitmq.com,重要的是官方有.net的客户端,但是如果对rabbitMQ不熟 ...
- Redis简单延时队列
Redis实现简单延队列, 利用zset有序的数据结构, score设置为延时的时间戳. 实现思路: 1.使用命令 [zrangebyscore keyName socreMin socreMax] ...
随机推荐
- vue - 子组件向父组件 传递方法和参数
1,子组件 TodoItem.vue : <template> <div class="todo-item" :class="{'is-compl ...
- python多进程编程中常常能用到的几种方法
python中的多线程其实并不是真正的多线程,如果想要充分地使用多核CPU资源,在python中大部分情况需要使用多进程.python提供了非常好用的多进程包Multiprocessing,只需要定义 ...
- ACM-生化武器
Description在一个封闭的房间里,gogo给大家表演了他的屁遁术,人果然一下没影了,但是他留下的“生化武器”,却以每秒1米的速度向上下左右扩散出去.为了知道自己会不会被“毒”到,你果断写了个算 ...
- TBLASTN
TBLASTN search translated nucleotide databases using a protein query
- python --- 日志模块 logging
1.日志的使用 import logging class CommonLog(object): def _common_log(self,level,message): # 设定收集器,再设定收集的级 ...
- 中兴将用“加减乘除”建立理想 5G 网络
6 月 28 日,MWC 2019 上海展期间,中兴通讯执行董事.总裁徐子阳发表演讲表示,面对 5G 建网大势,要看破大势,不破不立.为此中兴将用“加减乘除”建立理想 5G 网络. 何为“加减乘除 ...
- HihoCoder第十周:后序遍历
也就在大二学数据结构的时候知道了树的前序遍历.后序遍历.中序遍历.之后就忘了,在之后就是大四研究生老师考我,我当时还不知道,真够丢人的.自此之后,知道了如何通过其中两个得到第三个,但是也没有编程实现过 ...
- 041-PHP把闭包函数当做参数传递
<?php //把闭包函数当做参数传递 function demo($obj){ $obj('我爱PHP'); } # 传一个闭包过去 demo( function($txt){ echo $t ...
- [题解] LuoguP6071 [MdOI2020] Treequery
传送门 感觉这是一个写的很舒服的题? 树上路径的交什么的就很想树上差分?发现根本没法做...它还要求在线.... 好先来看\(Subtask\)吧\(qwq\)... Subtask 1 \(l=r\ ...
- 一、VIP课程:互联网工程专题 05-快速掌握Jenkins原理与核心功能
第五课:快速掌握jenkins核心功能.docx 2.164 (2019-02) and newer: Java 8 or Java 11 一.jenkins 概述与环境配置 知识点: 关于可持续化集 ...