扩展------分布式调度任务框架XXL-JOB

目录


定时任务

         在我们的java应用程序中,可以设定在特定的时间点或按照一定的时间间隔自动执行的任务。

定时任务的应用场景

        用户画像:大数据时代,比如淘宝我们的浏览记录都会被埋点,然后定时的在一个时间段(一般是选择凌晨)去分析给用户打标签tag,然后再进行定向推荐。

        消息推送: 比如库存到期,证照合同到期,网点生命周期到期,需要做提前的消息提醒,可以设置定时任务每天去检查是否有即将到期的,然后进行消息推送。

        数据报表:每天设置定时任务让系统自动生成数据报表进行数据统计。

        状态同步:比如一个外卖平台或者物流平台,用户确认到货后,但是店员这边还没确定订单完成,订单状态一直为派送中,可设置定时任务每天凌晨去检查更新。

        日志清除:可以每隔一个星期或者几天去检查系统日志文件的大小,如果过大进行清理或者持久化。

定时任务的实现方式

1、Java原生的Timer类

2、线程池技术中ScheduleExecutorService

3、Spring Task,通过@schedule实现

4、Quartz

5、Elastic-job

6、Xxl-job

为什么要使用Xxl-job?有什么优点?缺点?

①Timer类功能简单、仅支持简单的定时任务,缺乏任务管理和监控功能,不可靠。

②ScheduleExecutorService是通过Executors创建出来的,阿里开发手册中规定不能使用这种方式创建线程池,因为其最大线程数为无限大,使用不当会导致OOM。

③SpringTask也是功能有限,缺乏任务管理和监控功能,并且不适合分布式架构,只适合单体。

④Quarzt的话实现比较复杂,Elastic-job是基于uarzt重构的,还引入了Zookeeper,实现也比较复杂

xxl-job的优点:

①可视化管理界面,提供直观、易用的可视化管理界面,方便我们统一进行管理和监控任务。

②支持分布式任务调度。使用分布式环境,也支持集群分布式架构,可保证高可用性和可靠性。

③任务日志的记录和查看。

④简单且动态,学习简单,上手即用,可动态调整任务状态、启动/停止。

⑤任务监控和报警,提供了丰富的任务监控功能,可以实时查看任务的执行状态、执行日志和执行结果。同时,它还支持任务执行失败时的报警通知,可以通过邮件、短信等方式及时通知相关人员进行处理。

⑥社区活跃。

xxl-job缺点:

①xxl-job通常会将任务信息、执行历史记录等数据存储在数据库中。当任务数量众多且任务执行频繁时,数据库的读写压力会增大。如果数据库的性能不够优化,可能会导致数据存储和查询的延迟。

②并且调度中心是通过DB锁来保证执行任务的唯一性,如果任务较多,数据库锁竞争激烈会导致性能下降

Springboot整合Xxl-job 

部署运行环境: jdk8 + centos7 + docker  + docker-mysql(自行拉取镜像创建容器,比较简单)

1、下载源码

    xxl-job-2.4.1源码下载地址

2、配置admin,构建镜像部署在Centos上

配置数据库,在Mysql中执行项目中自带的sql脚本:

修改xxl-job-admin中配置文件application.properties:

测试启动:

更改Dockerfile文件:

打包:

 将Dockerfile和target文件夹全都上传到CentOS上:

构建镜像,并启动 xxl-admin调度中心:

docker build -t xxl-job-admin:1.0 .

docker run -it -d --name xxl-job-admin -p 8080:8080 admin:1.0

访问CentOS地址:8080/xxl-job-admin:

 

3、执行器服务

编写application.porperties文件:

# web port
server.port=8081
# no web
#spring.main.web-environment=false

# log config
logging.config=classpath:logback.xml

### xxl-job admin address list, such as "http://address" or "http://address01,http://address02"
xxl.job.admin.addresses=http://192.168.136.132:8080/xxl-job-admin

### xxl-job, access token
xxl.job.accessToken=default_token

### xxl-job executor appname
xxl.job.executor.appname=xxl-job-executor-test
### xxl-job executor registry-address: default use address to registry , otherwise use ip:port if address is null
xxl.job.executor.address=
### xxl-job executor server-info
xxl.job.executor.ip=
xxl.job.executor.port=0
### xxl-job executor log-path
xxl.job.executor.logpath=/data/applogs/xxl-job/jobhandler
### xxl-job executor log-retention-days
xxl.job.executor.logretentiondays=30

编写XxlJobConfig文件:

@Configuration
public class XxlJobConfig {
    private Logger logger = LoggerFactory.getLogger(XxlJobConfig.class);

    @Value("${xxl.job.admin.addresses}")
    private String adminAddresses;

    @Value("${xxl.job.accessToken}")
    private String accessToken;

    @Value("${xxl.job.executor.appname}")
    private String appname;

    @Value("${xxl.job.executor.address}")
    private String address;

    @Value("${xxl.job.executor.ip}")
    private String ip;

    @Value("${xxl.job.executor.port}")
    private int port;

    @Value("${xxl.job.executor.logpath}")
    private String logPath;

    @Value("${xxl.job.executor.logretentiondays}")
    private int logRetentionDays;


