延时任务的解决方案

延时任务的解决方案

  • 1.数据库轮询
  • 2. JDK的延迟队列
  • 3.netty时间轮算法
  • 4.使用消息队列

1.数据库轮询

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

代码示例:

select * from '表名' where '时间字段' < '数据库存储的时间戳' and status = '未执行'
while(true){sql;Thread.sleep(1000);
}

1.优点:简单易行,支持集群操作

2.缺点:

  • 对服务器内存消耗大
  • 存在延迟,比如你每隔3分钟扫描一次,那最坏的延迟时间就是3分钟
  • 假设你的订单有几千万条,每隔几分钟这样扫描一次,数据库损耗极大

2. JDK的延迟队列

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

在这里插入图片描述
代码示例:

public class JdkDelayQueue {public static void main(String[] args) throws Exception{DelayQueue<MyDelayed> delayQueue = new DelayQueue();delayQueue.add(new MyDelayed("Andy",5, TimeUnit.SECONDS));delayQueue.add(new MyDelayed("Andy_1",10, TimeUnit.SECONDS));for (;;){// 没有队列就就会阻塞MyDelayed take = delayQueue.take();take.excutue();}}static class MyDelayed implements Delayed {private String name;private long startTime;public MyDelayed(String name, long delayTime, TimeUnit unit) {this.name = name;// 当前时间毫秒值long currentTime = System.currentTimeMillis();// 时间转换为毫秒值long convert = TimeUnit.MILLISECONDS.convert(delayTime, unit);// 任务真正的执行时间this.startTime = currentTime + convert;}@Overridepublic long getDelay(TimeUnit unit) {long currentTime = System.currentTimeMillis();if(startTime <= currentTime){return 0;}long nextTime = startTime - currentTime;return unit.convert(nextTime, TimeUnit.MICROSECONDS);}@Overridepublic int compareTo(Delayed o) {MyDelayed prx = (MyDelayed) o;MyDelayed next = this;if (prx.startTime < next.startTime) {return 1;} else if (prx.startTime > next.startTime){return -1;}return 0;}public void excutue(){System.out.println(name + "任务执行");}}
}

1.优点:效率高,任务触发时间延迟低

2.缺点:

  • 服务器重启后,数据全部消失,怕宕机
  • 集群扩展相当麻烦
  • 因为内存条件限制的原因,比如下单未付款的订单数太多,那么很容易就出现OOM异常
  • 代码复杂度较高

3.netty时间轮算法

时间轮算法可以类比于时钟,如上图箭头(指针)按某一个方向按固定频率轮动,每一次跳动称为一个 tick

在这里插入图片描述
这样可以看出定时轮由个3个重要的属性参数,ticksPerWheel(一轮的tick数),tickDuration(一个tick的持续时间)以及 timeUnit(时间单位),例如当ticksPerWheel=60,tickDuration=1,timeUnit=秒,这就和现实中的始终的秒针走动完全类似了。

如果当前指针指在1上面,我有一个任务需要4秒以后执行,那么这个执行的线程回调或者消息将会被放在5上。那如果需要在20秒之后执行怎么办,由于这个环形结构槽数只到8,如果要20秒,指针需要多转2圈,位置是在2圈之后的5上面(20 % 8 + 1)

1.优点:效率高,任务触发时间延迟时间比delayQueue低,代码复杂度比delayQueue低

2.确定

  • 服务器重启后,数据全部消失,怕宕机
  • 集群扩展相当麻烦
  • 因为内存条件限制的原因,比如下单未付款的订单数太多,那么很容易就出现OOM异常

4.使用消息队列

在这里插入图片描述

我们可以采用RabbitMQ的延时队列,RabbitMQ具有以下两个特性,可以实现延迟队列

  • RabbitMQ可以针对Queue和Message设置 x-message-ttl,来控制消息的生存时间,如果超时,则消息变为dead letter
  • RabbitMQ的Queue可以配置x-dead-letter-exchange 和x-dead-letter-routing-key(可选)两个参数,用来控制队列内出现了dead letter,则按照这两个参数重新路由

1.优点:高效,可以利用rabbitmq的分布式特性轻易的进行横向扩展,消息支持持久化增加了可靠性。

2.缺点:本身的易用度要依赖于RabbitMq的运维,因为要引用RabbitMq,所以复杂度和成本变高

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/616711.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C++核心编程——类和对象(二)

本专栏记录C学习过程包括C基础以及数据结构和算法&#xff0c;其中第一部分计划时间一个月&#xff0c;主要跟着黑马视频教程&#xff0c;学习路线如下&#xff0c;不定时更新&#xff0c;欢迎关注。 当前章节处于&#xff1a; ---------第1阶段-C基础入门 ---------第2阶段实战…

[ctf.show 元旦水友赛 2024] crypto

感觉半个多月回家没有打开过电脑了。看到ctf.show上元旦的比赛&#xff0c;才想起似乎应该看看。 月月的爱情故事 上来这就是个小脑洞题&#xff0c;给了一大段文字和一个base64的串。并且提示&#xff1a;试试摩斯吧&#xff01; 从文字上看只有三种标点符号&#xff0c;显…

基于汽车胎压检测及温度预警

课题简介 汽车胎压监测系统可分为两种&#xff1a;一种是间接式胎压监测系统&#xff0c;是通过轮胎的转速差来判断轮胎是否异常&#xff1b;另一种是直接式胎压监测系统&#xff0c;通过在轮胎里面加装四个胎压监测传感器&#xff0c;在汽车静止或者行驶过程中对轮胎气压和温…

SwiftUI之深入解析布局协议

一、什么是布局协议&#xff1f; 采用布局协议类型的任务&#xff0c;是告诉 SwiftUI 如何放置一组视图&#xff0c;需要多少空间。这类型常常被作为视图容器&#xff0c;虽然布局协议是 2022 年新推出的&#xff08;至少公开来说&#xff09;&#xff0c;但是我们在第一天使用…

线性代数:由矩阵 AB=A 可以推出 B=E 吗?

其实&#xff0c;类似的问题在十几年前的各种提问中就出现了&#xff0c;而且&#xff0c;根据 A B A A BA ABA 推出 B E BE BE 有时候也相当 "符合直觉”&#xff0c;但如果追根问底&#xff0c;矩阵 B B B 到底应该是什么样子的&#xff0c;却很少有详细的解答。 …

Docker的介绍及安装基本操作命令

前言 Docker 是一个开源的应用容器引擎&#xff0c;基于 Go 语言 并遵从 Apache2.0 协议开源。 Docker 可以让开发者打包他们的应用以及依赖包到一个轻量级、可移植的容器中&#xff0c;然后发布到任何流行的 Linux 机器上&#xff0c;也可以实现虚拟化。 容器是完全使用沙箱…

Hive 数据同步

一、需求 同步集团的数据到断直连环境。 二、思路 三、同步数据&#xff08;方案&#xff09; 1、环境&#xff1a;断直连模拟环境 2、操作机器&#xff1a;ETL 机器 XX.14.36.216 3、工作路径&#xff1a;cd /usr/local/fqlhadoop/hadoop/bin 4、执行命令&#xff1a; 命令…

H264码流进行RTP包封装

一.H264基本概念 H.264从框架结构上分为视频编码层&#xff08;VCL&#xff09;和网络抽象层&#xff08;NAL&#xff09;&#xff0c;VCL功能是进行视频编解码&#xff0c;包括运动补偿预测&#xff0c;变换编码和熵编码等功能&#xff1b;NAL用于采用适当的格式对VCL视频数据…

springboot实现文件上传与下载的通用思路模板流程

文件上传 需要将参数设置成为MultipartFile类型 或者我们可以使用spring提供的一个文件内置工具类 FileCopyUtils.copy(InputStream in…

线性方程组计算

一、题型 1&#xff09;给一个线性方程组&#xff0c;问&#xff1a;唯一解&#xff1f;无解&#xff1f;无穷多解&#xff1f; 2&#xff09;在上面的基础上&#xff0c;给一个未知数λ&#xff0c;问&#xff1a;当λ为几时&#xff0c;方程组唯一解&#xff1f;无解&#…

STM32F103RCT6开发板M3单片机教程07-TIMER1CH1输出 PWM做LED呼吸灯

概述 本教程使用是&#xff08;光明谷SUN_STM32mini开发板&#xff09; 免费开发板 在谷动谷力社区注册用户&#xff0c;打卡&#xff0c;发帖求助都可以获取积分&#xff0c;当然最主要是发原创应用文档奖励更多积分&#xff0e; (可用积分换取&#xff0c;真的不用钱&…

2D绘图--视口窗口setViewport setWindow

目录 1 setViewport setWindow 2 示例 3 实际应用&#xff08;个人理解&#xff09; 4 总结 1 setViewport setWindow 在Qt中&#xff0c;QPainter的setViewport()方法用于定义绘图区域在窗口坐标系中的可视部分。 QPainter::setWindow() 是 Qt 库中 QPainter 类的一个方法…

数据库创建表并插入数据练习题

一、创建表的要求 创建一个英雄表(hero) 主键 name nickname address groups email telphone 二、 操作步骤 1.登录MySQL [rootlocalhost ~]# systemctl start mysqld [rootlocalhost ~]# mysql -uroot -p Enter password: Welcome to the MySQL monitor. Commands end with…

NAND系统性能提升常见方案

随着NAND的发展&#xff0c;针对NAND系统性能提升&#xff0c;业内目前主要的做法有以下几种方案&#xff1a; 1.提升总线频率和优化AC时序&#xff1a; 提高NAND闪存接口的工作频率可以显著加快数据传输速度。通过不断改进工艺和技术&#xff0c;缩短了信号稳定时间、降低了延…

工程师职称申报业绩是如何要求的?

无论是初级职称还是中级职称或是高级职称&#xff0c;评审的重要条件之一就是相关的业绩证明。 一、个人业绩&#xff0c;比如你做过哪些与本专业相关的业绩证明&#xff0c;像工程类的职称&#xff0c;你的业绩证明就包括中标通知书、竣工验收报告&#xff0c;或是你参与工程建…

php 的数学常用函数

目录 1.常用列表 2.代码示例 1.常用列表 函数名描述输入输出abs()求绝对值数字绝对值数字ceil()进一法取整浮点数进一取整floor()舍去法求整浮点数直接舍去小数部分fmod()浮点数取余 两个浮点 数,x>y 浮点余数 pow()返回数的n次方基础数n次方乘方值round()浮点数四舍五入…

区块链是怎么存储数据的?

每个块都是有大小限制的新的数据存储单元&#xff0c;当前数据不到上限&#xff0c;那么都可以添加进块。当前数据达到了上限&#xff0c;那么就得分表/分块&#xff0c;超限的那部分数据就需要等待下个区块存储 存储的数据&#xff1a;和mysql一样&#xff0c;文本数据直接存储…

Python 全栈体系【四阶】(十二)

第四章 机器学习 十五、朴素贝叶斯 朴素贝叶斯是一组功能强大且易于训练的分类器&#xff0c;它使用贝叶斯定理来确定给定一组条件的结果的概率&#xff0c;“朴素”的含义是指所给定的条件都能独立存在和发生。朴素贝叶斯是多用途分类器&#xff0c;能在很多不同的情景下找到…

完整的模型验证套路

读取图片 from PIL import Imageimg_path "../Yennefer_of_Vengerberg.jpg" image Image.open(img_path) print(image)转换成灰度图&#xff08;可选&#xff09; image image.convert(L) image.show()转换成RGB格式 image image.convert(RGB)因为png格式是四…

基础数据结构之堆栈

堆栈的定义、入栈、出栈、查询栈顶 #include <stdio.h> #include <stdlib.h>typedef int DataType;// 定义栈节点结构体 struct StackNode;struct StackNode {DataType data; // 节点数据struct StackNode* next; // 指向下一个节点的指针 };// 定…