为什么用定时任务?

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

定时任务怎么部署实现?

传统的定时任务可以通过可定时线程池、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}
}

浅谈传统定时任务和分布式定时任务相关推荐

  1. 得物技术浅谈深入浅出的Redis分布式锁

    一.什么是分布式锁 1.1 分布式锁介绍 分布式锁是控制不同系统之间访问共享资源的一种锁实现,如果不同的系统或同一个系统的不同主机之间共享了某个资源时,往往需要互斥来防止彼此干扰来保证一致性. 1.2 ...

  2. java quartz 动态执行,浅谈SpringBoot集成Quartz动态定时任务

    SpringBoot自带schedule 沿用的springboot少xml配置的优良传统,本身支持表达式等多种定时任务 注意在程序启动的时候加上@EnableScheduling @Schedule ...

  3. 浅谈传统企业网络运营那些事儿

    网络的变革.更新推动的速度很快,小到出门购物全方位在原基础的微信/支付宝等第三方支付等,随着微信公众号/微信小程序等"轻"级传播推广渠道的发展,以及客观的传统企业在互联网的冲击下, ...

  4. 浅谈传统电力运维与智能电力运维

    1.引言 在社会经济和科学技术的发展过程中,对电力工程的质量要求日趋严格,为了满足这种需求,我国不断地对电力工程进行改造,并不断地提高电力工程技术水平以及电力工程项目的建设,由此也带来了庞大的市场,从 ...

  5. 浅谈传统语音通信和APP语音通信音频软件开发之不同点

    本人在传统的语音通信公司做过手机和IP电话上的语音软件开发,也在移动互联网公司做过APP上的语音软件开发.现在带实时语音通信功能的APP有好多,主流的有微信语音.QQ电话.钉钉等,当然也包括我开发过的 ...

  6. java 项目初始化一个定时任务_elastic-job 分布式定时任务框架 在 SpringBoot 中如何使用(一)初始化任务并定时执行...

    第一篇需要实现一个最简单的需求:某个任务定时执行,多台机子只让其中一台机子执行任务 一.安装 分布式应用程序协调服务 zookeeper,安装步骤在链接里面 二.在springboot项目中引入 el ...

  7. 几种主流的分布式定时任务,你知道哪些?

    欢迎关注方志朋的博客,回复"666"获面试宝典 单点定时任务 JDK原生 自从JDK1.5之后,提供了ScheduledExecutorService代替TimerTask来执行定 ...

  8. mysql事务的四大特性_浅谈数据库事务四大特性

    数据库四大特性分别是:原子性.一致性.分离性.持久性.下面我们看看具体介绍. 原子性 事务的原子性指的是,事务中包含的程序作为数据库的逻辑工作单位,它所做的对数据修改操作要么全部执行,要么完全不执行. ...

  9. 浅谈Spring定时任务

    浅谈Spring定时任务 三种定时任务基于原理 多定时任务并发配置 动态定时任务 定时任务Demo 三种定时任务基于原理 SpringBoot配置定时任务主要有Spring Schedule.JDK自 ...

最新文章

  1. es6在原生代码的用法_关于ES6的模块化
  2. Microsoft Fluent Design System
  3. UIScrollView实现不全屏分页的小技巧
  4. iOS UIButton文字和图片间距随意调整
  5. python列表(list)和元组(tuple)之间的转换
  6. [转载] 消息中间件学习总结(8)——RocketMQ之RocketMQ捐赠给Apache那些鲜为人知的故事
  7. jumpserver开源堡垒机部署安装
  8. ElementUI:项目中引入自己的ICON
  9. pdo怎么建mysql表_PDO操作数据库的基本步骤
  10. OverflowError: Python int too large to convert to C long 在Windows环境下Python报错
  11. 华硕怎么安装linux系统教程,有关华硕电脑无法安装Ubuntu系统的解决方案
  12. 原来小米手机的电源键不止能用来关机,这么多实用功能,别浪费了
  13. 计算机属性没有共享,win10系统本地连接属性里没有共享选项的具体方案
  14. win10自带输入法突然变成了繁体,輸入法怎麼成繁體了?
  15. 同一个网址电脑手机访问显示不同内容思路
  16. 周志华西瓜书课后习题答案总目录
  17. pythonista去掉图片背景色是哪条语句?
  18. java 图形 登录_java登录图形界面 - osc_994n5tsc的个人空间 - OSCHINA - 中文开源技术交流社区...
  19. 如何更快地渲染?深入了解3D渲染性能的指南!(5)
  20. python中正负号怎么表示_[转载]python中整数除法的正负号

热门文章

  1. Mysql环境检测 安装MySQL 数据库 配置MySQL 环境变量
  2. 计算机excel试题各科学员,职称计算机考试excel复习试题「含答案」
  3. heatmap(高德热力图)
  4. Oracle AWR报告生成步骤
  5. MATLAB 色图函数绘制多彩图形
  6. 我的2014-转行转行再转行,坚守互联网
  7. 江西会考计算机考试题目,江西省信息技术会考操作题知识要点汇总
  8. 货币转换 I----Python
  9. 【学习打卡】CAM可解释性分析-算法讲解
  10. PLSQL如何保存用户名和密码