    @Bean
    public XxlJobSpringExecutor xxlJobExecutor() {
        logger.info(">>>>>>>>>>> xxl-job config init.");
        XxlJobSpringExecutor xxlJobSpringExecutor = new XxlJobSpringExecutor();
        xxlJobSpringExecutor.setAdminAddresses(adminAddresses);
        xxlJobSpringExecutor.setAppname(appname);
        xxlJobSpringExecutor.setAddress(address);
        xxlJobSpringExecutor.setIp(ip);
        xxlJobSpringExecutor.setPort(port);
        xxlJobSpringExecutor.setAccessToken(accessToken);
        xxlJobSpringExecutor.setLogPath(logPath);
        xxlJobSpringExecutor.setLogRetentionDays(logRetentionDays);

        return xxlJobSpringExecutor;
    }
}

编写执行器任务代码:

@Component
public class SampleXxlJob {

    @XxlJob("MyJobHandler")
    public void demoJobHandler() throws Exception {
        System.out.println(new Date());
    }
}

 先在本地启动项目:

4、admin调度中心创建执行器

如果是在本地跑执行器程序/业务程序,机器地址必须填电脑的IP地址,否则出现下面的错误:

正确执行:

5、基于OpenJDK镜像部署Java应用程序

我们项目开发完成之后如果要部署在CentOS中,我们使用基于OpenJDK镜像方式运行:

docker pull openjdk:8

 将我们的应用程序代码打包,上传到CentOS指定目录下:

 通过jdk镜像运行jar包,启动应用程序:

docker run --name job-demo -p 8081:8081 -p 9999:9999 
-d -v /home/zzl/server/jars/xxl-job:/jar openjdk:8 
java -jar /jar/xxl-job-executor-sample-springboot-2.4.1.jar 

此时需要将admin调度中心的执行器的地址修改:

启动定时任务:

查看输出日志,定时任务成功启动:

docker logs -f --tail 20 job-demo 

创建一个新SpringBoot工程将Xxl-job整合进去

只需要引入核心依赖: 

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

<dependency>
    <groupId>com.xuxueli</groupId>
    <artifactId>xxl-job-core</artifactId>
    <version>2.4.1</version>
</dependency>

application.properties配置文件: 

# web port
server.port=8088
# no web
#spring.main.web-environment=false

# log config
logging.config=classpath:logback.xml


### xxl-job admin address list, such as "http://address" or "http://address01,http://address02"
xxl.job.admin.addresses=http://192.168.136.132:8080/xxl-job-admin

### xxl-job, access token
xxl.job.accessToken=default_token

### xxl-job executor appname
xxl.job.executor.appname=xxl-job-executor-test
### xxl-job executor registry-address: default use address to registry , otherwise use ip:port if address is null
xxl.job.executor.address=
### xxl-job executor server-info
xxl.job.executor.ip=
xxl.job.executor.port=0
### xxl-job executor log-path
xxl.job.executor.logpath=/data/applogs/xxl-job/jobhandler
### xxl-job executor log-retention-days
xxl.job.executor.logretentiondays=30

xxl-job配置类: 

package com.example.realdemo.demos.web.config;

import com.xxl.job.core.executor.impl.XxlJobSpringExecutor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class XxlJobConfig {
    private Logger logger = LoggerFactory.getLogger(XxlJobConfig.class);

    @Value("${xxl.job.admin.addresses}")
    private String adminAddresses;

    @Value("${xxl.job.accessToken}")
    private String accessToken;

    @Value("${xxl.job.executor.appname}")
    private String appname;

    @Value("${xxl.job.executor.address}")
    private String address;

    @Value("${xxl.job.executor.ip}")
    private String ip;

    @Value("${xxl.job.executor.port}")
    private int port;

    @Value("${xxl.job.executor.logpath}")
    private String logPath;

    @Value("${xxl.job.executor.logretentiondays}")
    private int logRetentionDays;


    @Bean
    public XxlJobSpringExecutor xxlJobExecutor() {
        logger.info(">>>>>>>>>>> xxl-job config init.");
        XxlJobSpringExecutor xxlJobSpringExecutor = new XxlJobSpringExecutor();
        xxlJobSpringExecutor.setAdminAddresses(adminAddresses);
        xxlJobSpringExecutor.setAppname(appname);
        xxlJobSpringExecutor.setAddress(address);
        xxlJobSpringExecutor.setIp(ip);
        xxlJobSpringExecutor.setPort(port);
        xxlJobSpringExecutor.setAccessToken(accessToken);
        xxlJobSpringExecutor.setLogPath(logPath);
        xxlJobSpringExecutor.setLogRetentionDays(logRetentionDays);

        return xxlJobSpringExecutor;
    }
}

controller层:

@RestController
public class BasicController {

    @Autowired
    private BasicService basicService;

    @RequestMapping("/createTask")
    public String createTask() {
        basicService.createTask();
        return "成功创建任务!";
    }
}

service层:

@Service
public class BasicService {

    @XxlJob("createTaskHandler")
    public void createTask() {
        System.out.println("这是我新创建的项目,现在是北京时间:" + new Date());
    }
}

启动项目,去调度中心创建执行器:

创建任务:

启动定时任务,成功运行!!!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值