官方文档

因为我们项目需要用到定时任务,而且必须要实现分布式或者可以做到多种方式的执行,一方面是为了业务需要,同时也是为了执行的安全性,于是就默默的用了轻量级的xxl-job。并且它是支持异构语言(多语言),我的一个python项目里面也用到了定时任务,所以可以一并执行。多余的不做过多介绍,直接看大佬的开源项目文档就行,地址为:https://www.xuxueli.com/xxl-job/

部署过程

在部署这个组件之前需要了解下它源码的结构

  1. xxl-job-admin:调度中心(会依赖于xxl-job-core)
  2. xxl-job-core:公共依赖
  3. xxl-job-executor-samples:执行器Sample示例(就是我们项目,会依赖于xxl-job-core)

    xxl-job-core

    这个是admin任务管理后台和执行器都需要的依赖,在部署之前需要先执行下它的sql脚本,位置如下图,我这里是把它打成了一个starter组件,供admin和执行器app调用。
    image.png

    xxl-job-admin

    这个admin后台主要作用:统一管理任务调度平台上调度任务,负责触发调度执行,并且提供任务管理平台。
    对于admin的部署,我这里是下载源码然后编译打包成镜像部署的,当然在打包编译前,你需要配置一下它的application.yaml文件的配置,比如配置数据库连接、邮件提醒等。

    yaml

    1. ### 调度中心JDBC链接:链接地址请保持和 2.1章节 所创建的调度数据库的地址一致
    2. spring.datasource.url=jdbc:mysql://127.0.0.1:3306/xxl_job?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&serverTimezone=Asia/Shanghai
    3. spring.datasource.username=root
    4. spring.datasource.password=root_pwd
    5. spring.datasource.driver-class-name=com.mysql.jdbc.Driver
    6. ### 报警邮箱
    7. spring.mail.host=smtp.qq.com
    8. spring.mail.port=25
    9. spring.mail.username=xxx@qq.com
    10. spring.mail.password=xxx
    11. spring.mail.properties.mail.smtp.auth=true
    12. spring.mail.properties.mail.smtp.starttls.enable=true
    13. spring.mail.properties.mail.smtp.starttls.required=true
    14. spring.mail.properties.mail.smtp.socketFactory.class=javax.net.ssl.SSLSocketFactory
    15. ### 调度中心通讯TOKEN [选填]:非空时启用;
    16. xxl.job.accessToken=
    17. ### 调度中心国际化配置 [必填]: 默认为 "zh_CN"/中文简体, 可选范围为 "zh_CN"/中文简体, "zh_TC"/中文繁体 and "en"/英文;
    18. xxl.job.i18n=zh_CN
    19. ## 调度线程池最大线程配置【必填】
    20. xxl.job.triggerpool.fast.max=200
    21. xxl.job.triggerpool.slow.max=100
    22. ### 调度中心日志表数据保存天数 [必填]:过期日志自动清理;限制大于等于7时生效,否则, 如-1,关闭自动清理功能;
    23. xxl.job.logretentiondays=30

    dockerfile

    ```dockerfile FROM openjdk:8u201-jdk-alpine3.9 MAINTAINER xuxueli

ENV PARAMS=””

ENV TZ=PRC

RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone

RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime

jenkins流水线部署只能在工作空间部署,所以加了一层路径

ADD simone-support/xxl-job-admin/target/xxl-job-admin-*.jar /app.jar

ENTRYPOINT [“sh”,”-c”,”java -jar $JAVA_OPTS /app.jar $PARAMS”]

  1. 部署完成后,调度中心访问地址:[http://ip:port/xxl-job-admin](http://localhost:8080/xxl-job-admin) (该地址执行器将会使用到,作为回调地址)<br />默认登录账号 “admin/123456”
  2. <a name="GKzz6"></a>
  3. ### 启用定时任务
  4. 如果你配置完了定时任务后,需要上线的话需要点击启用喔,否则它是不会自动执行你的任务的哦<br />![image.png](https://cdn.nlark.com/yuque/0/2021/png/771792/1637999939345-2eb788c0-acf2-45a3-ba49-eb98d77e9d85.png#clientId=u1cdf8a11-5adb-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=435&id=u1533b362&margin=%5Bobject%20Object%5D&name=image.png&originHeight=435&originWidth=1655&originalType=binary&ratio=1&rotation=0&showTitle=false&size=42389&status=done&style=none&taskId=u1bff19aa-44ae-472d-8f47-25c1182e567&title=&width=1655)
  5. <a name="cE34N"></a>
  6. ## xxl-job-executor-samples(执行器)
  7. <a name="szUSw"></a>
  8. ### 执行器配置
  9. ```yaml
  10. xxl:
  11. job:
  12. # 执行器通讯TOKEN [选填]:非空时启用
  13. accessToken: xxx
  14. executor:
  15. # 执行器AppName [选填]:执行器心跳注册分组依据;为空则关闭自动注册
  16. appname: xxl-job-executor-simoneAdmin
  17. # 执行器注册 [选填]:优先使用该配置作为注册地址,为空时使用内嵌服务 ”IP:PORT“ 作为注册地址。从而更灵活的支持容器类型执行器动态IP和动态映射端口问题。
  18. address:
  19. # 执行器IP [选填]:默认为空表示自动获取IP,多网卡时可手动设置指定IP,该IP不会绑定Host仅作为通讯实用;地址信息用于 "执行器注册" 和 "调度中心请求并触发任务";
  20. ip:
  21. # 执行器端口号 [选填]:小于等于0则自动获取;默认端口为9999,单机部署多个xxl-job registry执行器时,注意要配置不同执行器端口;
  22. port: 10009
  23. # 执行器运行日志文件存储磁盘路径 [选填] :需要对该路径拥有读写权限;为空则使用默认路径;
  24. logpath: /data/applogs/xxl-job/simoneAdmin
  25. # 执行器日志文件保存天数 [选填] : 过期日志自动清理, 限制值大于等于3时生效; 否则, 如-1, 关闭自动清理功能;
  26. logretentiondays: 30

