delayqueue

基于redis的延迟消息队列设计

怎甘沉沦 提交于 2020-03-28 02:55:12
介绍 延迟队列,顾名思义它是一种带有延迟功能的消息队列。 那么,是在什么场景下我才需要这样的队列呢? 很多时候我们会有延时处理一个任务的需求,比如说: 2个小时后给用户发送短信。 15分钟后关闭网络连接。 2分钟后再次尝试回调。 下面我们来分别探讨一下几种实现方案: 1、Java中的DelayQueue Java中的DelayQueue位于java.util.concurrent包下,本质是由PriorityQueue和BlockingQueue实现的阻塞优先级队列。 见《 延时队列:Java中的DelayQueue 》 2、使用Redis实现 前文我们看到,可以通过优先级队列来实现延迟队列的功能。Redis提供了很多数据结构,其中的zset是一种有序的数据结构;我们可以通过Redis中的zset来实现一个延迟队列。 基本的方法就是使用时间戳作为元素的score存入zset。 redis> ZADD delayqueue <future_timestamp> "messsage" 获取所有已经“就绪”的message,并且删除message。 redis> MULTI redis> ZRANGEBYSCORE delayqueue 0 <current_timestamp> redis> ZREMRANGEBYSCORE delayqueue 0 <current

延迟任务的实现总结

早过忘川 提交于 2020-03-23 08:48:25
上一篇 写了使用RabbitMQ来实现延迟任务的实现,其实实现延迟任务的方式有很多,各有利弊,有单机和分布式的。在这里做一个总结,在遇到这类问题的时候希望给大家一个参考和思路。 延迟任务有别于定式任务,定式任务往往是固定周期的,有明确的触发时间。而延迟任务一般没有固定的开始时间,它常常是由一个事件触发的,而在这个事件触发之后的一段时间内触发另一个事件。延迟任务相关的业务场景如下: 场景一:物联网系统经常会遇到向终端下发命令,如果命令一段时间没有应答,就需要设置成超时。 场景二:订单下单之后30分钟后,如果用户没有付钱,则系统自动取消订单。 下面我们来探讨一些方案,其实这些方案没有好坏之分,和系统架构一样,只有最适合。对于数据量较小的情况下,任意一种方案都可行,考虑的是简单明了和开发速度,尽量避免把系统搞复杂了。而对于数据量较大的情况下,就需要有一些选择,并不是所有的方案都适合了。 1. 数据库轮询 这是比较常见的一种方式,所有的订单或者所有的命令一般都会存储在数据库中。我们会起一个线程去扫数据库或者一个数据库定时Job,找到那些超时的数据,直接更新状态,或者拿出来执行一些操作。这种方式很简单,不会引入其他的技术,开发周期短。 如果数据量比较大,千万级甚至更多,插入频率很高的话,上面的方式在性能上会出现一些问题,查找和更新对会占用很多时间,轮询频率高的话甚至会影响数据入库

几种实现延时任务的方式

不羁的心 提交于 2020-03-23 08:43:33
大家肯定都有过在饿了么,或者在美团外卖下单的经历,下完单后,超过一定的时间,订单就被自动取消了。这就是延时任务。延时任务的应用场景相当广泛,不仅仅上面所说的饿了吗,美团外卖,还有12306,或者是淘宝,携程等等 都有这样的场景。这延时任务是怎么实现的呢?跟着我,继续看下去吧。 1.在SQL查询,Serive层组装的时候做手脚 在拼接SQL或者Serive层做一些判断,比如 订单状态为 “已下单,但未支付”,同时 当前时间超过了 下单时间 15分钟,显示在用户端或者后台的订单状态就改为 “已取消”。 这种方式比较方便,也没有任何延迟,但是数据库里面的状态不是真实状态了。如果需要提供接口给其他部门调用的话,别忘了对这个订单状态做一些特殊处理。 2.Job 这是最普通的方式之一了。就是开一个Job,每隔一段时间去循环订单,当满足条件后,修改订单状态。 这种方式也比较方便,但是会有一定的延迟,如果订单数据比较少的话,每分钟扫描一次,还是可以接受的,延迟也就在一分钟左右。但是订单数据一旦大了起来,可能一小时也扫描不完,那么延迟就相当恐怖了。而且不停的扫描数据库,对于数据库也是一种压力。 当然还可以做一些改进,比如扫描的时候加上时间范围,在一定时间以前的订单不扫描了,因为这些订单已经被上一次运行的Job给处理了。 第一种方式可以和第二种方式结合起来使用。 前面两个是比较常规的做法

RabbitMq(7)消息延时推送

