百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 编程网 > 正文

说说 Spring 定时任务如何大规模企业级运用

yuyutoo 2024-10-12 00:06 8 浏览 0 评论

Spring 定时任务简介

Cloud Native

定时任务是业务应用开发中非常普遍存在的场景(如:每分钟扫描超时支付的订单,每小时清理一次数据库历史数据,每天统计前一天的数据并生成报表等等), 解决方案很多 ,Spring 框架提供了一种通过注解来配置定时任务的解决方案,接入非常的简单,仅需如下两步:

1. 在启动类上添加注解@EnableScheduling

@SpringBootApplication

@EnableScheduling  // 添加定时任务启动注解

public class SpringSchedulerApplication {

    public static void main(String[] args) {

        SpringApplication.run(SpringSchedulerApplication.class, args);

    }

}

2. 开发定时任务 Bean 并配置相应的定时注解@Scheduled

@Component

public class SpringScheduledProcessor {




  /**

     * 通过Cron表达式指定频率或指定时间

     */

    @Scheduled(cron = "0/5 * * * * ?")

    public void doSomethingByCron() {

        System.out.println("do something");

    }

    

  /**

     * 固定执行间隔时间

     */

    @Scheduled(fixedDelay = 2000)

    public void doSomethingByFixedDelay() {

        System.out.println("do something");

    }




    /**

     * 固定执行触发频率

     */

    @Scheduled(fixedRate = 2000)

    public void doSomethingByFixedRate() {

        System.out.println("do something");

    } 

}

Spring 定时任务原理

Cloud Native

运行原理

Spring 定时任务核心逻辑主要在 spring-context 中的 scheduling 包中,其主要结构包括:

  • 定时任务解析:通过 ScheduledTasksBeanDefinitionParser 对 XML 定义任务配置解析;也可通过 ScheduledAnnotationBeanPostProcessor对@Scheduled 注解进行任务解析(常见模式)。
  • 定时任务注册登记:上述解析获得的 Task 任务配置会被注册登记至 ScheduledTaskRegistrar 中以备运行使用。
  • 任务定时运行:完成所有任务注册登记后,会通过 TaskScheduler 正式地定时运行相关任务,底层通过 JDK 的 ScheduledExecutorService 运行任务。

业务逻辑会将被包装在 ScheduledMethodRunnable 类中,其中包含了待执行的目标业务对象 Bean 和业务方法,该 Runnable 对象在运行时会被提交至 ScheduledExecutorService 调度线程池完成任务的定时运行。

从上图可以看到真正要运行的业务逻辑 ScheduledMethodRunnable 会被 ReschedulingRunnable、DelegatingErrorHandlingRunnable 做了代理扩展,这两层代理扩展具有如下意义:

  • DelegatingErrorHandlingRunnable:为业务方法运行异常进行包装处理,提供了自定义异常处理机制、解决 JDK 原生定时任务执行异常后任务失效问题。
  • ReschedulingRunnable:提供了扩展的定时模式支持,可支持基于 Trigger 接口自定义实现获取下次触发时间定时调度,默认提供的 Cron 定时通过此方式进行扩展实现。

定时模式

Spring 定时任务 Task 类的模式主要可分为两类:IntervalTask 和 TriggerTask。前者表示固定频率间隔执行,后者则采用 Trigger 触发器模式实现定时调度,Cron 表达式配置为该模式实现。

  • FixedDelay:按固定延迟频率执行,任务下一次触发时间=上一次执行结束时间+Delay 延迟时间。
  • FixedRate:按固定频率触发执行,任务下一次触发时间=上一次触发时间+Delay 延迟时间。如果上一次执行方法不结束会阻塞下一次任务执行。
  • Cron 表达式:按 Cron 表达式计算下一次触发时间,任务下一次触发时间=cron(上一次执行结束时间)。

进阶扩展

  • 线程池运行

默认配置下底层运行的线程池为单线程,单线程的运行模型在任务量较多且触发频率较高的情况下,一旦某个任务发生阻塞会导致所有后续定时任务运行阻断,这对业务运行带来严重隐患。常见可采用如下方式:

  • 配置定时执行线程池:常见基于配置 Spring Boot 配置(spring.task.scheduling.pool.size=线程数),线程数大小取决于任务数及调度频率合理配置。
  • 配置异步任务:在 spring context 中的 scheduling 模块下提供了@EnableAsync 和@Async,可用于开启任务异步执行,实现定时调度线程池非阻塞运行。该模式下存在一些不足之处:异常处理需要走异步调用的 AsyncUncaughtExceptionHandler 异常处理接口实现,同步/异步定时任务异常处理机制不统一,另外异步模式增加了业务应用的线程开销。
@Scheduled(fixedDelay = 2000)

@Async

public void test() {

    System.out.println(DateUtil.now()+ " test.");

}
  • 异常统一处理

定时任务运行可设置统一异常处理,基于 ErrorHandler 接口开发对应异常处理实现类。对应的异常实现处理类需要注入到核心的 ThreadPoolTaskScheduler 中,用户可以通过自定义 TaskSchedulerCustomizer 方式来实现 ErrorHandler 自定义异常处理 Bean 注入至 ThreadPoolTaskScheduler 中。

