JAVA 实现分布式任务调度:XXL-JOB 集群部署完整流程
大家好,今天我们来聊聊如何在 Java 中实现分布式任务调度,并重点讲解如何使用 XXL-JOB 进行集群部署。分布式任务调度在复杂的企业应用中扮演着至关重要的角色,它可以帮助我们实现定时任务、异步处理、数据同步等功能,极大地提高系统的效率和可维护性。
一、为什么需要分布式任务调度?
在单体应用中,我们可以使用 Java 自带的 Timer 或者 ScheduledExecutorService 来实现简单的定时任务。但是,随着业务规模的扩大,单点任务调度会面临以下问题:
- 单点故障: 单个节点宕机,所有任务都将无法执行。
- 资源瓶颈: 单个节点的资源有限,无法支撑大量的并发任务。
- 任务管理困难: 分布在不同应用中的任务难以统一管理和监控。
- 任务调度冲突: 在多实例部署的应用中,相同的任务可能会被重复执行。
分布式任务调度旨在解决上述问题,它将任务调度逻辑从应用中剥离出来,形成一个独立的调度中心,负责任务的分配、执行和监控。
二、XXL-JOB 简介
XXL-JOB 是一个开源的分布式任务调度平台,由大众点评开源,现已托管于 Github,并被广泛应用于各种场景。它具有以下特点:
- 简单易用: 提供可视化的管理界面,操作简单,易于上手。
- 高可用性: 支持集群部署,保证调度中心的可用性。
- 弹性伸缩: 可以根据任务量动态调整 Worker 节点的数量。
- 丰富的任务类型: 支持多种任务类型,包括 Java 方法、Shell 脚本、Python 脚本等。
- 强大的监控和告警: 提供完善的任务监控和告警机制,及时发现和处理问题。
- 轻量级: 核心代码简洁,易于维护和扩展。
三、XXL-JOB 核心概念
在深入了解 XXL-JOB 的部署和使用之前,我们需要先了解其几个核心概念:
| 概念 | 描述 |
|---|---|
| 调度中心 (Admin) | 负责任务的管理、调度和监控。通常以集群方式部署,保证高可用性。 |
| 执行器 (Executor) | 负责执行具体的任务。通常部署在业务系统中,通过 HTTP 接口与调度中心通信。 |
| 任务 (Job) | 需要被调度的具体任务。包括任务的执行逻辑、调度策略、参数等。 |
| 注册中心 | 用于服务注册和发现。Executor 通过注册中心向 Admin 注册自己的地址信息,Admin 通过注册中心获取 Executor 的地址信息。XXL-JOB 支持多种注册中心,包括 Zookeeper、Redis、Nacos 等。如果 Executor 和 Admin 在同一个网络环境,也可以使用内置的 Static 注册方式,直接配置 Executor 的地址信息。 |
| 任务处理器 (JobHandler) | 任务的执行逻辑。在 Executor 中定义,负责执行具体的任务。 |
四、XXL-JOB 集群部署流程
下面我们将详细讲解如何进行 XXL-JOB 的集群部署。
1. 环境准备
- Java 环境: JDK 1.8+
- MySQL 数据库: 用于存储 XXL-JOB 的配置信息和任务执行日志。
- ZooKeeper (可选): 如果需要使用 ZooKeeper 作为注册中心,需要安装 ZooKeeper 集群。其他注册中心同理。
- Maven: 用于构建和管理 XXL-JOB 项目。
2. 下载 XXL-JOB 源码
从 XXL-JOB 的 Github 仓库下载最新版本的源码:
git clone https://github.com/xuxueli/xxl-job.git
3. 初始化数据库
在 MySQL 数据库中创建 XXL-JOB 的数据库,并导入 doc/db/tables_xxl_job.sql 文件。
CREATE DATABASE `xxl_job` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
USE `xxl_job`;
-- 导入SQL文件
source tables_xxl_job.sql;
4. 修改 XXL-JOB Admin 配置
进入 xxl-job/xxl-job-admin 目录,修改 src/main/resources/application.properties 文件,配置数据库连接信息和注册中心信息。
### 数据库配置
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/xxl_job?Unicode=true&characterEncoding=UTF-8&autoReconnect=true&serverTimezone=Asia/Shanghai
spring.datasource.username=root
spring.datasource.password=root
### 注册中心配置 (选择一种)
# 1. Static (如果 Executor 和 Admin 在同一个网络环境,推荐使用)
xxl.job.admin.addresses=http://127.0.0.1:8081,http://127.0.0.1:8082 #多个admin用逗号分隔
# 2. Zookeeper
#xxl.job.admin.addresses=http://127.0.0.1:8080
#xxl.job.registry.address=127.0.0.1:2181
# 3. Redis
#xxl.job.admin.addresses=http://127.0.0.1:8080
#xxl.job.registry.address=127.0.0.1:6379
# 4. Nacos
#xxl.job.admin.addresses=http://127.0.0.1:8080
#xxl.job.registry.address=127.0.0.1:8848
### 报警邮箱
xxl.job.mail.server.host=smtp.qq.com
xxl.job.mail.server.port=465
[email protected]
xxl.job.mail.server.password=your_password # 授权码
xxl.job.mail.server.ssl=true
[email protected]
5. 部署 XXL-JOB Admin 集群
将 xxl-job-admin 项目打包成 WAR 包,并部署到多个 Tomcat 或其他 Web 容器中。
cd xxl-job/xxl-job-admin
mvn clean package
将 xxl-job-admin.war 部署到不同的服务器上,例如:
- 服务器 A: 127.0.0.1:8081
- 服务器 B: 127.0.0.1:8082
确保每台服务器上的 application.properties 文件配置一致,并且 xxl.job.admin.addresses 配置指向所有 Admin 节点的地址。比如上面的例子中,两台服务器的 xxl.job.admin.addresses 都需要配置为 http://127.0.0.1:8081,http://127.0.0.1:8082。
6. 修改 XXL-JOB Executor 配置
进入 xxl-job/xxl-job-executor-samples/xxl-job-executor-sample-springboot 目录,修改 src/main/resources/application.properties 文件,配置 Admin 地址和注册中心信息。
### XXL-JOB admin address list, multiple addresses are separated by commas
xxl.job.admin.addresses=http://127.0.0.1:8081,http://127.0.0.1:8082
### XXL-JOB executor address.
### 1、为空表示自动获取,优先获取网卡IP,其次是 HOST。
### 2、手动指定,例如:address=http://127.0.0.1:9999
xxl.job.executor.address=
### XXL-JOB executor appname, ensure that each executor has a unique appname
xxl.job.executor.appname=xxl-job-executor-sample
### XXL-JOB executor port
xxl.job.executor.port=9999
### XXL-JOB executor log path
xxl.job.executor.logpath=/data/applogs/xxl-job/jobhandler
### XXL-JOB, access token
xxl.job.accessToken=default_token
### 注册中心配置 (选择一种)
# 1. Static (如果 Executor 和 Admin 在同一个网络环境,推荐使用)
#xxl.job.registry.address=
# 2. Zookeeper
#xxl.job.registry.address=127.0.0.1:2181
# 3. Redis
#xxl.job.registry.address=127.0.0.1:6379
# 4. Nacos
#xxl.job.registry.address=127.0.0.1:8848
7. 定义任务处理器 (JobHandler)
在 xxl-job-executor-sample-springboot 项目中,定义一个任务处理器,用于执行具体的任务逻辑。
package com.xxl.job.executor.service.jobhandler;
import com.xxl.job.core.context.XxlJobHelper;
import com.xxl.job.core.handler.annotation.XxlJob;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import java.util.concurrent.TimeUnit;
@Component
public class DemoJobHandler {
private static final Logger logger = LoggerFactory.getLogger(DemoJobHandler.class);
@XxlJob("demoJobHandler")
public void demoJobHandler() throws Exception {
logger.info("XXL-JOB, demoJobHandler start");
for (int i = 0; i < 5; i++) {
XxlJobHelper.log("beat at:" + i);
TimeUnit.SECONDS.sleep(2);
}
logger.info("XXL-JOB, demoJobHandler end");
// default success
}
}
在这个例子中,我们定义了一个名为 demoJobHandler 的任务处理器,它会循环打印 5 次日志,每次间隔 2 秒。 @XxlJob("demoJobHandler") 注解用于指定任务的名称,这个名称需要在 XXL-JOB Admin 中配置。
8. 部署 XXL-JOB Executor
将 xxl-job-executor-sample-springboot 项目打包成 JAR 包,并部署到业务系统中。
cd xxl-job/xxl-job-executor-samples/xxl-job-executor-sample-springboot
mvn clean package
将 xxl-job-executor-sample-springboot.jar 部署到业务系统中,并启动应用。
java -jar xxl-job-executor-sample-springboot.jar
9. 配置 XXL-JOB 任务
登录 XXL-JOB Admin 管理界面 (例如:http://127.0.0.1:8081/xxl-job-admin ),添加一个任务,配置任务的执行器、任务处理器、调度策略等信息。
- 执行器: 选择刚刚部署的 Executor 的
appname(例如:xxl-job-executor-sample)。 - JobHandler: 输入任务处理器在 Executor 中定义的名称 (例如:
demoJobHandler)。 - Cron 表达式: 设置任务的调度时间,例如:
0/5 * * * * ?表示每 5 秒执行一次。 - 其他配置: 根据实际需求配置任务的其他参数,例如:任务描述、超时时间、失败重试次数等。
五、代码详解
下面我们对关键的代码进行详细的解释。
-
Admin 的
application.properties:### 数据库配置 spring.datasource.url=jdbc:mysql://127.0.0.1:3306/xxl_job?Unicode=true&characterEncoding=UTF-8&autoReconnect=true&serverTimezone=Asia/Shanghai spring.datasource.username=root spring.datasource.password=root ### 注册中心配置 (选择一种) # 1. Static (如果 Executor 和 Admin 在同一个网络环境,推荐使用) xxl.job.admin.addresses=http://127.0.0.1:8081,http://127.0.0.1:8082 #多个admin用逗号分隔spring.datasource.url、spring.datasource.username、spring.datasource.password:配置数据库连接信息,用于存储 XXL-JOB 的配置信息和任务执行日志。xxl.job.admin.addresses:配置 Admin 集群的地址,多个地址用逗号分隔。Executor 会通过这些地址与 Admin 进行通信。
-
Executor 的
application.properties:### XXL-JOB admin address list, multiple addresses are separated by commas xxl.job.admin.addresses=http://127.0.0.1:8081,http://127.0.0.1:8082 ### XXL-JOB executor appname, ensure that each executor has a unique appname xxl.job.executor.appname=xxl-job-executor-sample ### XXL-JOB executor port xxl.job.executor.port=9999 ### XXL-JOB, access token xxl.job.accessToken=default_tokenxxl.job.admin.addresses:配置 Admin 集群的地址,与 Admin 中的配置保持一致。xxl.job.executor.appname:配置 Executor 的名称,在 XXL-JOB Admin 中用于标识 Executor。这个名称需要唯一,不同的 Executor 应该使用不同的appname。xxl.job.executor.port:配置 Executor 的端口号,用于接收 Admin 的调度请求。xxl.job.accessToken:配置访问令牌,用于验证 Executor 和 Admin 之间的通信。
-
任务处理器 (
DemoJobHandler)@Component public class DemoJobHandler { private static final Logger logger = LoggerFactory.getLogger(DemoJobHandler.class); @XxlJob("demoJobHandler") public void demoJobHandler() throws Exception { logger.info("XXL-JOB, demoJobHandler start"); for (int i = 0; i < 5; i++) { XxlJobHelper.log("beat at:" + i); TimeUnit.SECONDS.sleep(2); } logger.info("XXL-JOB, demoJobHandler end"); // default success } }@Component:将DemoJobHandler注册为 Spring Bean,方便 XXL-JOB 加载和管理。@XxlJob("demoJobHandler"):将demoJobHandler方法注册为 XXL-JOB 的任务处理器。"demoJobHandler"是任务的名称,需要在 XXL-JOB Admin 中配置。XxlJobHelper.log():用于在任务执行过程中打印日志,这些日志会在 XXL-JOB Admin 中显示。
六、使用 ZooKeeper 作为注册中心
上面我们讲解了使用 Static 方式进行服务注册和发现。如果你的 Executor 和 Admin 不在同一个网络环境,或者需要更高级的服务发现功能,可以使用 ZooKeeper 作为注册中心。
-
配置 Admin 的
application.properties:xxl.job.admin.addresses=http://127.0.0.1:8081,http://127.0.0.1:8082 xxl.job.registry.address=127.0.0.1:2181取消
Static注册方式的注释,并配置 ZooKeeper 的地址。 -
配置 Executor 的
application.properties:xxl.job.admin.addresses=http://127.0.0.1:8081,http://127.0.0.1:8082 xxl.job.registry.address=127.0.0.1:2181取消
Static注册方式的注释,并配置 ZooKeeper 的地址。 -
启动 ZooKeeper 集群
确保 ZooKeeper 集群正常运行。
完成以上配置后,Executor 会自动将自己的地址信息注册到 ZooKeeper 中,Admin 会通过 ZooKeeper 获取 Executor 的地址信息,从而实现任务的调度。
七、FAQ
-
Q: XXL-JOB Admin 无法访问?
- 确保 Admin 应用已正确部署到 Web 容器中。
- 检查 Admin 的端口是否被占用。
- 检查防火墙是否阻止了对 Admin 的访问。
-
Q: Executor 无法连接到 Admin?
- 检查 Executor 的
xxl.job.admin.addresses配置是否正确,确保指向所有 Admin 节点的地址。 - 检查 Executor 和 Admin 之间的网络是否畅通。
- 检查防火墙是否阻止了 Executor 和 Admin 之间的通信。
- 检查 Admin 和 Executor 的
xxl.job.accessToken配置是否一致。
- 检查 Executor 的
-
Q: 任务执行失败?
- 查看 XXL-JOB Admin 中的任务执行日志,了解任务执行失败的原因。
- 检查 Executor 的日志,查找是否有异常信息。
- 确保任务处理器中的代码没有错误。
八、总结
本次讲座主要介绍了 XXL-JOB 的概念、核心组件以及集群部署流程。 通过学习这些内容,大家可以搭建自己的分布式任务调度平台,并解决实际业务中的任务调度问题。
正确配置 Admin 和 Executor 的参数,并定义合适的任务处理器,是成功实现分布式任务调度的关键。
分布式调度的重要性
分布式任务调度能够解决单点故障和资源瓶颈,提高系统的可用性和可扩展性。
XXL-JOB 的优势
XXL-JOB 简单易用、高可用、弹性伸缩,是一个优秀的分布式任务调度平台。
集群部署的步骤
集群部署涉及环境准备、源码下载、配置修改、应用部署和任务配置等步骤。