做~自己de王妃 提交于 2020-03-23 08:41:57
应用场景 目前常见的应用软件都有消息的延迟推送的影子,应用也极为广泛,例如: 淘宝七天自动确认收货。在我们签收商品后,物流系统会在七天后延时发送一个消息给支付系统,通知支付系统将款打给商家,这个过程持续七天,就是使用了消息中间件的延迟推送功能。 12306 购票支付确认页面。我们在选好票点击确定跳转的页面中往往都会有倒计时,代表着 30 分钟内订单不确认的话将会自动取消订单。其实在下订单那一刻开始购票业务系统就会发送一个延时消息给订单系统,延时30分钟,告诉订单系统订单未完成,如果我们在30分钟内完成了订单,则可以通过逻辑代码判断来忽略掉收到的消息。 在上面两种场景中,如果我们使用下面两种传统解决方案无疑大大降低了系统的整体性能和吞吐量: 使用 redis 给订单设置过期时间,最后通过判断 redis 中是否还有该订单来决定订单是否已经完成。这种解决方案相较于消息的延迟推送性能较低,因为我们知道 redis 都是存储于内存中,我们遇到恶意下单或者刷单的将会给内存带来巨大压力。 使用传统的数据库轮询来判断数据库表中订单的状态,这无疑增加了IO次数,性能极低。 使用 jvm 原生的 DelayQueue ,也是大量占用内存,而且没有持久化策略,系统宕机或者重启都会丢失订单信息。 消息延时推送实现 在 RabbitMQ 3.6.x 之前我们一般采用死信队列+TTL过期时间来实现延迟队列。

Java多线程-工具篇-BlockingQueue

China☆狼群 提交于 2020-03-01 01:45:07
前言: 在新增的Concurrent包中,BlockingQueue很好的解决了多线程中,如何高效安全“传输”数据的问题。通过这些高效并且线程安全的队列类,为我们快速搭建高质量的多线程程序带来极大的便利。本文详细介绍了BlockingQueue家庭中的所有成员,包括他们各自的功能以及常见使用场景。 认识BlockingQueue 阻塞队列,顾名思义,首先它是一个队列,而一个队列在数据结构中所起的作用大致如下图所示: 从上图我们可以很清楚看到,通过一个共享的队列,可以使得数据由队列的一端输入,从另外一端输出; 常用的队列主要有以下两种:(当然通过不同的实现方式,还可以延伸出很多不同类型的队列,DelayQueue就是其中的一种)   先进先出(FIFO):先插入的队列的元素也最先出队列,类似于排队的功能。从某种程度上来说这种队列也体现了一种公平性。   后进先出(LIFO):后插入队列的元素最先出队列,这种队列优先处理最近发生的事件。 多线程环境中,通过队列可以很容易实现数据共享,比如经典的“生产者”和“消费者”模型中,通过队列可以很便利地实现两者之间的数据共享。假设我们有若干生产者线程,另外又有若干个消费者线程。如果生产者线程需要把准备好的数据共享给消费者线程,利用队列的方式来传递数据,就可以很方便地解决他们之间的数据共享问题。但如果生产者和消费者在某个时间段内

Java多线程(三)

为君一笑 提交于 2020-02-13 22:35:08
个人博客 http://www.milovetingting.cn Java多线程(三) 前言 本文为学习Java相关知识所作笔记,参考以下资料: https://github.com/Snailclimb/JavaGuide ,感谢原作者的分享! 线程基本方法 线程相关的基本方法有 wait,notify,notifyAll,sleep,join,yield 等。 线程等待(wait) 调用该方法的线程进入 WAITING 状态,只有等待另外线程的通知或被中断才会返回,需要注意的是调用 wait()方法后,会释放对象的锁。因此,wait 方法一般用在同步方法或同步代码块中。 线程睡眠(sleep) sleep 导致当前线程休眠,与 wait 方法不同的是 sleep 不会释放当前占有的锁,sleep(long)会导致线程进入 TIMED-WATING 状态,而 wait()方法会导致当前线程进入 WATING 状态 线程让步(yield) yield 会使当前线程让出 CPU 执行时间片,与其他线程一起重新竞争 CPU 时间片。一般情况下,优先级高的线程有更大的可能性成功竞争得到 CPU 时间片,但这又不是绝对的,有的操作系统对线程优先级并不敏感。 线程中断(interrupt) 中断一个线程,其本意是给这个线程一个通知信号,会影响这个线程内部的一个中断标识位

数据结构之队列的使用 + 面试题

