定时任务服务搭建
一、框架选型
基于以下比较,xxl-job由于轻量化、简单、功能强大、安全等特性,考虑作为微服务项目的定时任务框架支持。
分布式环境下定时任务选型考虑以下因素
- 主要因素:高可用、负载均衡、路由策略。
- 其他因素:调度模块与任务模块解耦、可视化的管理界面、失败重试机制、超时机制、统计、报警...... 。
当前市面使用较多的定时任务框架有:quartz、elastic-job、xxl-job。
1. quartz
- 底层以“抢占式”获取DB锁并由抢占成功节点负责运行任务,会导致节点负载悬殊非常大,
- 调度逻辑与任务逻辑耦合在同一个项目中
- 没有路由策略,任务能否执行依赖于服务是否获得DB锁
- 调用API的的方式操作任务,不人性化,任务的动态管理需要自行开发
2. elastic-job
- 需要结合zookeeper实现作业注册,提高复杂度
3. xxl-job
- 调度模块与任务模块解耦,两者都可进行高可用的集群部署
- 弹性扩容
- 相同执行器的任务通过线程池异步执行,不同执行器的任务并行执行
- ......
4. 详细对比
quartz | elastic-job | xxl-job | |
---|---|---|---|
高可用 | ✔ | ✔ | ✔ |
负载均衡 | ✖ | ✔ | ✔ |
路由策略 | ✖ | ✔ | ✔ |
低复杂度 | ✖ | ✖ | ✔ |
调度模块与任务模块解耦 | ✖ | ✔ | ✔ |
弹性扩容 | ✖ | ✔ | ✔ |
超时、重试 | ✔ | ✔ | ✔ |
报警 | ✖ | ✔ | |
一致性 | ✔ | ✔ | |
任务依赖 | ✖ | ✖ | ✔ |
自定义任务参数 | ✔ | ✔ | ✔ |
多线程 | ✔ | ✔ | ✔ |
统计 | ✖ | ✔ | |
日志 | ✔ | ✔ | ✔ |
容器化 | ✖ | ✔ | ✔ |
用户管理、权限控制 | ✖ | ✖ | ✔ |
持久化 | ✔ | ✔ | ✔ |
二、设计方案
调度中心
1. 容器化部署
调度中心使用docker容器进行集群部署,通过nginx对其做负载均衡访问
docker pull xuxueli/xxl-job-admin
docker run -p 8080:8080 -v /tmp:/data/applogs --name xxl-job-admin -d xuxueli/xxl-job-admin:{指定版本}
/**
* 如需自定义 mysql 等配置,可通过 "-e PARAMS" 指定,参数格式 PARAMS="--key=value --key2=value2" ;
* 配置项参考文件:/xxl-job/xxl-job-admin/src/main/resources/application.properties
* 如需自定义 JVM内存参数 等配置,可通过 "-e JAVA_OPTS" 指定,参数格式 JAVA_OPTS="-Xmx512m" ;
*/
docker run -e PARAMS="--spring.datasource.url=jdbc:mysql://127.0.0.1:3306/xxl_job?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&serverTimezone=Asia/Shanghai" -p 8080:8080 -v /tmp:/data/applogs --name xxl-job-admin -d xuxueli/xxl-job-admin:{指定版本}
2. 源码部署
下载源码:https://gitee.com/xuxueli0323/xxl-job.git
源码目录
xxl-job-admin:调度中心
xxl-job-core:公共依赖
xxl-job-executor-samples:执行器Sample示例(选择合适的版本执行器,可直接使用,也可以参考其并将现有项目改造成执行器)
:xxl-job-executor-sample-springboot:Springboot版本,通过Springboot管理执行器,推荐这种方式;
:xxl-job-executor-sample-frameless:无框架版本;
配置文件:
### web
server.port=8080
server.servlet.context-path=/xxl-job-admin
### actuator
management.server.servlet.context-path=/actuator
management.health.mail.enabled=false
### resources
spring.mvc.servlet.load-on-startup=0
spring.mvc.static-path-pattern=/static/**
spring.resources.static-locations=classpath:/static/
### freemarker
spring.freemarker.templateLoaderPath=classpath:/templates/
spring.freemarker.suffix=.ftl
spring.freemarker.charset=UTF-8
spring.freemarker.request-context-attribute=request
spring.freemarker.settings.number_format=0.##########
### mybatis
mybatis.mapper-locations=classpath:/mybatis-mapper/*Mapper.xml
#mybatis.type-aliases-package=com.xxl.job.admin.core.model
### xxl-job, datasource
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=root_pwd
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
### datasource-pool
spring.datasource.type=com.zaxxer.hikari.HikariDataSource
spring.datasource.hikari.minimum-idle=10
spring.datasource.hikari.maximum-pool-size=30
spring.datasource.hikari.auto-commit=true
spring.datasource.hikari.idle-timeout=30000
spring.datasource.hikari.pool-name=HikariCP
spring.datasource.hikari.max-lifetime=900000
spring.datasource.hikari.connection-timeout=10000
spring.datasource.hikari.connection-test-query=SELECT 1
spring.datasource.hikari.validation-timeout=1000
### xxl-job, email
spring.mail.host=smtp.qq.com
spring.mail.port=25
spring.mail.username=xxx@qq.com
spring.mail.from=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
### xxl-job, access token
xxl.job.accessToken=
### xxl-job, i18n (default is zh_CN, and you can choose "zh_CN", "zh_TC" and "en")
xxl.job.i18n=zh_CN
## xxl-job, triggerpool max size
xxl.job.triggerpool.fast.max=200
xxl.job.triggerpool.slow.max=100
### xxl-job, log retention days
xxl.job.logretentiondays=30
数据库工作准备好后,修改xxl-job-admin模块的配置文件后通过springboot的方式启动main方法即可
admin/123456登录
3. 运维平台部署
下载源码,数据库工作与配置文件修改完成后,对xxl-job-admin模块源码进行部分必要的修改,如接口地址、接口参数等,通过maven打为jar包并导入运维平台,至此调度中心后端接口工作完成,只需要前端调用即可
4. 集群部署
要求:DB配置保持一致;集群机器时钟保持一致(单机集群忽视);
建议:推荐通过nginx为调度中心集群做负载均衡,分配域名。调度中心访问、执行器回调配置、调用API服务等操作均通过该域名进行。
执行器
方案一
所有定时任务统一由任务服务执行,优点是定时任务逻辑与业务处理逻辑解耦,缺点是冗余度较高,该服务需要处理其他各个服务的业务数据
方案二
任务服务只负责执行器的配置工作,具体任务的实现由对应的服务负责,比如视频问诊提醒的定时任务逻辑交给问诊模块开发。
或许根本不需要新建一个任务服务,执行器的配置工作可以交给各个执行器完成
执行器部署
步骤一
确认pom文件中引入了 “xxl-job-core” 的maven依赖;
步骤二
修改配置文件
### 调度中心部署跟地址 [选填]:如调度中心集群部署存在多个地址则用逗号分隔。执行器将会使用该地址进行"执行器心跳注册"和"任务结果回调";为空则关闭自动注册;
xxl.job.admin.addresses=http://127.0.0.1:8080/xxl-job-admin
### 执行器通讯TOKEN [选填]:非空时启用;
xxl.job.accessToken=
### 执行器AppName [选填]:执行器心跳注册分组依据;为空则关闭自动注册
xxl.job.executor.appname=xxl-job-executor-sample
### 执行器注册 [选填]:优先使用该配置作为注册地址,为空时使用内嵌服务 ”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=30
步骤三
打包部署
集群部署
要求:
- 执行器回调地址(xxl.job.admin.addresses)需要保持一致;
- 执行器根据该配置进行执行器自动注册等操作。
- 同一个执行器集群内AppName(xxl.job.executor.appname)需要保持一致;
- 调度中心根据该配置动态发现不同集群的在线执行器列表。
三、xxl-job环境要求
- Maven3+
- Jdk1.8+
- Mysql5.7+
四、xxl-job版本选择
版本号:v2.3.0 Release
发布时间:2021-02-09
该版本为最新稳定版,修复了优先级较高的bug,如cron表达式的问题、执行器注册表的更新失败问题等。且新增了子任务触发策略、调度过期策略两个新特性。
五、xxl-job性能
一致性:
基于数据库的集群方案,数据库选用Mysql;集群分布式并发环境中进行定时任务调度时,会在各个节点会上报任务,存到数据库中,执行时会从数据库中取出触发器来执行,如果触发器的名称和执行时间相同,则只有一个节点去执行此任务。
高可用:
XXL-JOB中“调度模块”和“任务模块”完全解耦,调度模块进行任务调度时,将会解析不同的任务参数发起远程调用,调用各自的远程执行器服务。这种调用模型类似RPC调用,调度中心提供调用代理的功能,而执行器提供远程服务的功能。
多线程并行调度:
调度采用线程池方式实现,避免单线程因阻塞而引起任务调度延迟。
XXL-JOB调度模块默认采用并行机制,在多线程调度的情况下,调度模块被阻塞的几率很低,大大提高了调度系统的承载量。
XXL-JOB的不同任务之间并行调度、并行执行。
XXL-JOB的单个任务,针对多个执行器是并行运行的,针对单个执行器是串行执行的。同时支持任务终止。
全异步:
XXL-JOB系统中业务逻辑在远程执行器执行,触发流程全异步化设计。相比直接在调度中心内部执行业务逻辑,极大的降低了调度线程占用时间;
调度中心每次任务触发时仅发送一次调度请求,该调度请求首先推送“异步调度队列”,然后异步推送给远程执行器
执行器会将请求存入“异步执行队列”并且立即响应调度中心,异步运行。
调度中心轻量级:
XXL-JOB调度中心中每个JOB逻辑非常 “轻”,在全异步化的基础上,单个JOB一次运行平均耗时基本在10ms之内(基本为一次请求的网络开销);因此,可以保证使用有限的线程支撑大量的JOB并发运行
纸上得来终觉浅,绝知此事要躬行。
————————我是万万岁,我们下期再见————————