分布式任务调度方案
一、Quartz 的不足
Quartz 差不多20多年的历史,调度模型已经非常成熟了。但是在分布式场景下会有一些问题
- 调度逻辑和任务类耦合在同一项目中,随着调度任务数量增多,调度的整体性能会受到很大的影响。
- Quartz 集群的节点是抢占式,谁抢占到了数据库锁就由谁去执行,发挥不了机器的性能。
- Quartz 本身没有提供动态调度和管理界面,需要自己根据API进行开发。
- Quartz 日志记录、数据统计、监控都不完善。
xxl-job和Elastic-job 都是对Quartz 进行了封装,让其使用起来更简单,功能更强大。
二、xxl-job特性
性能提升:可以调度更多的任务
可靠性的提升:任务超时、失败、故障转移的处理
运维更加方便:有操作界面、用户权限、告警、可配置、自动生成报表等
三、xxl-job 应用
- 下载最新release源码
- 执行数据库脚本
- main方法或者jar包启动(调度中心、执行器)
xxl-job 提供了8张表:
其中admin(调度中心)和executor(执行器)的项目可以作为独立的工程,独立运行。executor也可以集成到业务项目中(业务实例)。调度器决定任务的调度,并且通过HTTP的方式调用执行器接口执行任务。
xxl-job调度原理:调度线程在一个while循环中不断的获取一定数量的即将触发的Trigger,拿到绑定的job,包装成工作线程执行。
所以需要先配置一个调度中心(生产中可以集群部署),然后再配置一个执行器(生产中同样集群部署)。
3.1、配置调度中心
配置:
数据库:spring.datasource
显示增加用户:
xxl.job.login.username=admin
xxl.job.login.password=123456
启动之后,访问:http://127.0.0.1:8080/xxl-job-admin
集群需要满足几个条件:
- 连接到同一个数据库
- 集群时钟保持一致
- 建议通过域名,用Nginx做负载均衡。
3.2、配置执行器(xxl-job-executor)
xxl.job.admin.addresses=http://127.0.0.1:8080/xxl-job-admin
xxl.job.executor.logpath=E:/dev_logs/xxl-job/jobhandler
如果单机启动多次:
server.port=${random.int[10000,19999]}
xxl.job.executor.port=${random.int[9000,10000]}
集群需要配置一致:
- xxl.job.admin.addresses=
- xxl.job.executor.appname=
3.3、添加任务
3.4、路由策略
一个任务选择哪个执行器去执行,Quartz只能抢占式随机负载。这个参数当执行器做集群的时候才有意义。xxl-job提供了丰富的路由策略
3.5、运行模式
在xxl-job中除了支持预先编写好的任务类,还可以直接输入代码或者脚本运行。运行任务类这种方式叫做BEAN模式,这个需要指定任务类(JobHandler在执行器端编码)。
运行代码或者脚本,叫做GLUE模式,支持java、Shell、PHP、Python、Nodejs等,这个时候代码维护在调度器这边。
3.6、阻塞处理策略
任务的一次运行还没有结束的时候,下一次调度的时间又到了,这个时候的处理方式
3.7、子任务
如果需要在本任务执行结束并执行成功的时候触发下一个任务,任务是相互依赖的,任务A—>任务B—>任务C,也就是说任务是串行调度的。那么就可以把另外的任务作为本任务的子任务运行。
因为每个任务都有一个唯一的任务ID(可以从任务列表中获取),只需要把JobId 填写上就可以了。
四、xxl 任务开发步骤
所有的任务开发步骤都是一样的:
1、返回固定public ReturnT<String> execute(String param)
参数固定String param、方法名自定义
2、为job 方法 添加@XxlJob注解、属性(init、destroy)
3、日志打印 XxlJobLogger.log
这个是固定的规范,所有的任务开发都要遵守这个开发流程(类似Quartz的任务必须实现job接口一样)。
4.1、任务类型
- demoJobHandler:简单任务;
- shardingJobHandler:分片任务;
- commandJobHandler:命令行任务;
- httpJobHandler:访问HTTP接口。
可以根据实际业务需求进行配置。