spring 定时任务 集群,spring定时任务是多线程吗
Spring计划任务云原生简介
定时任务是业务应用开发中非常常见的场景(比如每分钟扫描一次加班付费订单,每小时清理一次数据库的历史数据,每天统计前一天的数据并生成报表等。),而且有很多解决方法。Spring框架提供了一个通过注释来配置定时任务的解决方案,访问非常简单,只需要以下两个步骤:
1\.在启动类上添加注释@EnableScheduling
@SpringBootApplication
@EnableScheduling //添加开始定时任务的注释
公共类SpringSchedulerApplication {
公共静态void main(String[] args) {
spring application . run(spring scheduler application . class,args);
}
}2\.开发定时任务Bean并配置相应的定时注释@Scheduled
@组件
公共类SpringScheduledProcessor {
/**
*通过Cron表达式指定频率或指定时间。
*/
@Scheduled(cron=0/5 * * * *?)
public void doSomethingByCron() {
System.out.println(做点什么);
}
/**
*固定的执行间隔
*/
@Scheduled(固定延迟=2000)
public void doSomethingByFixedDelay(){
System.out.println(做点什么);
}
/**
*固定的执行触发频率
*/
@Scheduled(固定速率=2000)
public void doSomethingByFixedRate(){
System.out.println(做点什么);
}
}弹簧计时任务原理
云原生
运行原理Spring定时任务的核心逻辑主要在spring-context中的调度包中,其主要结构包括:
调度任务分析:通过ScheduledTaskSbeanDefinition解析器分析XML定义任务的配置;还可以通过scheduledannotationbeanpost处理器对@Scheduled注释执行任务解析(通用模式)。调度任务注册:从上述分析中得到的任务配置将被注册到ScheduledTaskRegistrar中运行。计划任务运行:所有任务注册后,通过TaskScheduler正式定期运行相关任务,通过JDK的ScheduledExecutorService底层运行任务。
业务逻辑将被包装在ScheduledMethodRunnable类中,该类包含目标业务对象Bean和要执行的业务方法。Runnable对象将在运行时提交给ScheduledExecutorService,调度线程池完成任务的预定操作。
从上图可以看出,真正的业务逻辑ScheduledMethodRunnable将被ReschedulingRunnable和delegateingerrorhandlingrunnable扩展。这两层代理扩展具有以下含义:
DelegateErrorHandlingRunnable:对业务方法的异常操作进行封装和处理,提供自定义的异常处理机制,解决JDK原生调度任务异常执行后任务失败的问题。ReschedulingRunnable:提供了扩展的定时模式支持,可用于获取基于触发器接口自定义实现的下一个触发时间的定时日程。默认提供的Cron计时是以这种方式扩展和实现的。模式Spring定时任务任务类的模式可以分为两类:IntervalTask和TriggerTask。前者意味着固定频率的间隔执行,后者使用Trigger触发模式实现定时调度,Cron表达式配置实现这种模式。
FixedDelay:以固定的延迟频率执行,任务的下一次触发时间=上次执行结束时间延迟的延迟时间。
FixedRate:以固定的频率触发执行,任务的下一次触发时间=上一次触发时间延迟延时时间。如果上一个执行方法没有完成,下一个任务执行将被阻塞。
Cron表达式:根据Cron表达式计算下一次触发时间,任务的下一次触发时间=cron(上次执行结束时间)。在高级线程池运行的默认配置下,底层运行的线程池是单线程的。在单线程运行模式下,一旦一个任务被阻塞,后续所有的调度任务都会被阻塞,给业务运行带来严重隐患。常见的方式如下:
为调度执行配置线程池:通常基于Spring Boot (spring)的配置。task.scheduling.pool.size=线程数),线程数取决于任务数和调度频率。配置异步任务:@EnableAsync和@Async在spring context的调度模块下提供,可以用来启动任务的异步执行,从而定时调度线程池的非阻塞操作。这种模式存在一些不足:异常处理需要通过异步调用的AsyncUncaughtExceptionHandler接口实现,同步/异步定时任务的异常处理机制不统一,异步模式增加了业务应用的线程开销。@Scheduled(固定延迟=2000)
@Async
公共无效测试(){
system . out . println(date util . now() test );
}统一异常处理调度任务运行时,可以设置统一异常处理,基于ErrorHandler接口开发相应的异常处理实现类。需要将相应的异常实现处理类注入到核心ThreadPoolTaskScheduler中,用户可以通过自定义TaskSchedulerCustomizer将ErrorHandler自定义异常处理Bean注入到ThreadPoolTaskScheduler中。
@组件
公共类DemoTaskSchedulerCustomizer实现TaskSchedulerCustomizer {
@覆盖
public void customize(ThreadPoolTaskScheduler task scheduler){
task scheduler . set error handler(new demo error handler());
}
私有类DemoErrorHandler实现ErrorHandler {
@覆盖
公共void handle error(Throwable Throwable){
统一异常处理);
}
}
}原生Spring调度任务在企业云原生中遇到的问题
只要有注释,就会重复执行Spring调度任务。在分布式场景中,相同的机器码会导致在多台机器上重复执行相同的任务。一般的解决方案是锁抓取触发器,分布式锁可以通过DB、ZK、Redis等实现。
示例代码如下:
@组件
@启用调度
公共类MyTask {
/**
*每30秒运行一次。
*/
@Scheduled(cron=30 * * * *?)
公共void task1()引发异常{
string lockName=“task 1”;
if (tryLock(lockName)) {
system . out . println( hello cron );
release lock(lock name);
}否则{
返回;
}
}
私有布尔tryLock(字符串锁名){
//TODO
返回true
}
私有void release lock(String lock name){
//TODO
}
}如上图所示,当一个任务被触发时,三个服务器会抢占该任务的锁,只有获得该任务锁的服务器才能执行相应的任务业务逻辑。现在的设计,如果你更细心的话,可以发现它实际上可能会导致重复的任务。例如,任务执行得非常快。这个机器在任务完成后很快就获得锁并释放它。b本机器抢锁后,还是会抢锁,再次执行任务。
如果没有控制和维护,就没有用于原生Spring调度任务的控制台,所以不可能动态地添加和修改调度任务。如果要修改计划任务的配置(例如,每分钟一次到每小时一次),必须修改代码并重新发布应用程序。同时原生的Spring调度任务没有运维,不支持运行一次任务,任务失败也不支持重新运行任务。
如果自主开发的可视化控制台要实现整个任务可视化管控系统,需要一定的前后台R&D成本和服务部署成本的投入。对于需要搭建自己平台的用户,可以参考以下需求函数搭建自己的平台:
任务可视化动态配置,任务执行细节可视化查看,任务执行日志可视化查询分析,执行调用链,调度触发,业务应用间任务信息配置权限隔离,无业务失败通知能力。对于一个完整的企业级计划任务应用方案来说,告警通知能力是必不可少的,任务失败时要及时通知用户,否则可能会失败。
本机Spring定时任务不支持警报通知功能。如果想自己研究,可以参考上一章的《异常统一处理》收集任务失败的信息,构建相应的异常处理机制(包括对接各种报警平台进行异常消息通知,定义不同的异常级别和类别的通知策略),然后进行定时的任务报警通知。
没有在线故障排除和分析能力的调度任务在运行过程中会出现各种问题,比如执行失败、执行耗时、执行卡顿等。这些都需要在后期的实际运维中进行定位和快速分析。在对应分析过程中,如果没有高效的在线故障排除能力,将会出现许多棘手的问题:
集群任务对应的时间点是它在哪个机器上运行。无法从大量的业务应用日志中获知计划任务执行日志需要在哪个时间点进行检索,日志服务需要自身进行改进。如果任务涉及多个跨服务调用,无法定位执行的异常点或耗时点,就需要构建全链路跟踪系统,支持阿里云Spring企业级的调度任务解决方案。
云原生
接下来主要讲一下如何在公有云上使用任务调度SchedulerX轻松访问基于Spring的调度任务。我们谈到了基于Spring的原生函数在使用过程中面临的问题以及需要自己解决的相关解决方案。我们可以看到,仅仅对于企业级最基础的应用场景,就需要花费更多的投入在改造和后续相关服务的运维上。通过接入SchedulerX任务调度平台,原有的Spring调度任务用户可以无缝、零转换地获取企业级应用所需的能力,同时降低运维调度服务相关组件自研和部署的技术成本。
如何访问对于新的SchedulerX用户,访问只需三个步骤(参见随附的访问手册):
对调度平台的访问由SchedulerX的Spring Boot版SDK完成(版本=1.7.2,老用户只能升级SDK版本)。在配置文件中添加配置项,配置开启后,Spring Timer调度器不会运行相关任务(如果没有配置,不会主动接管原有的Spring Timer任务,在配置开启前不会影响原有的Timer任务业务)# Configuration表示SchedulerX将接管Spring Timer任务。
春天。SchedulerX2。任务。日程安排。Scheduler=在ScheduleRX控制台上的相应应用程序分组下创建一个任务配置定时触发器。也可以选择开启自动同步任务配置模式(可选)#自动同步Spring调度任务到调度平台,不需要手动创建(默认不开启)。
spring . scheduler 2 . task . scheduling . sync=true Access Advantage白屏控制和运维提供了可以动态添加、修改、启用和禁用任务的白屏控制台,支持运行一次、原地重新运行、重新刷数据、停止任务、标记成功等运维操作。
在线可视化故障排除支持记录查看、业务日志查询和全链路跟踪。
丰富的报警通知SchedulerX提供丰富的报警通知能力,支持短信、电话、邮件和webhook报警,支持报警联系人组和报警历史,可以动态配置白屏。
其他平台接入方案,有优势,无改造成本。不需要额外的独立运维调度服务平台或其他第三方组件服务。任务运行在稳定可靠支持的集群环境中,避免了原生框架的重复执行,具有自动故障转移能力。在企业中,多个团队可以共享一套平台,通过命名空间和应用分组实现各个团队的任务配置数据隔离和环境隔离。版权归作者所有:博主小二上九八原创作品转载授权请联系作者,否则将追究法律责任。
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。