JAVA 实现分布式任务调度?使用 XXL-JOB 集群部署完整流程

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.urlspring.datasource.usernamespring.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_token
    • xxl.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 作为注册中心。

  1. 配置 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 的地址。

  2. 配置 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 的地址。

  3. 启动 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 配置是否一致。
  • Q: 任务执行失败?

    • 查看 XXL-JOB Admin 中的任务执行日志,了解任务执行失败的原因。
    • 检查 Executor 的日志,查找是否有异常信息。
    • 确保任务处理器中的代码没有错误。

八、总结

本次讲座主要介绍了 XXL-JOB 的概念、核心组件以及集群部署流程。 通过学习这些内容,大家可以搭建自己的分布式任务调度平台,并解决实际业务中的任务调度问题。
正确配置 Admin 和 Executor 的参数,并定义合适的任务处理器,是成功实现分布式任务调度的关键。

分布式调度的重要性

分布式任务调度能够解决单点故障和资源瓶颈,提高系统的可用性和可扩展性。

XXL-JOB 的优势

XXL-JOB 简单易用、高可用、弹性伸缩,是一个优秀的分布式任务调度平台。

集群部署的步骤

集群部署涉及环境准备、源码下载、配置修改、应用部署和任务配置等步骤。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注