elastic-job 定时任务 —— 失效转移、任务错过机制与幂等机制


作业配置项

lastic-job 定时任务 —— elasticjob 介绍与使用教程 一文中介绍了 elasticjob 及基本使用,这里深入讲解 elasticjob 的三个重要功能:失效转移、任务错过机制与幂等性,在讲解三个功能之前,先简单介绍作业配置项中的几个属性。

可配置属性
属性名类型缺省值描述
jobNameString作业名称
shardingTotalCountint作业分片总数
cronStringCRON 表达式,用于控制作业触发时间
timeZoneStringCRON 的时区设置
shardingItemParametersString个性化分片参数
jobParameterString作业自定义参数
monitorExecutionbooleantrue监控作业运行时状态
failoverbooleanfalse是否开启任务执行失效转移
misfirebooleantrue是否开启错过任务重新执行
maxTimeDiffSecondsint-1(不检查)最大允许的本机与注册中心的时间误差秒数
reconcileIntervalMinutesint10修复作业服务器不一致状态服务调度间隔分钟
jobShardingStrategyTypeStringAVG_ALLOCATION作业分片策略类型
jobExecutorThreadPoolSizeProviderStringCPU作业线程池处理策略
jobErrorHandlerTypeString作业错误处理策略
descriptionString作业描述信息
propsProperties作业属性配置信息
disabledbooleanfalse作业是否禁止启动
overwritebooleanfalse本地配置是否可覆盖注册中心配置

这里只着重介绍以下几个作用配置属性:overwrite、monitorExecution、failover、misfire。


overwrite 配置覆盖

overwrite:本地配置是否可覆盖注册中心配置。默认为 false 不可覆盖;true 代表可覆盖,每次启动作业都以本地配置为准。

当启动一个 job 服务时,相关配置会传到 zookeeper 注册中心中。当改变配置后:若 overwrite=false(默认值),重启或者启动新的任务服务,更改后的配置也不会上传到 zookeeper 中,启动服务执行任务还是使用原来的配置。若 overwrite=true,重启或者启动新的任务服务,相关配置会传到 zookeeper 注册中心中并覆盖掉之前的配置,会以最后一次启动上传的配置为准,所以以后任务执行时,都会从 zookeeper 中得到最新的配置执行。

示例:设置 overwrite=true
作业配置如下:

private LiteJobConfiguration createJobConfiguration() {
    // 定义作业核心配置
    // 作业名称:"demoSimpleJob"、 CRON 表达式,控制作业触发时间:"0/15 * * * * ?"、 作业分片总数:2
    JobCoreConfiguration coreConfig =
        JobCoreConfiguration.newBuilder("demoSimpleJob", "0 0/5 * * * ?", 4).failover(true).misfire(true).build();
    // 定义 SIMPLE 作业类型配置
    SimpleJobConfiguration jobConfig =
        new SimpleJobConfiguration(coreConfig, myJob.getClass().getCanonicalName());
    // 定义 Lite 作业根配置
    LiteJobConfiguration simpleJobRootConfig =
        LiteJobConfiguration.newBuilder(jobConfig).overwrite(true).monitorExecution(true).build();
    return simpleJobRootConfig;
}

作业代码如下:

