Java处理延时任务的常用几种解决方案

目录
  • 前言
  • 数据库轮询
    • 原理
    • 优缺点
  • Java延迟队列
  • Reids监听失效key
    • 创建监听类,实现MessageListener接口
  • RocketMq延迟消息
  • 总结

前言

项目中经常会遇到如下的需求:

  • 创建订单30分钟未支付,订单自动取消。
  • 订单支付成功后,1分钟后给用户发送短信,提醒用户评价。

针对延时任务需求,我们可以采用如下的解决方案:

数据库轮询

原理

通过一个线程定时的扫描数据库当天创建的订单,根据订单的创建时间来判断订单是否超时,针对超时订单进行相关的更新操作。
实现技术
采用Spring Boot结合quartz来实现,具体的实现可以参考之前的文章。

优缺点

优点:

此方案比较简单,且quartz也支持集群操作。

缺点:

  • 系统订单数据量比较大,每个几分钟轮询数据库,对服务器和数据库的内存消耗比较大。
  • 存在延迟,即使1分钟扫描一次数据库,也会存在1分钟的延迟。

Java延迟队列

原理

采用JDK自带的DelayQueue来实现,这是一个无界阻塞队列,该队列只有在延迟期满的时候才能从中获取元素,放入DelayQueue中的对象。
实现技术
使用JDK的DelayQueue队列进行相关操作即可。

优缺点

优点:

此方案是基于内存操作所以效率高,任务触发时间延迟低.

缺点:

  • 消息队列的信息都存放在内存中,一旦服务器重启,则数据全部消失
  • 无法进行集群用扩展
  • 由于本机内存有限,一旦订单数据量过大,很容易出现OOM异常。

Reids监听失效key

原理

该方案使用Redis的Keyspace Notifications,利用key失效的提供的回调机制,处理相关的业务实现

实现技术

基于reids的方案,实现MessageListener接口。

实现步骤

修改Redis配置文件
打开redis.conf 文件,搜索 “notify-keyspace-events”找到原本的notify-keyspace-events " ",修改为 “notify-keyspace-events Ex”,至此Redis 就支持Key过期事件的监听。

创建监听类,实现MessageListener接口

@Component
public class RedisKeyExpirationListener implements MessageListener
{
    private static final Logger logger = LoggerFactory.getLogger(RedisKeyExpirationListener.class);

    public static final String KEY_PREX = "test::order:queue";

    @Override
    public void onMessage(Message message, byte[] pattern)
    {
        try
        {
            String expiredKey = message.toString();

            // 通过key来判断
            if(!expiredKey.contains(KEY_PREX))
            {
                return;
            }

            //满足条件处理具体的业务逻辑
        }
        catch (Exception e)
        {
            logger.error("失效事件失败",e);
        }
    }
}

优缺点

优点:

基于Redis实现简单

缺点:

  • 客户端断开后重连会导致所有事件丢失。
  • 高并发场景下,存在大量的失效key场景会导出失效时间存在延迟。
  • 此方案针对业务量较少且可靠性要求不高的场景使用。

RocketMq延迟消息

实现原理

基于RocketMQ设置消息的等级,发送延迟消息,RocketMQ延时消息会暂存在名为SCHEDULE_TOPIC_XXXX的Topic中,并根据delayTimeLevel存入特定的queue,queueId = delayTimeLevel – 1,即一个queue只存相同延迟的消息,保证具有相同发送延迟的消息能够顺序消费。broker会调度地消费SCHEDULE_TOPIC_XXXX,将消息写入真实的topic。
其具体步骤如下:

  • 修改消息Topic名称和队列信息
  • 转发消息到延迟主题SCHEDULE_TOPIC_XXXX的CosumeQueue中
  • 延迟服务消费SCHEDULE_TOPIC_XXXX消息
  • 将信息重新存储到CommitLog中
  • 将消息投递到目标Topic中
  • 消费者消费目标topic中的数据。