@Component

public class DemoTaskSchedulerCustomizer implements TaskSchedulerCustomizer {

    @Override

    public void customize(ThreadPoolTaskScheduler taskScheduler) {

        taskScheduler.setErrorHandler(new DemoErrorHandler());

    }




    private class DemoErrorHandler implements ErrorHandler {

        @Override

        public void handleError(Throwable throwable) {

            System.out.println("异常统一处理.");

        }

    }

}

原生 Spring 定时任务在企业中遇到的问题

Cloud Native

任务重复执行

Spring 定时任务,只要有注解就会执行,在分布式场景下,所有机器代码一致,会导致同一个任务在多台机器上重复执行。 一般的解决方案是抢锁触发,分布式锁实现形式可采用 DB、ZK、Redis 等方式。

示例代码 如下:

@Component

@EnableScheduling

public class MyTask {

    /**

     * 每分钟的第30秒跑一次

     */

    @Scheduled(cron = "30 * * * * ?")

    public void task1() throws Exception {

        String lockName = "task1";

        if (tryLock(lockName)) {

            System.out.println("hello cron");

            releaseLock(lockName);

        } else {

            return;

        }

    }

    private boolean tryLock(String lockName) {

        //TODO

        return true;

    }

    

    private void releaseLock(String lockName) {

        //TODO

    }

}

如 上图所示,当任务触发时 3 个 server 会对任务抢锁,仅获得任务锁的 server 才能执行对应任务业务逻辑。 当前的这个设计,仔细一点的同学可以发现,其实还是有可能导致任务重复执行的。 比如任务执行的非常快,A 这台机器抢到锁,执行完任务后很快就释放锁了。 B 这台机器后抢锁,还是会抢到锁,再执行一遍任务。

无管控无运维

原生 Spring 定时任务没有控制台,无法动态的新增和修改定时任务,如果要修改定时任务的配置(比如每分钟跑一次改成每小时跑一次),必须修改代码重新发布应用。 同时原生Spring定时任务也没有运维操作,不支持运行一次任务,任务失败了也不支持重跑任务。

如果要自研的可视化控制台来实现整套任务可视化管控体系,需要一定的前后端研发成本和服务部署成本投入。对于需要自建的用户而言,可参考以下需求功能进行自有平台建设:

  • 任务的可视化动态配置
  • 任务执行运行详细信息的可视化查看
  • 任务执行日志、执行调用链、调度触发的可视化查询分析
  • 业务应用间任务信息配置权限隔离

无业务失败通知能力

对于完整企业级定时任务运用方案中,报警通知能力必不可少,任务跑失败了需要及时通知到用户,否则可能产生故障。

原生 Spring 定时任务不支持报警通知能力,如果要自研,可以参考上一章节中《异常统一处理》对任务失败的信息进行收集,构建相应的异常处理机制(包括对接各类报警平台进行异常消息通知处理,定义异常等级和类别进行不同的通知策略),然后进行 定时任务报警通知。

无在线排查分析能力

定时任务在运行过程中会存在各种各样的问题,比如: 执行失败、执行耗时、执行卡住等,这些都需要在后期实际运维去定位快速分析。 在对应分析过程中没有高效在线排查能力的话将遇到很多棘手的问题:

  • 集群中任务对应时间点是跑在哪个机器上无从可知
  • 需要在大量的业务应用日志中去检索对应时点的定时任务执行日志,需要自行对接日志服务改善
  • 如果任务涉及多个跨服务调用,无法定位执行异常点或执行耗时点,需要自建全链路追踪来支持

阿里云 Spring 定时任务企业级解决方案

Cloud Native

接下来主要讲下如何利用公有云上任务调度 SchedulerX 轻松接入基于 Spring 开发的定时任务。前面聊了基于 Spring 原生功能在使用过程中面临的问题及需要自行处理解决的相关方案,可以看到仅针对企业级最基础的运用场景下就需要花费较多的改造投入及相关服务后续运维投入。通过接入 SchedulerX 任务调度平台,原本 Spring 定时任务使用者可无缝且 0 改造获得企业级运用所需能力,同时降低了自研部署运维定时服务相关组件的技术成本。

如何接入

对于 SchedulerX 新用户而言接入仅需三步(参考附件接入手册):

  • 依赖 SchedulerX 的 Spring Boot 版 SDK 完成调度平台接入(版本>=1.7.2,老用户仅升级 SDK 版本即可)
  • 配置文件添加配置项,配置开启后 Spring 定时调度器将不运行相关任务(未配置情况下,不会主动接管原 Spring 定时任务运行,在配置开启前不会影响原本定时任务业务运行)
# 配置表示由SchedulerX接管Spring定时任务运行

spring.schedulerx2.task.scheduling.scheduler=schedulerx
  • 控制台上在对应应用分组下创建任务配置定时触发。也可以选择开启自动同步任务配置方式(可选)
# 自动同步Spring定时任务至调度平台,无需单独手动创建(默认不开启)

spring.schedulerx2.task.scheduling.sync=true

接入优势

  • 白屏管控和运维

