浅谈传统定时任务和分布式定时任务

article/2025/10/10 2:19:47

为什么用定时任务?

定时任务平台可以在后台自动检测数据并进行操作。主要应用在订单状态改变、后台统计、定时发送邮件或短信等。

定时任务怎么部署实现?

传统的定时任务可以通过可定时线程池、timertask、quartz、spring-schedule方式来进行处理。他们的依赖和代码如下面所示。

maven依赖

<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.4.4</version><relativePath/><!-- lookup parent from repository -->
</parent>
<dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!-- quartz --><dependency><groupId>org.quartz-scheduler</groupId><artifactId>quartz</artifactId><version>2.2.1</version></dependency><dependency><groupId>org.quartz-scheduler</groupId><artifactId>quartz-jobs</artifactId><version>2.2.1</version></dependency>
</dependencies>

代码实现

timetask法

public class TimerTaskDemo {public static void main(String[] args) {TimerTask timerTask = new TimerTask() {@Overridepublic void run() {System.out.println(Thread.currentThread().getName() + "定时任务触发");}};Timer timer = new Timer();// 天数long delay = 0;// 耗秒数long period = 1000;timer.scheduleAtFixedRate(timerTask, delay, period);}
}

可定时线程池法

public class ScheduledExecutorServiceDemo {public static void main(String[] args) {Runnable runnable = new Runnable() {public void run() {System.out.println("定时任务触发..");}};ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(10);scheduledExecutorService.scheduleAtFixedRate(runnable, 1, 1, TimeUnit.SECONDS);}
}

quartz法

public class QuartzTest {public static void main(String[] args) throws SchedulerException {//1.创建Scheduler的工厂SchedulerFactory sf = new StdSchedulerFactory();//2.从工厂中获取调度器实例Scheduler scheduler = sf.getScheduler();//3.创建JobDetailJobDetail jb = JobBuilder.newJob(MyJob.class).withDescription("this is a ram job") //job的描述.withIdentity("ramJob", "ramGroup") //job 的name和group.build();//任务运行的时间,SimpleSchedle类型触发器有效long time = System.currentTimeMillis() + 3 * 1000L; //3秒后启动任务Date statTime = new Date(time);//4.创建Trigger//使用SimpleScheduleBuilder或者CronScheduleBuilderTrigger t = TriggerBuilder.newTrigger().withDescription("").withIdentity("ramTrigger", "ramTriggerGroup")//.withSchedule(SimpleScheduleBuilder.simpleSchedule()).startAt(statTime)  //默认当前时间启动.withSchedule(CronScheduleBuilder.cronSchedule("0/2 * * * * ?")) //两秒执行一次.build();//5.注册任务和定时器scheduler.scheduleJob(jb, t);//6.启动 调度器scheduler.start();}
}
public class MyJob implements Job {public void execute(JobExecutionContext context) throws JobExecutionException {System.out.println("quartz MyJob date:" + new Date().getTime());}
}

spring-schedule法

@Component
public class UserScheduled {@Scheduled(cron = "0/1 * * * * *")public void taskUserScheduled() {System.out.println("定时任务触发...");}}

从以上的代码可以看出,使用spring-schedule法可以减少代码量,只不过依赖于spring相关的注解。可定时任务线程池可以完全脱离spring注解来执行定时任务。quartz的代码相对繁琐些。同时他们底层的原理都是死循环来进行实现的。

传统定时任务的局限性

问题来了,随着数据量和用户数量的增加,传统定时任务的局限性日渐凸显。比如说,笔者在最早的公司深绘工作时,遇上如下两个问题:第一个问题是定时任务与普通业务逻辑代码耦合在一个项目里面发布,一旦定时任务过多,就会引起CPU飚高问题,造成整个系统的崩溃,代表的失误是用户运维统计数目过多导致系统的崩溃;第二个问题是,在集群的情况之下,多台服务器执行同一个定时任务,造成统计数据重复的问题,专业的角度来讲是幂等性问题,典型的代表是ai复核统计数据重复的问题。
从上面提到的问题中,可以概况出传统定时任务的局限性如下。
1.业务逻辑与定时任务逻辑放入在同一个Jar包中,如果定时任务逻辑挂了也会影响到业务逻辑;—没有实现解耦
2.如果服务器集群的情况下,可能存在定时任务逻辑会重复触发执行;
3.定时任务执行非常消耗cpu的资源,可能会影响到业务线程的执行

如何解决以上三点问题呢?

针对重复执行问题,笔者采用的第一个方法是加入联合唯一键来限制,从而保证唯一数据。第二个方法是使用分布式锁来进行处理,只要jar能够拿到分布式锁就能够执行定时任务,否则情况下不执行。第三个方法是对Jar包加上一个开关,项目启动的时候读取该开关 如果为true的情况下则加载定时任务类,否则情况下就不加载该定时任务类。以上三个方法都没有发挥集群优势,效率偏低。
针对定时任务挂了影响正常逻辑,笔者所在的深绘后来采用用户运维统计业务放到另外一个项目来进行处理,把定时任务和业务逻辑分开实现解耦、只对业务逻辑实现集群,不对我们的定时任务逻辑集群,这个方法不能够发挥集群的优势处理。
针对cpu飚高问题,笔者采用分片进行统计,每统计一次对线程休眠,防止CPU飚高和内存溢出的问题。
总而言之,针对传统定时任务框架的局限性,这里需要防止cpu飚高和发挥集群的优势,需要一个可控制的任务调度平台来处理。常见的定时任务调度平台有xxl-job和elastic-job。前者是利用自定义的admin调度平台来进行调度执行任务的,任务数据是放入数据库里面的;后者是用zookeeper来进行调度执行的。

分布式定时任务原理

1.执行器启动的时候会将他的IP和端口号信息注册到执行器注册中上。
2.当我们现在定时任务模块中启动定时任务的时候,定时任务会再admin
项目先触发,会根据执行器的名称查询多个不同的执行的ip信息,在采用
负载均衡算法选择一个地址,发送rest请求通知给执行器执行到定时任务。
在这里插入图片描述

项目如何整合xxl-job

maven依赖

<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.4.4</version><relativePath/> <!-- lookup parent from repository -->
</parent>
<dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>com.xuxueli</groupId><artifactId>xxl-job-core</artifactId><version>2.3.0</version></dependency></dependencies>

java代码

@Configuration
public class XxlJobConfig {private Logger logger = LoggerFactory.getLogger(XxlJobConfig.class);@Value("${xxl.job.admin.addresses}")private String adminAddresses;@Value("${xxl.job.executor.appname}")private String appName;@Value("${xxl.job.executor.ip}")private String ip;@Value("${xxl.job.executor.port}")private int port;@Value("${xxl.job.accessToken}")private String accessToken;@Value("${xxl.job.executor.logpath}")private String logPath;@Value("${xxl.job.executor.logretentiondays}")private int logRetentionDays;@Beanpublic XxlJobSpringExecutor xxlJobExecutor() {logger.info(">>>>>>>>>>> xxl-job config init.");XxlJobSpringExecutor xxlJobSpringExecutor = new XxlJobSpringExecutor();xxlJobSpringExecutor.setAdminAddresses(adminAddresses);xxlJobSpringExecutor.setAppName(appName);xxlJobSpringExecutor.setIp(ip);xxlJobSpringExecutor.setPort(port);xxlJobSpringExecutor.setAccessToken(accessToken);xxlJobSpringExecutor.setLogPath(logPath);xxlJobSpringExecutor.setLogRetentionDays(logRetentionDays);return xxlJobSpringExecutor;}}
@Component
public class SampleXxlJob {private static Logger logger = LoggerFactory.getLogger(SampleXxlJob.class);/*** 1、简单任务示例(Bean模式)*/@XxlJob("demoJobHandler")public void demoJobHandler() throws Exception {XxlJobHelper.log("XXL-JOB, Hello World.");for (int i = 0; i < 5; i++) {XxlJobHelper.log("beat at:" + i);TimeUnit.SECONDS.sleep(2);}// default success}
}

http://chatgpt.dhexx.cn/article/wQZ8NSXj.shtml

相关文章

分布式定时任务技术选型

1、目前的定时任务方案 Java中开发大多数使用Spring-Scheduler&#xff0c;只需要在Spring中的bean的对应方法加上sheduler注解即可完成我们的定时任务&#xff0c;但是光是用这个注解还远远不能保证定时任务执行多次&#xff0c;我们需要一些其他手段的保证&#xff0c;一般来…

java 分布式 定时任务_Java中实现分布式定时任务的方法

定时器Scheduler在平时使用比较频繁&#xff0c;在springboot中&#xff0c;配置好Scheduled和EnableScheduling之后&#xff0c;定时器就能正常执行&#xff0c;实现定时任务的功能。 但是在这样的情况下&#xff1a;如果开发的服务需要水平部署实现负载均衡&#xff0c;那么定…

【手把手】分布式定时任务调度解析之Quartz

1、任务调度背景 在业务系统中有很多这样的场景&#xff1a; 1、账单日或者还款日上午 10 点&#xff0c;给每个信用卡客户发送账单通知&#xff0c;还款通知。如何判断客户的账单日、还款日&#xff0c;完成通知的发送&#xff1f; 2、银行业务系统&#xff0c;夜间要完成跑批…

轻量级分布式定时任务框架XXL-Job

轻量级分布式定时任务框架XXL-Job: XXL-JOB是一款轻量级的分布式定时任务框架&#xff0c;上手简单&#xff0c;操作容易&#xff0c;XXL-Job可以到官网下载也可以去gitee上拉取源码&#xff0c;其中核心模块分页两个&#xff1a;1&#xff1a;是分布式调度服务&#xff0c; 2&…

Springboot结合Redis实现分布式定时任务

一、背景 之前分享过分布式定时任务的技术选型方案&#xff1a;分布式定时任务技术选型方案&#xff0c;个人青睐xxl_job&#xff0c;分享了搭建接入流程&#xff1a;xxl_job搭建方案&#xff0c;本次项目需求较为简单&#xff0c;同时时间紧张。下面介绍利用Redis锁实现分布式…

分布式定时任务框架说明

分布式定时任务框架说明 分布式定时任务框架说明Quartz概念架构组件springboot集成方式使用内存使用数据库 TBSchedule&#xff1a;elastic-job概念架构组件执行流程特性 satumxxl-job概念特性架构组件使用 分布式定时任务框架说明 Quartz 概念 Quartz&#xff1a;Java事实上…

分布式定时任务对比

1. 什么是分布式定时任务 把分散的&#xff0c;可靠性差的计划任务纳入统一的平台&#xff0c;并实现集群管理调度和分布式部署的一种定时任务的管理方式。叫做分布式定时任务。 2. 常见开源方案 elastic-job , xxl-job &#xff0c;quartz , saturn, opencron , antares el…

简单粗暴的分布式定时任务解决方案

分布式定时任务 1.为什么需要定时任务&#xff1f;2.数据库实现分布式定时任务3.基于redis实现 1.为什么需要定时任务&#xff1f; 因为有时候我们需要定时的执行一些操作&#xff0c;比如业务中产生的一些临时文件&#xff0c;临时文件不能立即删除&#xff0c;因为不清楚用户…

Java 实现分布式定时任务

文章目录 前言一、技术点二、代码实践1、引入库2、创建启动线程入口3、表结构4、任务解析5、任务拉取 三、结果展示四、总结 前言 最近有一个需求&#xff1a;需要实现分布式定时任务。而市面上的定时任务大多数都是基于Scheduled注解进行实现。不符合需求。所以根据需求整体思…

分布式定时任务调度

前言 什么是分布式定时任务? 把分散的&#xff0c;可靠性差的计划任务纳入统一的平台&#xff0c;并实现集群管理调度和分布式部署的一种定时任务的管理方式。叫做分布式定时任务。 为什么要采用分布式定时任务&#xff1f; 单点定时任务的缺点: 功能相对简单&#xff0c…

分布式定时任务-XXL-JOB-教程+实战

一.定时任务概述 1.定时任务认识 1.1.什么是定时任务 定时任务是按照指定时间周期运行任务。使用场景为在某个固定时间点执行&#xff0c;或者周期性的去执行某个任务&#xff0c;比如&#xff1a;每天晚上24点做数据汇总&#xff0c;定时发送短信等。 1.2.常见定时任务方案…

几种常用的分布式定时任务

1. 什么是分布式定时任务 把分散的&#xff0c;可靠性差的计划任务纳入统一的平台&#xff0c;并实现集群管理调度和分布式部署的一种定时任务的管理方式。叫做分布式定时任务。 2. 常见开源方案 elastic-job xxl-job quartz saturn opencron antares elastic-job el…

分布式定时任务

分布式定时任务 1&#xff0c;什么是分布式定时任务&#xff1b;2&#xff0c;为什么要采用分布式定时任务&#xff1b;3&#xff0c;怎么样设计实现一个分布式定时任务&#xff1b;4&#xff0c;当前比较流行的分布式定时任务框架&#xff1b; 1&#xff0c;什么是分布式定时…

python类型转换函数str

str函数&#xff0c;将数字转为字符串&#xff1a;

Python 类型转换(数据类型转换函数大全)

文章目录 虽然 Python 是弱类型编程语言&#xff0c;不需要像 Java 或 C 语言那样还要在使用变量前声明变量的类型&#xff0c;但在一些特定场景中&#xff0c;仍然需要用到类型转换。 比如说&#xff0c;我们想通过使用 print() 函数输出信息“您的身高&#xff1a;”以及浮点…

python怎么转换文件格式_python怎么转换数据类型

在处理数据的时候&#xff0c;经常需要转换数据的格式&#xff0c;来方便数据遍历等操作。下面我们来看一下Python中的几种数据类型转换。 1、字符串转字典&#xff1a;dict_string "{name:linux,age:18}" to_dict eval(dict_string) print(type(to_dict)) 也可以用…

python强制类型转换

1.强转为int string->int a string print(int(a))a 1.2 print(int(a))a 12 print(int(a))string仅在无特殊字符&#xff08;包括小数点&#xff09;且全为数字的情况下可强转为float boolen->int a True b False print(int(a)) print(int(b))float->int a …

python批量转换数据类型_python中数据类型转换

1、list转str 假设有一个名为test_list的list,转换后的str名为test_str 则转换方法: test_str = "".join(test_list) 例子: 需要注意的是该方法需要list中的元素为字符型,若是整型,则需要先转换为字符型后再转为str类型。 2、str转list 假设有一个名为test_str的…

python类型转换

一、int——支持转换为 int 类型的&#xff0c;仅有 float、str、bytes&#xff0c;其他类型均不支持。 1、str与bytes类型是什么&#xff0c;有什么区别 文本总是Unicode&#xff0c;由str类型表示&#xff0c;二进制数据则由bytes类型表示。 字符串是 以字符为单位进行处理…

浅谈Python中的类型转换

目录 &#xff08;一&#xff09;前言 &#xff08;二&#xff09;四种常见转换类型 1. int()函数 &#xff08;1&#xff09;int()函数的格式 &#xff08;2&#xff09;示例 2. float()函数 &#xff08;1&#xff09;float()函数格式&#xff1a; &#xff08;2&…