定时任务
单机定时任务 - Timer、Ticker
- Timer —— java
- Ticker —— Go
特点: 可以跨平台,只能控制一台机器的定时任务(仅单机可用)
单机定时任务 - ScheduledExecutorService
特点: 拥有线程池的功能,仅单机可用
任务调度 - Quartz
特点: 单任务极致控制,没有负载均衡机制
分布式定时任务!!!
优点: 平台化管理,分布式部署,支持海量数据
什么是分布式定时任务?
定时任务是指系统为了 自动 完成特定任务,实时、延时、周期性 完成任务调度的过程。分布式定时任务就是把分散的、可靠性差的定时任务纳入统一的平台,并实现集群管理调度和分布式部署的一种定时任务的管理方式。
按触发时机分类 :
- 定时任务 : 特定时间触发
- 延时任务 : 延迟触发,比如 10s 后触发
- 周期任务
分布式定时任务 - 执行方式
- 单机任务 : 随机触发一台机器执行任务,适用于计算量小,并发量低的任务
- 广播任务: 广播到所有机器上执行同一个任务,比如所有机器一起清理日志
- Map 任务: 一个任务拆解成很多个子任务,每个子任务负责一部分的计算,适用于计算量大,单机无法满足要求的任务
- MapReduce 任务:在Map任务的基础上,还可以对所有的子任务结果汇总计算,适用于计算量大,并且需要对子任务结果汇总的任务。
行业内定时任务框架
- Xxl - job : 开发迅速,易拓展,支持分片,支持简单的任务依赖和子任务依赖,不是跨平台的。开源免费,轻量级,开箱即用,操作简单易上手,在中小型公司使用广泛。
- SchedulerX 2.0:基于
AKKa框架自研,提供定时调度,调度任务编排和分布式批量处理的功能。付费使用,功能强大,在阿里巴巴内部广泛使用且久经考验 - TCT : 高性能,高可靠,通用的分布式任务调度中间件,支持国际通用的时间表达式,调度任务执行生命周期管理,解决传统地市任务单点及并发性能问题。支持任务分片,流程编排复杂调度任务处理能力,覆盖广泛的任务调度应用场景。未开源也未商用。
知识补充
分布式定时任务 与 单机定时任务
关系:
- 都可以实现自动化的定时、延时、周期任务调度
差异:
- 分布式定时任务可以支撑更大的业务体量。
- 分布式定时任务的性能、伸缩性、稳定性更高
分布式定时任务 与 大数据处理引擎
关系:
- 都可以对海量数据处理
- 性能、伸缩性、稳定性都很高
差异:
- 定时并不是大数据处理引擎要解决的核心问题
- 大数据处理引擎往往治理于将源数据处理成结果数据,分布式定时任务除了能做这个,还能调用
HTTP和RPC服务
实现原理
核心架构
分布式定时任务核心要解决 触发、调度、执行 三个 关键问题
- 触发器:Trigger, 解析任务,生成出发事件
- 调度器:Scheduler,分配任务,管理任务生命周期
- 执行器:Executor, 获取执行任务单元,执行任务逻辑
除此之外,还需要提供一个控制台(Admin),提供任务管理和干预功能。
控制台
基础概念
任务: Job, 任务元数据
任务实例: JobInstance,任务运行的实例
任务结构: JobResult,任务实例运行的结构
任务历史: JobHistory,用户可以修改任务信息,任务实例对应的任务元数据可以不同,因而使用任务历史存储
任务和任务实例之间是
1 :n 的关系,因为同一个任务可以多次执行,每次执行会生成一个实例
任务实例和任务结果之间也是 1:n 的关系,因为每个任务实例执行后,都可能失败,失败后就需要重新执行
任务和任务历史之间也是 1:n 的关系,不同版本的任务信息如果修改,就需要任务历史来记录修改。
任务元数据
任务元数据是用户对任务属性定义,包括任务类型调度时机、执行行为等。
Job
基础信息 WHO
调度时机 When
执行行为 What
执行方式 How
任务实例
任务实例是一个确定的 Job 的一次运行实例
JobInstance
Job_id
触发时间
状态 & 结果
过程信息
触发器
核心职责
给定一系列任务,解析他们的触发规则,在规定的时间点触发任务的调度
设计约束
- 需要支持大量任务:十万,百万级的任务
- 需要支持秒级的调度:比如秒杀业务需要精确到秒
- 周期任务需要多次执行
- 需要保证秒级扫描的高性能,并避免资源浪费
方案一
定时扫描 + 延时消息(腾讯、字节方案)
方案二
时间轮(Quartz 所用方案)
时间轮是一种高效利用线程资源进行批量化调度的一种调度模型。时间轮是一个存储环形队列,底层采用数组实现,数组中的每个元素可以存放一个定时任务列表
查询复杂度 �(1)O(1),修改复杂度 �(1)O(1)
问题 : 如果出现时间轮刻度不够怎么办?
- 给时间轮加上一个
count属性,相当于时间轮转过的圈数,规定当时间轮转过多少圈的时候再去执行这个任务。 - 使用多级时间轮存储任务,上一级时间轮转过对应刻度后再把任务塞入下一级时间轮中。
比如说上图中:任务二要在第 2 小时执行,所以任务二就会在时轮转到 2 的时候再放入分轮中去,分轮转到 3 后再放入到秒轮,然后秒轮就在 1 的时候执行了任务2。
查询和修改的时间复杂度同样为 �(1)O(1),且解决了单个时间轮刻度不够的问题。
触发器的高可用问题
核心问题:
- 不同业务之间,任务的调度相互影响怎么办
- 负责扫描和触发的机器挂掉了额怎么办
解法思路:
- 存储上:不同国别,不同业务做资源隔离
- 运行时,不同国别,不同业务分开执行
- 部署时 ,采用多机房集群化部署,避免单点故障,通过数据库锁或者分布式锁保证任务只被触发一次
Trigger模式
单 Trigger 模式
单 Trigger 模式下执行一致性高,但是会出现单点故障,机器故障时导致平台崩溃
Trigger 集群模式
有多个 Trigger 同时进行服务,一个 Trigger 挂掉还可以有其他 Trigger 相应,可以避免单点故障。但是需要避免同一个任务被多次触发,导致业务紊乱
数据库设计
行锁模式
为了保证在 Trigger 集群模式 下,同一个业务不被多次触发,数据库可以加上 行锁模式:在触发调度之前,更新数据库中的 JobInstance 状态,成功抢锁的 Trigger 才会触发调度。
抢锁成功
触发调度
抢锁失败
放弃调度
Trigger 1
数据库
Trigger 2
Trigger N
缺点 : 会有多台机器频繁竞争数据库锁,导致消耗资源,节点越多性能越差。
分布式锁模式
在触发调度之前,尝试抢占分布式锁,这里可以使用 Redis 锁或者 Zookeeper 锁
抢锁成功
触发调度
抢锁失败
放弃调度
Trigger 1
Redis
Trigger 2
Trigger N
特点: 性能比较高,多家公司使用这种方案,比较推荐。
调度器
核心问题:
- 资源来源:我可以调度的机器从哪里来,有多少。
- 资源调度:我有了这些机器后,要如何对对他们几种调度,如何使用。
- 任务执行:我要如何用资源去解决用户提交的任务。
资源来源
由业务系统提供机器资源
优点:
- 任务执行逻辑与业务系统共用一份资源,利用率很高
缺点:
- 更容易发生定时任务脚本影响在线服务的事故
- 不能由定时任务平台控制扩容缩容
使用该方案的公司:阿里、美团、字节。
由定时任务平台提供机器资源
优点:
- 任务执行逻辑与业务系统提供的在线服务隔离,避免相互影响
- 可以支持优雅的扩容缩容
缺点:
- 消耗更多的机器资源
- 需要额外为定时任务平台申请接口调用权限,而不能直接继承业务系统的权限。
使用该方案的公司:字节等
资源调度
- **随机节点执行:**随机选择集群中一个可用的执行节点执行调度任务。使用场景:定时对账
- 广播执行: 在集群中所有的执行节点分发调度任务并执行。适用场景:批量运维。比如需要所有机器一起删掉日志文件。
- 分片执行: 按照用户自定义分片逻辑进行拆分,分发到集群中不同节点并执行,提升资源利用效率,适用场景:海量日志统计
任务分片
通过任务分片来提高任务执行的效率和资源的利用率
单机任务
Map任务
Map任务
Map任务
区段1
区段2
区段N
任务
任务分片
Executor1
Executor2
ExecutorN
业务数据
如果有N个执行器 Executor, M 个业务数据区段,最后 �≥�M≥N ,保证每个机器都有工作,且 �M 是 �N 的整数倍。这样任务的颗粒度会更加细腻。