初始化配置文件

  1. package com.jimushow.simone.app.config;
  2. import com.xxl.job.core.executor.impl.XxlJobSpringExecutor;
  3. import org.slf4j.Logger;
  4. import org.slf4j.LoggerFactory;
  5. import org.springframework.beans.factory.annotation.Value;
  6. import org.springframework.context.annotation.Bean;
  7. import org.springframework.context.annotation.Configuration;
  8. @Configuration
  9. public class XxlJobConfig {
  10. private Logger logger = LoggerFactory.getLogger(XxlJobConfig.class);
  11. @Value("${xxl.job.admin.addresses}")
  12. private String adminAddresses;
  13. @Value("${xxl.job.accessToken}")
  14. private String accessToken;
  15. @Value("${xxl.job.executor.appname}")
  16. private String appname;
  17. @Value("${xxl.job.executor.address}")
  18. private String address;
  19. @Value("${xxl.job.executor.ip}")
  20. private String ip;
  21. @Value("${xxl.job.executor.port}")
  22. private int port;
  23. @Value("${xxl.job.executor.logpath}")
  24. private String logPath;
  25. @Value("${xxl.job.executor.logretentiondays}")
  26. private int logRetentionDays;
  27. @Bean
  28. public XxlJobSpringExecutor xxlJobExecutor() {
  29. logger.info(">>>>>>>>>>> xxl-job config init.");
  30. XxlJobSpringExecutor xxlJobSpringExecutor = new XxlJobSpringExecutor();
  31. xxlJobSpringExecutor.setAdminAddresses(adminAddresses);
  32. xxlJobSpringExecutor.setAppname(appname);
  33. xxlJobSpringExecutor.setAddress(address);
  34. xxlJobSpringExecutor.setIp(ip);
  35. xxlJobSpringExecutor.setPort(port);
  36. xxlJobSpringExecutor.setAccessToken(accessToken);
  37. xxlJobSpringExecutor.setLogPath(logPath);
  38. xxlJobSpringExecutor.setLogRetentionDays(logRetentionDays);
  39. return xxlJobSpringExecutor;
  40. }
  41. }

admin端添加执行器

虽然我们在yaml配置文件中配置了执行器的一些参数,但是并不会自动新增在执行器列表页面,需要我们自身手动去新增
image.png

执行器示例任务

  1. import com.xxl.job.core.context.XxlJobHelper;
  2. import com.xxl.job.core.handler.annotation.XxlJob;
  3. import org.springframework.stereotype.Component;
  4. import java.util.concurrent.TimeUnit;
  5. @Component
  6. public class ScheduleDemo {
  7. /**
  8. * 前提:本项目就是一个执行器,必须初始化 XxlJobConfig 相应的配置
  9. * 1、任务开发:在Spring Bean实例中,开发Job方法;
  10. * 2、注解配置:为Job方法添加注解 "@XxlJob(value="自定义jobhandler名称", init = "JobHandler初始化方法", destroy = "JobHandler销毁方法")",注解value值对应的是调度中心新建任务的JobHandler属性的值。
  11. * 3、执行日志:需要通过 "XxlJobHelper.log" 打印执行日志;
  12. * 4、任务结果:默认任务结果为 "成功" 状态,不需要主动设置;如有诉求,比如设置任务结果为失败,可以通过 "XxlJobHelper.handleFail/handleSuccess" 自主设置任务结果;
  13. */
  14. @XxlJob(value = "scheduleAdminDemo")
  15. public void scheduleAdminDemo() throws Exception {
  16. XxlJobHelper.log(XxlJobHelper.getJobParam());
  17. XxlJobHelper.log("---------欢迎来到90年代");
  18. for (int i = 0; i < 3; i++) {
  19. XxlJobHelper.log("欢迎来到90年代:" + i);
  20. TimeUnit.SECONDS.sleep(2);
  21. }
  22. }
  23. }

于此同时需要我们在任务调度中心admin后台中心同时配置该任务,并且jibHandler与我们任务注解的value保持一致。同时配置这个定时任务的corn表达式和路由策略。而且还支持配置任务参数,这个对我们方法需要额外的参数很有用,在实际开发中应用也有用到。image.png

路由策略说明如下
  1. - 路由策略:当执行器集群部署时,提供丰富的路由策略,包括;
  2. FIRST(第一个):固定选择第一个机器;
  3. LAST(最后一个):固定选择最后一个机器;
  4. ROUND(轮询):;
  5. RANDOM(随机):随机选择在线的机器;
  6. CONSISTENT_HASH(一致性HASH):每个任务按照Hash算法固定选择某一台机器,且所有任务均匀散列在不同机器上。
  7. LEAST_FREQUENTLY_USED(最不经常使用):使用频率最低的机器优先被选举;
  8. LEAST_RECENTLY_USED(最近最久未使用):最久未使用的机器优先被选举;
  9. FAILOVER(故障转移):按照顺序依次进行心跳检测,第一个心跳检测成功的机器选定为目标执行器并发起调度;
  10. BUSYOVER(忙碌转移):按照顺序依次进行空闲检测,第一个空闲检测成功的机器选定为目标执行器并发起调度;
  11. SHARDING_BROADCAST(分片广播):广播触发对应集群中所有机器执行一次任务,同时系统自动传递分片参数;可根据分片参数开发分片任务;

在admin后台点击手动执行便会触发一次,触发结果如下:

执行器控制台输出
  1. 2021-11-27 15:06:53.780 INFO 13704 --- [Pool-1156631929] c.xxl.job.core.executor.XxlJobExecutor : >>>>>>>>>>> xxl-job regist JobThread success, jobId:2, handler:com.xxl.job.core.handler.impl.MethodJobHandler@42017162[class com.jimushow.simone.app.schedule.ScheduleDemo#scheduleDemo]
  2. 2021-11-27 15:06:53.785 INFO 13704 --- [ Thread-92] c.j.simone.app.schedule.ScheduleDemo : 开始执行定时任务
  3. 2021-11-37 15:06:53.785 INFO 13704 --- [ Thread-92] c.j.simone.app.schedule.ScheduleDemo : 结束执行定时任务
  4. 2021-11-27 15:08:37.142 INFO 13704 --- [ Thread-92] com.xxl.job.core.thread.JobThread : >>>>>>>>>>> xxl-job JobThread stoped, hashCode:Thread[Thread-92,10,main]

xxl-job页面admin执行日志输出

调度机器就是我们admin的ip地址,我这里是通过k8s部署,所以ip为容器内部ip:10.244.0.95,如果你是集群部署则注册的地址肯定是多个,如果你是需要多个机器只执行一次路由策略记得选择单机执行,我这里选择的是随机。如果是轮询的话则也是每次执行一台机器,然后保证逐个轮询到。
image.png
image.png

  1. 2021-12-01 10:44:14 [com.xxl.job.core.thread.JobThread#run]-[130]-[Thread-56]
  2. ----------- xxl-job job execute start -----------
  3. ----------- Param:{
  4. "from": "admin",
  5. "to": "20010018",
  6. "type": 1
  7. }
  8. 2021-12-01 10:44:14 [com.jimushow.simone.admin.schedule.ScheduleXxlJob#scheduleAdminDemo]-[58]-[Thread-56] {
  9. "from": "admin",
  10. "to": "20010018",
  11. "type": 1
  12. }
  13. 2021-12-01 10:44:14 [com.jimushow.simone.admin.schedule.ScheduleXxlJob#scheduleAdminDemo]-[59]-[Thread-56] ---------欢迎来到90年代
  14. 2021-12-01 10:44:14 [com.jimushow.simone.admin.schedule.ScheduleXxlJob#scheduleAdminDemo]-[61]-[Thread-56] 欢迎来到90年代:0
  15. 2021-12-01 10:44:16 [com.jimushow.simone.admin.schedule.ScheduleXxlJob#scheduleAdminDemo]-[61]-[Thread-56] 欢迎来到90年代:1
  16. 2021-12-01 10:44:18 [com.jimushow.simone.admin.schedule.ScheduleXxlJob#scheduleAdminDemo]-[61]-[Thread-56] 欢迎来到90年代:2
  17. 2021-12-01 10:44:20 [com.xxl.job.core.thread.JobThread#run]-[176]-[Thread-56]
  18. ----------- xxl-job job execute end(finish) -----------
  19. ----------- Result: handleCode=200, handleMsg = null
  20. 2021-12-01 10:44:20 [com.xxl.job.core.thread.TriggerCallbackThread#callbackLog]-[197]-[xxl-job, executor TriggerCallbackThread]
  21. ----------- xxl-job job callback finish.

如果你执行失败,控制台会显示rpc 各种错误,很有可能就是你注册的自动注册的地址网络存在问题,或者你手动注册的地址书写错误,因为我执行器配置的端口是9999,所以我这里的地址为:http://192.168.1.105:9999/ 如果你的执行器地址存在多个(集群服务)则用,分隔即可
image.png