一、 基础概念
1. 什么是定时任务
定时任务形式:每隔一定时间/特定某一时刻执行
场景:
订单审核、出库
订单超时自动取消、支付退款
礼券同步、生成、发放作业
物流信息推送、抓取作业、退换货处理作业
数据积压监控、日志监控、服务可用性探测作业
定时备份数据
金融系统每天的定时结算
数据归档、清理作业
报表、离线数据分析作业
2. 定时任务与消息队列的区别
共同点
异步处理:比如注册、下单事件
应用解耦: 不管定时任务作业还是MQ都可以作为两个应用之间的齿轮实现应用解耦,这个齿轮可以中转数据,当然单体服务不需要考虑这些,服务拆分的时候往往都会考虑。
流量削峰: 双十一的时候,任务作业和MQ都可以用来扛流量,后端系统根据服务能⼒定时处理订单或者从MQ抓取订单抓取到一个订单到来事件的话触发处理,对于前端用户来说看到的结果是已经下单成功了,下单是不受任何影响的。
本质区别
定时任务作业是时间驱动,而MQ是事件驱动。
时间驱动是不可代替的,比如金融系统每日的利息结算,不是说利息来一条(利息到来事件)就算一下,而往往是通过定时任务批量计算;
定时任务作业更倾向于批处理,MQ倾向于逐条处理。
3. 分布式和集群的区别
分布式
把一个系统拆分为多个子系统,每个子系统负责各自的那部分功能,独立部署,各司其职。
集群
多个实例共同工作,最简单/最常见的集群是把一个应用复制多份部署。
区别
分布式一定是集群:集群就是多个实例一起工作,分布式将一个系统拆分后那就是多个实例。
集群不一定是分布式:因为复制型集群不是拆分而是复制。
4. 什么是分布式调度
两层含义:
运行在分布式集群环境下的调度任务
同一个定时任务程序部署多份,只应该有一个定时任务在执行
分布式调度—>定时任务的分布式—>定时任务的拆分
即为把一个大的作业任务拆分为多个小的作业任务,同时执行
二、 为什么要使用 ElasticJob?
1. 定时任务的几种方式
Timer
这是 Java 自带的 java.util.Timer 类,这个类允许调度一个名为 java.util.TimerTask 任务。使用这种方式可以让你的程序按照某一个频度执行,但不能在指定时间运行。现在一般用的较少。
ScheduledExecutorService
JDK 自带的一个类,是基于线程池设计的定时任务类,每个调度任务都会分配到线程池中的一个线程去执行。也就是说,任务是并发执行,互不影响的。
Spring Task
Spring 3.0 以后自带的 Task,支持多线程调度,可以将它看成一个轻量级的 Quartz,而且使用起来比 Quartz 简单许多,但是适用于单节点的定时任务调度。
Quartz
这是一个 功能比较强大的调度器,可以让你的程序在指定时间执行,也可以按照某一个频度执行,配置起来稍显复杂。使用 Cron 时间表达式(包括:秒、分、时、日、月、周、年)配置某一个任务什么时间去执行:
每一个元素都可以显式地规定一个值(如 6),一个区间(如 9-12),一个列表(如 9,11,13)或一个通配符(如 *,/)。"月份中的日期" 和 "星期中的日期" 这两个元素是 互斥的,因此应该通过设置一个问号(?)来表明你不想设置的那个字段。
下表显示了一些 cron 表达式的例子:
表达式
意义
0 0 12 * * ?
每天中午12点触发
0 15 10 ? * *
每天上午10:15触发
0 15 10 * * ?
每天上午10:15触发
0 15 10 * * ? *
每天上午10:15触发
0 15 10 * * ? 2005
2005年的每天上午10:15触发
0 * 14 * * ?
在每天下午2点到下午2:59期间的每1分钟触发
0 0/5 14 * * ?
在每天下午2点到下午2:55期间的每5分钟触发
0 0/5 14,18 * * ?
在每天下午2点到2:55期间和下午6点到6:55期间的每5分钟触发
0 0-5 14 * * ?
在每天下午2点到下午2:05期间的每1分钟触发
0 10,44 14 ? 3 WED
每年三月的星期三的下午2:10和2:44触发
0 15 10 ? * MON-FRI
周一至周五的上午10:15触发
0 15 10 15 * ?
每月15日上午10:15触发
0 15 10 L * ?
每月最后一日的上午10:15触发
0 15 10 ? * 6L
每月的最后一个星期五上午10:15触发
0 15 10 ? * 6L 2002-2005
2002年至2005年的每月的最后一个星期五上午10:15触发
0 15 10 ? * 6#3
每月的第三个星期五上午10:15触发
0 6 * * *
每天早上6点
0 /2 * *
每两个小时
0 23-7/2,8 * * *
晚上11点到早上8点之间每两个小时,早上八点
0 11 4 * 1-3
每个月的4号和每个礼拜的礼拜一到礼拜三的早上11点
0 4 1 1 *
1月1日早上4点
2. 以上定时任务框架的缺点
业务工程集群部署,可能会会重复多次执行而引发系统逻辑的错误导致系统的业务逻辑错误。
Quartz 集群方案仅仅只是解决了 HA,节点数量的增加并不能给我们的每次执行效率带来提升,即不能实现水平扩展。
所以在在分布式架构环境中使 Quartz 已经不能更好
的满足我们需求,我们可以使用专业的分布式调度框架,这里推荐使用 Elastic-job。
三、分布式调度框架Elastic-Job
1. Elastic-Job 介绍
① Elastic-Job 是当当网开源的一个分布式调度解决方案,基于 Quartz 二次开发的。
② 两个相互独立的子项由 Elastic-Job-Lite 和 Elastic-Job-Cloud 组成。
Elastic-Job-Lite:它定位为轻量级无中心化解决方案,使用Jar包的形式提供分布式任务的协调服务,外部依赖仅Zookeeper。
Elastic-Job-Cloud:子项目需要结合 Mesos 以及 Docker 在云环境下使用
③ Elastic-Job的github地址::github.com/elasticjob
2. 整体架构
3. 核心功能
分布式调度协调
在分布式环境中,任务能够按指定的调度策略执行,并且能够避免同一任务多实例重复执行。
丰富的调度策略
基于成熟的定时任务作业框架Quartz cron表达式执行定时任务
弹性扩容缩容
当集群中增加某一个实例,它应当也能够被选举并执行任务。
当集群减少一个实例时,它所执行的任务能被转移到别的实例来执行。
失效转移
某实例在任务执行失败后,会被转移到其他实例执行。
错过执行作业重触发
若因某种原因导致作业错过执行,自动记录错过执行的作业,并在上次作业完成后自动触发。
支持并行调度
支持任务分片,任务分片是指将一个任务分为多个小任务项在多个实例同时执行。
作业分片一致性
当任务被分片后,保证同一分片在分布式环境中仅一个执行实例
4. Elastic-Job-Lite 轻量级去中心化的特点
去中心化
执行节点对等(程序和 jar 一样,唯一不一样的可能是分片)
定时调度自触发(没有中心调度节点分配)
服务自发现(经过注册中心的服务发现,注册中心仅用于作业注册和监控信息存储。)
主节点非固定(主作业节点仅用于处理分片和清理等功能)
轻量级
All in jar, 外部依赖仅Zookeeper。
并非独立部署的中间件,使用Jar包的形式提供分布式任务的协调服务。