ε祈祈猫儿з 提交于 2020-02-07 14:05:15
数据结构之队列的使用 + 面试题 队列(Queue):与栈相对的一种数据结构, 集合(Collection)的一个子类。队列允许在一端进行插入操作,而在另一端进行删除操作的线性表,栈的特点是后进先出,而队列的特点是先进先出。队列的用处很大,比如实现消息队列。 Queue 类关系图,如下图所示: 注:为了让读者更直观地理解,上图为精简版的 Queue 类关系图。本文如无特殊说明,内容都是基于 Java 1.8 版本。 队列(Queue) 1)Queue 分类 从上图可以看出 Queue 大体可分为以下三类。 双端队列:双端队列(Deque)是 Queue 的子类也是 Queue 的补充类,头部和尾部都支持元素插入和获取。 阻塞队列:阻塞队列指的是在元素操作时(添加或删除),如果没有成功,会阻塞等待执行。例如,当添加元素时,如果队列元素已满,队列会阻塞等待直到有空位时再插入。 非阻塞队列:非阻塞队列和阻塞队列相反,会直接返回操作的结果,而非阻塞等待。双端队列也属于非阻塞队列。 2)Queue 方法说明 Queue 方法如下图所示: 其中比较常用的方法有以下几个: add(E):添加元素到队列尾部,成功返回 true,队列超出时抛出异常; offer(E):添加元素到队列尾部,成功返回 true,队列超出时返回 false; remove(Object):删除元素,成功返回 true

Executor框架

陌路散爱 提交于 2020-01-21 08:17:06
目录 Executor框架简介 Executor框架的结构与成员 Executor框架的结构 Executor框架的成员 ThreadPoolExecutor详解 FixedThreadPool详解 SingleThreadExecutor详解 CachedThreadPool详解 ScheduledThreadPoolExecutor详解 ScheduledThreadPoolExecutor的运行机制 ScheduledThreadPoolExecutor的实现 FutureTask详解 FutureTask简介 FutureTask的使用 FutureTask的实现 在Java中,使用线程来异步执行任务。Java线程的创建与销毁需要一定的开销,如果我们 为每一个任务创建一个新线程来执行,这些线程的创建与销毁将消耗大量的计算资源。同时, 为每一个任务创建一个新线程来执行,这种策略可能会使处于高负荷状态的应用最终崩溃。 Java的线程既是工作单元,也是执行机制。从JDK5开始,把工作单元与执行机制分离开 来。工作单元包括Runable和Callable, 而执行机制由Executor框架提供。 Executor框架简介 Executor框架的两级调度模型 在HotSpotVM的线程模型中, Java线程(java.lang. Thread)被一对一映射为本地操作系统线 程。

JUC之阻塞队列介绍

两盒软妹~` 提交于 2020-01-07 19:02:02
简介   在并发编程中,有时候需要使用线程安全的队列。   要实现一个线程安全的队列有两种方式: 1. 阻塞算法 ;    阻塞算法的队列可以用一个锁(入队和出队用同一把锁)或两个锁(入队和出队用不同的锁)等方式来实现。 2. 非阻塞算法 。    非阻塞的实现方式则可以使用循环CAS的方式来实现。   JUC中非阻塞队列有 ConcurrentLinked Queue 和 ConcurrentLinked Deque 。 本文主要介绍阻塞队列相关类和接口 阻塞队列   阻塞队列在实际应用中非常广泛,许多消息中间件中定义的队列,通常就是一种“阻塞队列”。    ConcurrentLinked Queue 和 ConcurrentLinked Deque 是以非阻塞算法实现的高性能队列,其使用场景一般在高并发环境下,需要“队列/栈”这类数据结构时才使用;   而 “阻塞队列” 通常利用了“锁”来实现,也就是会阻塞调用线程,其使用场景一般是在 “ 生产者-消费者 ” 模式中,用于线程之间的数据交换或系统解耦。   “生产者-消费者”这种模式中,“生产者” 和 “消费者” 是相互独立的,两者之间的通信需要依靠一个队列。这个队列就是要说的 阻塞队列。   引入“阻塞队列”的最大好处就是解耦,在软件工程中,“高内聚,低耦合”是进行模块设计的准则之一,这样“生产者”和“消费者

延迟队列DelayQueue简单入门

早过忘川 提交于 2020-01-07 16:51:37
【推荐】2019 Java 开发者跳槽指南.pdf(吐血整理) >>> 一、DelayQueue是什么 DelayQueue是一个无界的BlockingQueue,用于放置实现了Delayed接口的对象,其中的对象只能在其到期时才能从队列中取走。这种队列是有序的,即队头对象的延迟到期时间最长。注意:不能将null元素放置到这种队列中。 二、DelayQueue能做什么 1. 淘宝订单业务:下单之后如果三十分钟之内没有付款就自动取消订单。 2. 饿了吗订餐通知:下单成功后60s之后给用户发送短信通知。 三、实际开发中的应用 简单的延时队列要有三部分:第一实现了Delayed接口的消息体、第二消费消息的消费者、第三存放消息的延时队列 1.消息体。实现接口 Delayed ,重写方法 compareTo 和 getDelay public class Message implements Delayed{ private Map<String,String> body=new HashMap<>(); //消息内容 private long excuteTime;//执行时间 private String type; public Map<String, String> getBody() { return body; } public void setBody(Map<String,