常用定时任务框架
-
JDK 自带的
ScheduledExecutorService
- 适用于轻量级定时任务,基于线程池实现。
- API 简单,适用于小规模任务调度。
-
Quartz
- 强大的 Java 任务调度框架,支持 Cron 表达式、分布式集群、持久化等。
- 适用于复杂调度场景,如动态任务管理、任务持久化等。
-
Spring Task
- Spring 提供的轻量级定时任务方案,支持
@Scheduled
注解,简洁易用。 - 适用于简单的定时任务,不支持集群和分布式调度。
- Spring 提供的轻量级定时任务方案,支持
-
XXL-JOB
- 轻量级分布式任务调度框架,支持集群、动态管理任务、任务日志、失败重试等功能。
- 适用于互联网企业的大规模定时任务场景。
-
Elastic-Job
- 基于 Zookeeper 的分布式任务调度框架,支持分片、失效转移、任务高可用等特性。
- 适用于大规模分布式任务调度,如电商、金融等业务场景。
-
PowerJob
- 基于 Spring Boot 开发的分布式任务调度框架,支持分布式、秒级调度、任务依赖等功能。
- 适用于现代分布式任务管理,支持 Web 可视化管理。
分布式定时任务框架
如果你的项目被 多个相同实例的 Pod 复制 并部署在 Kubernetes 集群中,那么使用普通的 @Scheduled
或 ScheduledExecutorService
就会导致 每个 Pod 都会执行同一个定时任务,可能会产生 重复任务执行 的问题。为了解决这个问题,你可以选择 支持分布式调度 的定时任务框架,主要有以下几种推荐方案:
1. Elastic-Job(推荐)
- 适用场景:适用于 微服务架构,可基于 Zookeeper 进行任务分片,实现分布式调度。
- 特点:
- 分片执行:不同 Pod 执行任务的不同部分,避免重复执行。
- 任务失效转移:某个 Pod 宕机后,任务会自动转移给其他 Pod 继续执行。
- 支持高可用:基于 Zookeeper 进行任务协调,防止重复执行。
- 适用于:
- 高并发业务,如订单对账、数据同步、日志清理等。
- 需要保证每个任务只执行一次,或按分片方式执行的场景。
2. XXL-JOB
- 适用场景:适用于 Spring Boot + 集群环境,提供一个 调度中心 统一管理任务,避免重复执行。
- 特点:
- 基于调度中心(Admin)统一管理定时任务。
- 任务分片:可配置多个 Pod 执行不同的任务片段,防止重复执行。
- 失败重试:任务失败后可自动重试。
- 可视化管理:Web 界面配置任务,支持动态修改。
- 适用于:
- 需要 Web 可视化管理任务的场景。
- 希望任务分布式执行,并能动态调整任务执行策略。
Elastic-Job 示例代码
下面是 Elastic-Job 在分布式集群环境下的完整示例代码,基于 Spring Boot + Zookeeper,实现了 分布式定时任务调度。
功能概述
- 采用
Spring Boot + Elastic-Job-Lite
实现分布式定时任务。 - 任务注册到 Zookeeper,保证 多个实例(Pod)不会重复执行同一任务,可实现 任务分片。
- 适用于 Kubernetes、Docker Swarm 及 普通分布式集群环境。
配置 Zookeeper
在 application.yml
中配置 Elastic-Job 连接 Zookeeper:
spring:
application:
name: elastic-job-demo
elasticjob:
reg-center:
server-lists: zk-host:2181 # 替换为你的 Zookeeper 地址
namespace: elastic-job-demo # 在 Zookeeper 创建的命名空间
jobs:
demoJob:
cron: "0/10 * * * * ?" # 每 10 秒执行一次
sharding-total-count: 3 # 任务分片总数,多个实例共同执行任务
overwrite: true # 是否覆盖旧任务
编写定时任务
新建 分片任务,继承 SimpleJob
,实现 execute()
方法:
import org.apache.shardingsphere.elasticjob.api.ShardingContext;
import org.apache.shardingsphere.elasticjob.simple.job.SimpleJob;
import org.springframework.stereotype.Component;
@Component
public class MyElasticJob implements SimpleJob {
@Override
public void execute(ShardingContext shardingContext) {
// 获取当前分片编号
int shardingItem = shardingContext.getShardingItem();
String jobName = shardingContext.getJobName();
// 模拟不同分片处理不同数据
switch (shardingItem) {
case 0:
System.out.println("【分片 0】执行任务:" + jobName);
break;
case 1:
System.out.println("【分片 1】执行任务:" + jobName);
break;
case 2:
System.out.println("【分片 2】执行任务:" + jobName);
break;
default:
System.out.println("【未知分片】执行任务:" + jobName);
}
}
}
注册任务
创建 ElasticJobConfig
,将任务注册到 ElasticJob
:
import org.apache.shardingsphere.elasticjob.api.JobConfiguration;
import org.apache.shardingsphere.elasticjob.lite.api.bootstrap.impl.ScheduleJobBootstrap;
import org.apache.shardingsphere.elasticjob.lite.api.bootstrap.impl.OneOffJobBootstrap;
import org.apache.shardingsphere.elasticjob.lite.api.listener.ElasticJobListener;
import org.apache.shardingsphere.elasticjob.reg.zookeeper.ZookeeperRegistryCenter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class ElasticJobConfig {
private final ZookeeperRegistryCenter regCenter;
private final MyElasticJob myElasticJob;
public ElasticJobConfig(ZookeeperRegistryCenter regCenter, MyElasticJob myElasticJob) {
this.regCenter = regCenter;
this.myElasticJob = myElasticJob;
}
@Bean
public ScheduleJobBootstrap initElasticJob() {
JobConfiguration jobConfig = JobConfiguration.newBuilder("myElasticJob", 3)
.cron("0/10 * * * * ?") // 每 10 秒执行
.overwrite(true) // 覆盖旧任务
.build();
return new ScheduleJobBootstrap(regCenter, myElasticJob, jobConfig);
}
}
配置 Zookeeper 注册中心
创建 ZookeeperConfig
以连接 Zookeeper:
import org.apache.shardingsphere.elasticjob.reg.zookeeper.ZookeeperConfiguration;
import org.apache.shardingsphere.elasticjob.reg.zookeeper.ZookeeperRegistryCenter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class ZookeeperConfig {
@Bean(initMethod = "init")
public ZookeeperRegistryCenter regCenter() {
return new ZookeeperRegistryCenter(
new ZookeeperConfiguration("zk-host:2181", "elastic-job-demo")
);
}
}