提供白屏控制台可以动态新增、修改、启用、禁用任务,支持运行一次、原地重跑、重刷数据、停止任务、标记成功等运维操作。

  • 可视化在线排查问题

支持执行记录查看、执行业务日志查询、执行全链路追踪。

  • 丰富的报警通知

SchedulerX 提供丰富的报警通知能力 ,支持短信、电话、邮件、webhook 报警,支持报警联系人组和报警历史,可白屏动态配置。

  • 其他优势
  • 无改造成本的平台接入方案。
  • 无需额外独立运维调度服务平台或其他第三方组件服务。
  • 任务运行在集群环境中具备稳定高可靠支持,规避了原生框架存在的重复执行问题,具备故障自动转移能力。
  • 在企业内多个团队可共享一套平台使用,通过命名空间和应用分组实现各团队任务配置数据隔离及环境隔离。

总结

Cloud Native

本文主要从 Spring 定时任务的运行机制进行剖析阐述,并对如何扩展框架原生能力以满足企业级生产环境运行定时任务所需各种场景提出了相应的建议,用户可作参考构建自己内部定时任务方案。 同时就阿里云上提供的任务调度服务如何接入 Spring 定时任务的运行进行讲解,并简单展示了接入后所带来的企业级能力。 最后欢迎有定时任务业务需求用户可先通过基础免费额度体验感受云上服务带来便捷。

相关推荐

ETCD 故障恢复(etc常见故障)

概述Kubernetes集群外部ETCD节点故障,导致kube-apiserver无法启动。...

在Ubuntu 16.04 LTS服务器上安装FreeRADIUS和Daloradius的方法

FreeRADIUS为AAARadiusLinux下开源解决方案,DaloRadius为图形化web管理工具。...

如何排查服务器被黑客入侵的迹象(黑客 抓取服务器数据)

---排查服务器是否被黑客入侵需要系统性地检查多个关键点,以下是一份详细的排查指南,包含具体命令、工具和应对策略:---###**一、快速初步检查**####1.**检查异常登录记录**...

使用 Fail Ban 日志分析 SSH 攻击行为

通过分析`fail2ban`日志可以识别和应对SSH暴力破解等攻击行为。以下是详细的操作流程和关键分析方法:---###**一、Fail2ban日志位置**Fail2ban的日志路径因系统配置...

《5 个实用技巧,提升你的服务器安全性,避免被黑客盯上!》

服务器的安全性至关重要,特别是在如今网络攻击频繁的情况下。如果你的服务器存在漏洞,黑客可能会利用这些漏洞进行攻击,甚至窃取数据。今天我们就来聊聊5个实用技巧,帮助你提升服务器的安全性,让你的系统更...

聊聊Spring AI Alibaba的YuQueDocumentReader

序本文主要研究一下SpringAIAlibaba的YuQueDocumentReaderYuQueDocumentReader...

Mac Docker环境,利用Canal实现MySQL同步ES

Canal的使用使用docker环境安装mysql、canal、elasticsearch,基于binlog利用canal实现mysql的数据同步到elasticsearch中,并在springboo...

RustDesk:开源远程控制工具的技术架构与全场景部署实战

一、开源远程控制领域的革新者1.1行业痛点与解决方案...

长安汽车一代CS75Plus2020款安装高德地图7.5

不用破解原车机,一代CS75Plus2020款,安装车机版高德地图7.5,有红绿灯读秒!废话不多讲,安装步骤如下:一、在拨号状态输入:在电话拨号界面,输入:*#518200#*(进入安卓设置界面,...

Zookeeper使用详解之常见操作篇(zookeeper ui)

一、Zookeeper的数据结构对于ZooKeeper而言,其存储结构类似于文件系统,也是一个树形目录服务,并通过Key-Value键值对的形式进行数据存储。其中,Key由斜线间隔的路径元素构成。对...

zk源码—4.会话的实现原理一(会话层的基本功能是什么)

大纲1.创建会话...

Zookeeper 可观测性最佳实践(zookeeper能够确保)

Zookeeper介绍ZooKeeper是一个开源的分布式协调服务,用于管理和协调分布式系统中的节点。它提供了一种高效、可靠的方式来解决分布式系统中的常见问题,如数据同步、配置管理、命名服务和集群...

服务器密码错误被锁定怎么解决(服务器密码错几次锁)

#服务器密码错误被锁定解决方案当服务器因多次密码错误导致账户被锁定时,可以按照以下步骤进行排查和解决:##一、确认锁定状态###1.检查账户锁定状态(Linux)```bash#查看账户锁定...

zk基础—4.zk实现分布式功能(分布式zk的使用)

大纲1.zk实现数据发布订阅...

《死神魂魄觉醒》卡死问题终极解决方案:从原理到实战的深度解析

在《死神魂魄觉醒》的斩魄刀交锋中,游戏卡死犹如突现的虚圈屏障,阻断玩家与尸魂界的连接。本文将从技术架构、解决方案、预防策略三个维度,深度剖析卡死问题的成因与应对之策,助力玩家突破次元壁障,畅享灵魂共鸣...

取消回复欢迎 发表评论: