思维导图
文章已收录 Github 精选,欢送 Star:https://github.com/yehongzhi/learningSummary
一、概述
在平时的业务场景中,常常有一些场景须要应用定时工作,比方:
- 工夫驱动的场景:某个工夫点发送优惠券,发送短信等等。
- 批量解决数据:批量统计上个月的账单,统计上个月销售数据等等。
- 固定频率的场景:每隔 5 分钟须要执行一次。
所以定时工作在平时开发中并不少见,而且对于当初疾速生产的时代,每天都须要发送各种推送,音讯都须要依赖定时工作去实现,利用十分宽泛。
二、为什么须要任务调度平台
在 Java 中,传统的定时工作实现计划,比方 Timer,Quartz 等都或多或少存在一些问题:
- 不反对集群、不反对统计、没有治理平台、没有失败报警、没有监控等等
而且在当初分布式的架构中,有一些场景须要分布式任务调度:
- 同一个服务多个实例的工作存在互斥时,须要对立的调度。
- 任务调度须要反对高可用、监控、故障告警。
- 须要对立治理和追踪各个服务节点任务调度的后果,须要记录保留工作属性信息等。
显然传统的定时工作曾经不满足当初的分布式架构,所以须要一个分布式任务调度平台,目前比拟支流的是 elasticjob 和 xxl-job。
elasticjob 由当当网开源,目前 github 有 6.5k 的 Star,应用的公司在官网注销有 76 家。
跟 xxl-job 不同的是,elasticjob 是采纳 zookeeper 实现分布式协调,实现工作高可用以及分片。
三、为什么抉择 XXL-JOB
实际上更多公司抉择 xxl-job,目前xxl-job 的 github 上有 15.7k 个 star,注销公司有 348 个。毫无疑问 elasticjob 和 xxl-job 都是十分优良的技术框架,接下来咱们进一步比照探讨,摸索一下为什么更多公司会抉择 xxl-job。
首先先介绍一下 xxl-job,这是出自公众点评许雪里 (xxl 就是作者名字的拼音首字母) 的开源我的项目,官网上介绍这是一个轻量级分布式任务调度框架,其外围设计指标是开发迅速、学习简略、轻量级、易扩大。跟 elasticjob 不同,xxl-job 环境依赖于 mysql,不必 ZooKeeper,这也是最大的不同。
elasticjob 的初衷是为了面对高并发简单的业务,即便是在业务量大,服务器多的时候也能做好任务调度,尽可能的利用服务器的资源。应用 ZooKeeper 使其具备高可用、一致性的,而且还具备良好的扩展性。官网上写elasticjob 是无中心化的,通过 ZooKeeper 的选举机制选举出主服务器,如果主服务器挂了,会从新选举新的主服务器。因而 elasticjob 具备良好的扩展性和可用性,然而应用和运维有肯定的简单。
xxl-job 则相同,是通过一个核心式的调度平台,调度多个执行器执行工作,调度核心通过 DB 锁保障集群散布式调度的一致性,这样扩大执行器会增大 DB 的压力,然而如果实际上这里数据库只是负责工作的调度执行。然而如果没有大量的执行器的话和工作的状况,是不会造成数据库压力的。实际上大部分公司工作数,执行器并不多(尽管面试常常会问一些高并发的问题)。
相对来说,xxl-job 核心式的调度平台 轻量级,开箱即用,操作繁难,上手快,与 SpringBoot 有十分好的集成 ,而且监控界面就集成在调度核心,界面又简洁,对于 企业保护起来老本不高,还有失败的邮件告警 等等。这就使很多企业抉择 xxl-job 做调度平台。
四、装置
4.1 拉取源码
搭建 xxl-job 很简略,有 docker 拉取镜像部署和源码编译两种形式,docker 部署的形式比较简单,我就讲源码编译的形式。首先到 github 拉取 xxl-job 源码到本地。
4.2 导入 IDEA
拉取源码下来后,能够看到我的项目构造,如下:
导入到 IDEA,配置一下 Maven,下载相干的 jar 包,稍等一下后,就能够看到这样的我的项目:
4.3 初始化数据库
后面讲过 xxl-job 须要依赖 mysql,所以须要初始化数据库,在 xxl-jobdocdb 门路下找到 tables_xxl_job.sql 文件。在 mysql 上运行 sql 文件。
4.4 配置文件
接着就改一下配置文件,在 admin 我的项目下找到 application.properties 文件。
_### 调度核心 JDBC 链接_
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/xxl_job?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&serverTimezone=Asia/Shanghai
spring.datasource.username=root
spring.datasource.password=
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
_### 报警邮箱_
spring.mail.host=smtp.qq.com
spring.mail.port=25
spring.mail.username=xxx@qq.com
spring.mail.password=xxx
spring.mail.properties.mail.smtp.auth=true
spring.mail.properties.mail.smtp.starttls.enable=true
spring.mail.properties.mail.smtp.starttls.required=true
spring.mail.properties.mail.smtp.socketFactory.class=javax.net.ssl.SSLSocketFactory
_### 调度核心通信 TOKEN [选填]:非空时启用;_
xxl.job.accessToken=
_### 调度核心国际化配置 [必填]:默认为 "zh_CN"/ 中文简体, 可选范畴为 "zh_CN"/ 中文简体, "zh_TC"/ 中文繁体 and "en"/ 英文;_
xxl.job.i18n=zh_CN
_## 调度线程池最大线程配置【必填】_
xxl.job.triggerpool.fast.max=200
xxl.job.triggerpool.slow.max=100
_### 调度核心日志表数据保留天数 [必填]:过期日志主动清理;限度大于等于 7 时失效,否则, 如 -1,敞开主动清理性能;_
xxl.job.logretentiondays=10
4.5 编译运行
简略一点间接跑 admin 我的项目的 main 办法启动也行。
如果部署在服务器呢,那咱们须要打包成 jar 包,在 IDEA 利用 Maven 插件打包。
而后在 xxl-jobxxl-job-admintarget 门路下,找到 jar 包。
而后就失去 jar 包了,应用 java -jar 命令就能够启动了。
到这里就曾经实现了!关上浏览器,输出 http://localhost:8080/xxl-job-admin 进入治理页面。默认账号 / 明码:admin/123456。
五、永远的 HelloWord
部署了调度核心之后,须要往调度核心注册执行器,增加调度工作。接下来就参考 xxl-job 写一个简略的例子。
首先创立一个 SpringBoot 我的项目,名字叫 ”xxljob-demo”,增加依赖。
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>_<!-- 官网的 demo 是 2.2.1,地方 maven 仓库还没有,所以就用 2.2.0 -->_
<groupId>com.xuxueli</groupId>
<artifactId>xxl-job-core</artifactId>
<version>2.2.0</version>
</dependency>
</dependencies>
接着批改 application.properties。
_# web port_
server.port=8081
_# log config_
logging.config=classpath:logback.xml
spring.application.name=xxljob-demo
_### 调度核心部署跟地址 [选填]:如调度核心集群部署存在多个地址则用逗号分隔。执行器将会应用该地址进行 "执行器心跳注册" 和 "工作后果回调";为空则敞开主动注册;_
xxl.job.admin.addresses=http://127.0.0.1:8080/xxl-job-admin
_### 执行器通信 TOKEN [选填]:非空时启用;_
xxl.job.accessToken=
_### 执行器 AppName [选填]:执行器心跳注册分组根据;为空则敞开主动注册_
xxl.job.executor.appname=xxl-job-demo
_### 执行器注册 [选填]:优先应用该配置作为注册地址,为空时应用内嵌服务”IP:PORT“作为注册地址。从而更灵便的反对容器类型执行器动静 IP 和动静映射端口问题。_
xxl.job.executor.address=
_### 执行器 IP [选填]:默认为空示意主动获取 IP,多网卡时可手动设置指定 IP,该 IP 不会绑定 Host 仅作为通信实用;地址信息用于 "执行器注册" 和 "调度核心申请并触发工作";_
xxl.job.executor.ip=
_### 执行器端口号 [选填]:小于等于 0 则主动获取;默认端口为 9999,单机部署多个执行器时,留神要配置不同执行器端口;_
xxl.job.executor.port=9999
_### 执行器运行日志文件存储磁盘门路 [选填]:须要对该门路领有读写权限;为空则应用默认门路;_
xxl.job.executor.logpath=/data/applogs/xxl-job/jobhandler
_### 执行器日志文件保留天数 [选填]:过期日志主动清理, 限度值大于等于 3 时失效; 否则, 如 -1, 敞开主动清理性能;_
xxl.job.executor.logretentiondays=10
接着写一个配置类 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;
}
}
接着编写一个工作类 XxlJobDemoHandler,应用 Bean 模式。
@Component
public class XxlJobDemoHandler {
_/**
* Bean 模式,一个办法为一个工作
* 1、在 Spring Bean 实例中,开发 Job 办法,形式格局要求为 "public ReturnT<String> execute(String param)"
* 2、为 Job 办法增加注解 "@XxlJob(value=" 自定义 jobhandler 名称 ", init ="JobHandler 初始化办法 ", destroy ="JobHandler 销毁办法 ")",注解 value 值对应的是调度核心新建工作的 JobHandler 属性的值。* 3、执行日志:须要通过 "XxlJobLogger.log" 打印执行日志;*/_
@XxlJob("demoJobHandler")
public ReturnT<String> demoJobHandler(String param) throws Exception {XxlJobLogger.log("java, Hello World~~~");
XxlJobLogger.log("param:" + param);
return ReturnT.SUCCESS;
}
}
在 resources 目录下,增加 logback.xml 文件。
<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="false" scan="true" scanPeriod="1 seconds">
<contextName>logback</contextName>
<property name="log.path" value="/data/applogs/xxl-job/xxl-job-executor-sample-springboot.log"/>
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{HH:mm:ss.SSS} %contextName [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<appender name="file" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.path}</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${log.path}.%d{yyyy-MM-dd}.zip</fileNamePattern>
</rollingPolicy>
<encoder>
<pattern>%date %level [%thread] %logger{36} [%file : %line] %msg%n
</pattern>
</encoder>
</appender>
<root level="info">
<appender-ref ref="console"/>
<appender-ref ref="file"/>
</root>
</configuration>
写完之后启动服务,而后能够关上治理界面,找到执行器治理,增加执行器。
接着到工作治理,增加工作。
最初咱们能够到工作治理去测试一下,运行 demoJobHandler。
点击保留后,会立刻执行。点击查看日志,能够看到工作执行的历史日志记录。
关上刚刚执行的执行日志,咱们能够看到,运行胜利。
这就是简略的 Demo 演示,非常简单,上手也快。
六、谈谈架构设计
上面简略地说一下 xxl-job 的架构,咱们先看官网提供的一张架构图来剖析。
从架构图能够看出,别离有调度核心和执行器两大组成部分
- 调度核心。负责 治理调度信息,依照调度配置收回调度申请,本身不承当业务代码。反对可视化界面,能够在调度核心对工作进行新增,更新,删除,会实时失效。反对监控调度后果,查看执行日志,查看调度工作统计报表,工作失败告警等等。
- 执行器。负责接管调度申请,执行调度工作的业务逻辑。执行器启动后须要注册到调度核心。接管调度核心的收回的执行申请,终止申请,日志申请等等。
接下来咱们看一下 xxl-job 的工作原理。
- 工作执行器依据配置的调度核心的地址,主动注册到调度核心。
- 达到工作触发条件,调度核心下发工作。
- 执行器基于线程池执行工作,并把执行后果放入内存队列中、把执行日志写入日志文件中。
- 执行器的回调线程生产内存队列中的执行后果,被动上报给调度核心。
- 当用户在调度核心查看工作日志,调度核心申请工作执行器,工作执行器读取工作日志文件并返回日志详情。
絮叨
看完以上的内容,根本算入门了。实际上,xxl-job 还有很多性能,要深刻学习,还须要到官网去钻研摸索。最好就是本人在本地搭建一个 xxl-job 来玩玩,入手实际是学得最快的学习形式。
原文链接
本文为阿里云原创内容,未经容许不得转载。