/**
    * 发送延迟消息
    * @param topic
    * @param msg
    */
   public void sendDelayMessage(String topic,Object msg)
   {
      Message msgMessage =new Message();
      //设置消息等级
      msgMessage.setDelayTimeLevel(2);
     rocketMQTemplate.convertAndSend(topic, msg);
   }

注意:RocketMQ延时消息的延迟时长不支持随意时长的延迟,是通过特定的延迟等级来指定的。默认支持18个等级的延迟消息,延时等级定义在RocketMQ服务端的MessageStoreConfig类中的如下变量中:

例如指定的延时等级为2,则表示延迟时长为5s,即延迟等级是从1开始计数的。

优缺点

优点:

支持高并发场景消息处理.

缺点:

  • 引入额外的消息队列,增加项目的维护和复杂度。
  • 支持固定时长的消息延迟,针对任意时长的消息延迟需要进行扩展。

总结

本文讲解了针对延时任务的处理的几种方案和相关的优缺点,针对不同的业务场景,选择合适的解决方案。更多相关Java 延时任务内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Java自带定时任务ScheduledThreadPoolExecutor实现定时器和延时加载功能

    java.util.concurrent.ScheduledThreadPoolExecutor 是JDK1 .6之后自带的包,功能强大,能实现定时器和延时加载的功能 各类功能和处理方面优于Timer 1.定时器: ScheduledThreadPoolExecutor  有个scheduleAtFixedRate(command, initialDelay, period, unit) ;方法 command: 执行的线程(可自己New一个) initialDelay:初始化执行的延时时间 p

  • Java处理延时任务的常用几种解决方案

    目录 前言 数据库轮询 原理 优缺点 Java延迟队列 Reids监听失效key 创建监听类,实现MessageListener接口 RocketMq延迟消息 总结 前言 项目中经常会遇到如下的需求: 创建订单30分钟未支付,订单自动取消. 订单支付成功后,1分钟后给用户发送短信,提醒用户评价. … 针对延时任务需求,我们可以采用如下的解决方案: 数据库轮询 原理 通过一个线程定时的扫描数据库当天创建的订单,根据订单的创建时间来判断订单是否超时,针对超时订单进行相关的更新操作.实现技术采用Spr

  • 分享Java常用几种加密算法(四种)

    对称加密算法是应用较早的加密算法,技术成熟.在对称加密算法中,数据发信方将明文(原始数据)和加密密钥(mi yue)一起经过特殊加密算法处理后,使其变成复杂的加密密文发送出去.收信方收到密文后,若想解读原文,则需要使用加密用过的密钥及相同算法的逆算法对密文进行解密,才能使其恢复成可读明文.在对称加密算法中,使用的密钥只有一个,发收信双方都使用这个密钥对数据进行加密和解密,这就要求解密方事先必须知道加密密钥. 简单的java加密算法有: BASE 严格地说,属于编码格式,而非加密算法 MD(Mes

  • Java详解Swing中的几种常用按钮的使用

    目录 Swing中的常用按钮 AbstractButton的常用方法 JRadionButton(单选按钮) 单选按钮的构造方法 复选框(JCheckBox) 复选框的构造方法 组合框(JComboBox) 组合框的构造方法 下拉列表框的常用方法 小结 Swing中的常用按钮 在Swing中,常见的按钮组件有JButton,JCheckBox,JRadioButton等,它们都是抽象类AbstractButton类的直接或间接子类.在AbstractButton类中提供了按钮组件通用的一些方法.

  • 一文带你深入了解Java中延时任务的实现

    目录 概述 JAVA DelayQueue DelayQueue的实现原理 DelayQueue实现延时队列的优缺点 时间轮算法 时间轮的具体实现 进阶优化版时间轮算法 时间轮算法的应用 小结 redis延时队列 mq延时队列 rocketmq延时消息 rocketmq的精准延时消息 总结 概述 延时任务相信大家都不陌生,在现实的业务中应用场景可以说是比比皆是.例如订单下单15分钟未支付直接取消,外卖超时自动赔付等等.这些情况下,我们该怎么设计我们的服务的实现呢? 笨一点的方法自然是定时任务去数

  • Java程序员新手老手常用的八大开发工具

    现在有很多库.实用工具和程序任Java开发人员选择.每个工具都有其优点,但其中有一些因它的知名度.多功能性和有效性从众多选项中脱颖而出. 以下这8个工具,从代码构建到错误挤压,覆盖Java开发的全域.学习这些工具可以帮助你改善代码质量,成为一个更高效的Java开发人员. 1.Eclipse 尽管IntelliJ IDEA.NetBeans和一些其他的IDE正在日益普及,但是有调查表明,Eclipse仍然是几乎半数Java开发人员首选的开发环境. Eclipse是IDE领域的瑞士军刀,有着大量定制

  • Java语言Lang包下常用的工具类介绍

    无论你在开发哪中 Java 应用程序,都免不了要写很多工具类/工具函数.你可知道,有很多现成的工具类可用,并且代码质量都很不错,不用你写,不用你调试,只要你发现. 在 Apache Jakarta Common 中, Lang 这个 Java 工具包是所有 Apache Jakarta Common 项目中被使用最广泛的,几乎你所知道的名气比较大的软件里面都有用到它,包括 Tomcat, Weblogic, Websphere, Eclipse 等等.我们就从这个包开始介绍整个 common 项

  • spring、mybatis 配置方式详解(常用两种方式)

    在之前的文章中总结了三种方式,但是有两种是注解sql的,这种方式比较混乱所以大家不怎么使用,下面总结一下常用的两种总结方式: 一. 动态代理实现 不用写dao的实现类 这种方式比较简单,不用实现dao层,只需要定义接口就可以了,这里只是为了记录配置文件所以程序写的很简单: 1.整体结构图: 2.三个配置文件以及一个映射文件 (1).程序入口以及前端控制器配置 web.xml <?xml version="1.0" encoding="UTF-8"?> &

  • Java实现Map集合遍历的四种常见方式与用法分析

    本文实例讲述了Java实现Map集合遍历的四种常见方式与用法.分享给大家供大家参考,具体如下: ~Map集合是键值对形式存储值的,所以遍历Map集合无非就是获取键和值,根据实际需求,进行获取键和值 1. 无非就是通过map.keySet()获取到值,然后根据键获取到值 for(String s:map.keySet()){ System.out.println("key : "+s+" value : "+map.get(s)); } 2. 通过Map.Entry(

  • java快速生成接口文档的三种解决方案

    目录 前言 方案一,使用japidocs 基本用法 方案2,swagger + knife4j 生成步骤 方案3,开源的接口文档生成工具 总结 前言 常常在项目收尾阶段,客户需要项目的接口文档,或者是一个大的sass平台,各个产品之间互相调用的时候,需要对方提供接口文档 通常来说,接口文档属于产品的技术沉淀,是一个长期积累的过程,然而,很多时候,开发阶段并不会想的那么多,结果到了需要接口文档的时候总是疲于应付,情急之下,往往采用最笨拙的办法,就是对照着项目代码,一个个拷贝吧 下面针对这个情况,小

  • Java中关于线程安全的三种解决方式

    三个窗口卖票的例子解决线程安全问题 问题:买票过程中,出现了重票.错票-->出现了线程的安全问题 问题出现的原因:当某个线程操作车票的过程中,尚未操作完成时,其他线程参与进来,也操作车票 如何解决:当一个线程a在操作ticket的时候,其他线程不能参与进来,知道线程a操作完ticket时,其他线程才可以开始操作ticket,这种情况即使线程a出现了阻塞,也不能被改变 在Java中,我们通过同步机制,来解决线程的安全问题.(线程安全问题的前提:有共享数据) 方式一:同步代码块 synchroniz

随机推荐