@Component
@Qualifier("myJob")
public class MyJob implements SimpleJob {
    @Override
    public void execute(ShardingContext context) {
        for (int i = 1; i <= 6; i++) {
            System.out.println("第【" + i + "】次执行分片" + context.getShardingItem() + ",dateTime:" + new Date(System.currentTimeMillis()));
            try {
                Thread.sleep(10000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }
}

先设置分片总数为1,启动一个任务服务A。可以看到定时时间到时服务A触发执行任务,结果如下:(分片的概念看这篇文章 lastic-job 定时任务 —— elasticjob 介绍与使用教程
在这里插入图片描述

接下来修改分片总数为4(一个任务分成独立的4个片段去执行),启动一个新的任务服务B。任务服务A执行完上一个任务后,elastic-job 会读取配置重新分片,并在下一次任务触发执行时按照新的配置执行,如下所示:

任务服务A触发执行新任务,执行 [0, 1] 分片。
在这里插入图片描述
任务服务B触发执行任务,执行 [2, 3] 分片。
在这里插入图片描述


monitorExecution 监控作业运行时状态

monitorExecution:监控作业运行时状态,false 代表不监控,true 代表监控(默认是开启监控的)。可以用于实时查看作业的执行情况、统计信息和错误信息等。

启用 monitorExecution = ture 的作用和好处:

  • 实时监控作业执行情况:通过启用监控功能,可以实时查看作业的执行情况,包括作业是否在运行、作业的运行时间、作业的触发次数等。能够追踪作业的执行状态,确保它按照预期方式进行运行。
  • 统计作业的执行信息:监控功能可以收集有关作业执行的统计信息,如作业的成功执行次数、失败执行次数、平均执行时间等。这些统计信息可以用于了解作业的整体执行情况,并进行性能分析和优化。
  • 错误信息追踪和排查:启用监控功能后,可以获取作业执行过程中的错误信息。这对于故障排查和调试非常有帮助。可以查看作业执行的堆栈跟踪、异常信息和错误日志等,以便快速定位和解决问题。
  • 提供可视化的监控界面:ElasticJob 提供了监控中心(JobTracker)和作业状态展示页面(JobStatus Trace),通过这些界面可以直观地查看作业的执行状态、统计信息和错误信息。这些界面通常以图表、列表或日志的形式呈现,能够轻松地监控和分析作业的运行情况。

在每次作业执行时间和间隔时间均非常短的情况下,建议不监控作业运行时状态以提升效率。因为是瞬时状态,所以没必要监控。

Elastic-Job 如何保证一次任务触发,相同分片不会被重复处理(幂等机制)

开启 monitorExecution = true 能实现分布式作业幂等性,不会在多个作业服务器运行同一个分片。Elastic-Job 在开启 monitorExecution = true【幂等机制】机制的情况下,会在分片任务开始时会在注册中心 zookeeper 上创建 ${namespace}/jobname/sharding/{item}/running 临时节点,在任务结束后会删除该目录。但 monitorExecution 对短时间内执行的作业(如秒级触发)性能影响较大,建议关闭并自行实现幂等性,并自行在作业中实现幂等性机制。


failover 失效转移

failover:是否开启任务执行失效转移,false 代表不开启(默认是不开启的),true 代表开启。ElasticJob 不会在本次执行过程中进行重新分片,而是等待下次调度之前才开启重新分片流程。 当作业执行过程中服务器宕机,失效转移允许将该次未完成的任务在另一作业节点上补偿执行。

在一次运行耗时较长且间隔较长的作业场景,失效转移是提升作业运行实时性的有效手段; 对于间隔较短的作业,会产生大量与注册中心的网络通信,对集群的性能产生影响。 而且间隔较短的作业并未见得关注单次作业的实时性,可以通过下次作业执行的重分片使所有的分片正确执行,因此不建议短间隔作业开启失效转移。虽然失效转移能够重新执行分配给宕机的任务,但并不能完全保证业务的幂等性,还是建议在作业中实现幂等性,以确保数据的正确处理。

失效转移是当前执行作业的临时补偿执行机制,在下次作业运行时,会通过重分片对当前作业分配进行调整。 举例说明,若作业以每小时为间隔执行,每次执行耗时 30 分钟。如下如图所示。
在这里插入图片描述
图中表示作业分别于 12:00,13:00 和 14:00 执行。图中显示的当前时间点为 13:00 的作业执行中。

如果作业的其中一个分片服务器A在 13:10 的时候宕机,那么剩余的 20 分钟应该处理的业务未得到执行,并且需要在 14:00 时才能再次开始执行下一次作业。 也就是说,在不开启失效转移的情况下,位于该分片的作业有 50 分钟空档期。

在开启失效转移功能之后,ElasticJob 的其他服务器B能够在感知到宕机的作业服务器A之后,在执行完此次分配给自己的分片任作业后,会马上补偿执行此次分配给服务A的分片作业。下次定时任务触发时,会重新分配分片,并且分配给其他可用服务B。如下图所示。
在这里插入图片描述

开启失效转移 failover = true,设置定时任务每5分钟执行一次,任务分成4片,启动两台作业服务分别执行任务的这四个分片作业,服务A执行[0, 1]分片,服务B执行[2, 3]分片,在服务A执行过程中突然停止服务(宕机),运行结果如下。

服务A分配执行[0, 1]分片作业,触发此次任务执行过程中突然宕机,如下图:
在这里插入图片描述
服务B分配执行[2, 3]分片作业,执行完此次分配的[2, 3]分片后,还未到下次定时触发调度,就马上执行了[0, 1]分片,说明服务A宕机后,分片任务转移到服务B中执行了。若未开启失效转移,此次[0, 1]分片作业不会被执行,只有等下次定时任务触发。下次定时任务触发,四个分片都会分配给服务B执行。如下图失效转移运行结果:
在这里插入图片描述


misfire 任务错过机制

misfire:是否开启错过任务重新执行,false 代表不开启,true 代表开启(默认是开启的)。ElasticJob 不允许作业在同一时间内叠加执行。 当作业的执行时长超过其运行间隔,错过任务重执行能够保证作业在完成上次的任务后继续执行逾期的作业。

在一次运行耗时较长且间隔较长的作业场景,错过任务重执行是提升作业运行实时性的有效手段; 对于未见得关注单次作业的实时性的短间隔的作业来说,开启错过任务重执行并无必要。

错过任务重执行功能可以使逾期未执行的作业在之前作业执行完成之后立即执行。 举例说明,若作业以每小时为间隔执行,每次执行耗时 30 分钟。如下如图所示。
在这里插入图片描述
图中表示作业分别于 12:00,13:00 和 14:00 执行。图中显示的当前时间点为 13:00 的作业执行中。

如果 12:00 开始执行的作业在 13:10 才执行完毕,那么本该由 13:00 触发的作业则错过了触发时间,需要等待至 14:00 的下次作业触发。

在开启错过任务重执行功能之后,ElasticJob 将会在上次作业执行完毕后,立刻触发执行错过的作业,在 13:00 和 14:00 之间错过的作业将会重新执行。如下图所示。
在这里插入图片描述

开启错过任务重新执行 misfire = true,设置定时任务每2分钟执行一次,任务分成1片,任务执行时间为5分钟,使用事件跟踪功能看运行状态(ElasticJob 事件跟踪见后文),结果如下。

第一次触发任务执行5分钟,第一次触发的任务还没有执行完就触发了第二次任务,此时第二次不会叠加执行,会先记录,等第一次任务执行完后接着再执行第二次触发的任务。
在这里插入图片描述
job_execution_log 记录了每次触发的任务,可以看到第一次触发任务执行来源是 NORMAL_TRIGGER(正常触发)、第二次触发任务执行来源是 MISFIRE(错过重试)。
在这里插入图片描述

job_status_trace_log 记录作业状态变更痕迹,任务状态从TASK_STAGING —— TASK_RUNNING —— TASK_FINISHED 变化。
在这里插入图片描述

同时可以打开 zookeeper 客户端,在 ${namespace}/jobname/shading/{item}/ 对应分片下可以看到对应节点 。如在 zookeeper 命名空间 namespace = elastic-job-demo-zoo 下,有作业名称为 jobname = demoSimpleJob 的定时任务,有分片 sharding,分片为 0 的下会看到 misfire 节点。
在这里插入图片描述

开启错过任务重新执机制,才会出现${namespace}/jobname/sharding/{item}/misfire 节点(根据不同配置,还会有其他节点,如开启 failover = true,会有 failover 节点;开启 monitorExecution = true,会有 running 节点)。只要当前任务执行未完成,则新触发的任务怎会错过等待并且会增加 misfire 节点,会忽略后面继续触发的任务,直到错过的任务被执行完结束后再执行其他未忽略的任务。


事件跟踪

ElasticJob 事件跟踪。ElasticJob 提供了事件追踪功能,可通过事件订阅的方式处理调度过程的重要事件,用于查询、统计和监控。 目前提供了基于关系型数据库的事件订阅方式记录事件。

数据源配置:

@Bean
@Qualifier("dataSource")
public static DataSource getDataSource() throws Exception {
    MysqlDataSource dataSource = new MysqlDataSource();
    dataSource.setUser("root");
    dataSource.setPassword("root");
    dataSource.setURL("jdbc:mysql://localhost:3306/elastic_job?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true");
    return dataSource;
}

事件跟踪配置并注册:

@Bean(initMethod = "init")
public JobScheduler jobDemo() throws Exception {
    // 定义事件跟踪配置(注意数据源)
    JobEventConfiguration jobEventRdbConfig = new JobEventRdbConfiguration(dataSource);
    // 注册中心、job作业配置、事件跟踪配置;注入配置后启动定时任务计划
    JobScheduler jobScheduler = new JobScheduler(createRegistryCenter(), createJobConfiguration(),
                                                 jobEventRdbConfig);
    return jobScheduler;
}

启动定时任务后,会在数据库中自动生成 job_execution_log 和 job_status_trace_log 两张表。触发任务执行会在表中记录任务触发及执行情况。(若发现任务执行时表中没有落数据,可能是默认建表的字段设定的太大,将字段长度改小即可)

job_execution_log:
在这里插入图片描述
job_execution_log 表记录每次作业的执行历史。

  • execution_source:作业执行来源。可选值为NORMAL_TRIGGER, MISFIRE, FAILOVER
    分为两个步骤:
  1. 作业开始执行时向数据库插入数据,除failure_cause和complete_time外的其他字段均不为空。
  2. 作业完成执行时向数据库更新数据,更新is_success, complete_time和failure_cause(如果作业执行失败)。

job_status_trace_log:
在这里插入图片描述
job_status_trace_log 记录作业状态变更痕迹表。可通过每次作业运行的 task_id 查询作业状态变化的生命周期和运行轨迹。

  • execution_type:任务执行类型,可选值为NORMAL_TRIGGER, MISFIRE, FAILOVER;
  • state:任务执行状态,可选值为TASK_STAGING, TASK_RUNNING, TASK_FINISHED, TASK_KILLED, TASK_LOST, TASK_FAILED, TASK_ERROR。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值