当前位置:   article > 正文

阿里Java三面:分布式延时任务方案解析,长文一篇点通你_java 延迟支付放调度器弊端

java 延迟支付放调度器弊端

前言

在开发中,往往会遇到一些关于延时任务的需求。例如

  • 生成订单30分钟未支付,则自动取消
  • 生成订单60秒后,给用户发短信

对上述的任务,我们给一个专业的名字来形容,那就是延时任务。那么这里就会产生一个问题,这个延时任务定时任务的区别究竟在哪里呢?一共有如下几点区别

  1. 定时任务有明确的触发时间,延时任务没有
  2. 定时任务有执行周期,而延时任务在某事件触发后一段时间内执行,没有执行周期
  3. 定时任务一般执行的是批处理操作是多个任务,而延时任务一般是单个任务

下面,我们以判断订单是否超时为例,进行方案分析

方案分析

(1)数据库轮询

思路

该方案通常是在小型项目中使用,即通过一个线程定时地去扫描数据库,通过订单时间来判断是否有超时的订单,然后进行update或delete等操作

实现

博主当年早期是用quartz来实现的(实习那会的事),简单介绍一下
maven项目引入一个依赖如下所示

  1. <dependency>
  2. <groupId>org.quartz-scheduler</groupId>
  3. <artifactId>quartz</artifactId>
  4. <version>2.2.2</version>
  5. </dependency>

调用Demo类MyJob如下所示

  1. package com.rjzheng.delay1;
  2. import org.quartz.JobBuilder;
  3. import org.quartz.JobDetail;
  4. import org.quartz.Scheduler;
  5. import org.quartz.SchedulerException;
  6. import org.quartz.SchedulerFactory;
  7. import org.quartz.SimpleScheduleBuilder;
  8. import org.quartz.Trigger;
  9. import org.quartz.TriggerBuilder;
  10. import org.quartz.impl.StdSchedulerFactory;
  11. import org.quartz.Job;
  12. import org.quartz.JobExecutionContext;
  13. import org.quartz.JobExecutionException;
  14. public class MyJob implements Job {
  15. public void execute(JobExecutionContext context)
  16. throws JobExecutionException {
  17. System.out.println("要去数据库扫描啦。。。");
  18. }
  19. public static void main(String[] args) throws Exception {
  20. // 创建任务
  21. JobDetail jobDetail = JobBuilder.newJob(MyJob.class)
  22. .withIdentity("job1", "group1").build();
  23. // 创建触发器 每3秒钟执行一次
  24. Trigger trigger = TriggerBuilder
  25. .newTrigger()
  26. .withIdentity("trigger1", "group3")
  27. .withSchedule(
  28. SimpleScheduleBuilder.simpleSchedule()
  29. .withIntervalInSeconds(3).repeatForever())
  30. .build();
  31. Scheduler scheduler = new StdSchedulerFactory().getScheduler();
  32. // 将任务及其触发器放入调度器
  33. scheduler.scheduleJob(jobDetail, trigger);
  34. // 调度器开始调度任务
  35. scheduler.start();
  36. }
  37. }

运行代码,可发现每隔3秒,输出如下

要去数据库扫描啦。。。

优缺点

优点:简单易行,支持集群操作
缺点:(1)对服务器内存消耗大
   (2)存在延迟,比如你每隔3分钟扫描一次,那最坏的延迟时间就是3分钟
   (3)假设你的订单有几千万条,每隔几分钟这样扫描一次,数据库损耗极大

(2)JDK的延迟队列

思路

该方案是利用JDK自带的DelayQueue来实现,这是一个无界阻塞队列,该队列只有在延迟期满的时候才能从中获取元素,放入DelayQueue中的对象,是必须实现Delayed接口的。
DelayedQueue实现工作流程如下图所示

阿里Java三面:分布式延时任务方案解析,万字长文一篇点通你

其中Poll():获取并移除队列的超时元素,没有则返回空;take():获取并移除队列的超时元素,如果没有则wait当前线程,直到有元素满足超时条件,返回结果。

实现

定义一个类OrderDelay实现Delayed,代码如下

  1. package com.rjzheng.delay2;
  2. import java.util.concurrent.Delayed;
  3. import java.util.concurrent.TimeUnit;
  4. public class OrderDelay implements Delayed {
  5. private String orderId;
  6. private long timeout;
  7. OrderDelay(String orderId, long timeout) {
  8. this.orderId = orderId;
  9. this.timeout = timeout + System.nanoTime();
  10. }
  11. public int compareTo(Delayed other) {
  12. if (other == this)
  13. return 0;
  14. OrderDelay t = (OrderDelay) other;
  15. long d = (g
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/blog/article/detail/42742
推荐阅读
相关标签
  

闽ICP备14008679号