后端 | 青训营笔记

79 阅读9分钟

定时任务


单机定时任务 - 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 所用方案)

时间轮是一种高效利用线程资源进行批量化调度的一种调度模型。时间轮是一个存储环形队列,底层采用数组实现,数组中的每个元素可以存放一个定时任务列表

1676763918526-screenshot.png

查询复杂度 �(1)O(1),修改复杂度 �(1)O(1)

问题 : 如果出现时间轮刻度不够怎么办?

  1. 给时间轮加上一个 count 属性,相当于时间轮转过的圈数,规定当时间轮转过多少圈的时候再去执行这个任务。
  2. 使用多级时间轮存储任务,上一级时间轮转过对应刻度后再把任务塞入下一级时间轮中。

比如说上图中:任务二要在第 2 小时执行,所以任务二就会在时轮转到 2 的时候再放入分轮中去,分轮转到 3 后再放入到秒轮,然后秒轮就在 1 的时候执行了任务2。

查询和修改的时间复杂度同样为 �(1)O(1),且解决了单个时间轮刻度不够的问题。

触发器的高可用问题

核心问题:

  1. 不同业务之间,任务的调度相互影响怎么办
  2. 负责扫描和触发的机器挂掉了额怎么办

解法思路:

  1. 存储上:不同国别,不同业务做资源隔离
  2. 运行时,不同国别,不同业务分开执行
  3. 部署时 ,采用多机房集群化部署,避免单点故障,通过数据库锁或者分布式锁保证任务只被触发一次
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

特点:  性能比较高,多家公司使用这种方案,比较推荐。

调度器

核心问题:

  1. 资源来源:我可以调度的机器从哪里来,有多少。
  2. 资源调度:我有了这些机器后,要如何对对他们几种调度,如何使用。
  3. 任务执行:我要如何用资源去解决用户提交的任务。
资源来源

由业务系统提供机器资源

优点:

  • 任务执行逻辑与业务系统共用一份资源,利用率很高

缺点:

  • 更容易发生定时任务脚本影响在线服务的事故
  • 不能由定时任务平台控制扩容缩容

使用该方案的公司:阿里、美团、字节。

由定时任务平台提供机器资源

优点:

  • 任务执行逻辑与业务系统提供的在线服务隔离,避免相互影响
  • 可以支持优雅的扩容缩容

缺点:

  • 消耗更多的机器资源
  • 需要额外为定时任务平台申请接口调用权限,而不能直接继承业务系统的权限。

使用该方案的公司:字节等

资源调度
  1. **随机节点执行:**随机选择集群中一个可用的执行节点执行调度任务。使用场景:定时对账
  2. 广播执行:  在集群中所有的执行节点分发调度任务并执行。适用场景:批量运维。比如需要所有机器一起删掉日志文件。
  3. 分片执行:  按照用户自定义分片逻辑进行拆分,分发到集群中不同节点并执行,提升资源利用效率,适用场景:海量日志统计
任务分片

通过任务分片来提高任务执行的效率和资源的利用率

单机任务

Map任务

Map任务

Map任务

区段1

区段2

区段N

任务

任务分片

Executor1

Executor2

ExecutorN

业务数据

如果有N个执行器 Executor, M 个业务数据区段,最后 �≥�M≥N ,保证每个机器都有工作,且 �M 是 �N 的整数倍。这样任务的颗粒度会更加细腻。