分布式定时任务框架实现原理 | 青训营笔记

392 阅读6分钟

这是我参与「第五届青训营 」笔记创作活动的第 13 天

一、本堂课重点内容

有关分布式定时任务的基本实现原理

二、详细知识点介绍

实现原理

核心架构

分布式定时任务核心要解决触发、调度、执行三个问题

这里就涉及到三个不同的概念:

  • 触发器: Trigger,解析任务,生成触发事件
  • 调度器: Scheduler,分配任务,管理任务生命周期
  • 执行器: Executor,获取执行任务单元,执行任务逻辑

除此之外,还需要提供一个控制台(Admin),提供任务管理和干预的功能。

而他们四者之间的关系正如下图所示:

image-20230209161350002

数据流

接下来我们看一下分布式定时任务的数据流,也就是分布式定时任务整体上业务流程是如何运行的

如下图所示,用户通过告知控制任务对应的信息,在一定触发规则的基础上,执行了某一段任务代码,然后控制台将用户输入的定时诗句存入任务DB,以此完成任务创建工作

而任务执行,是控制台通过触发器,当触发器满足用户输入的触发规则,就会触发调度器进行定时任务的调度,最后通过执行器来成功完成整个任务的执行。

image-20230209161734338

功能架构

功能架构呢,我们就分别从控制台、触发器、调度器、执行器四个方面,从下图就能很清晰的看见

image-20230209162246833

控制台

基本概念

控制台中有多个关键元素,我们接下来一一简单讲解一下

  • 任务: Job,任务元数据
  • 任务实例: JobInstance,周期任务会生成多个任务实例
  • 任务结果: JobResult,任务实例运行的结果
  • 任务历史: JobHistory,用户可以修改任务信息,任务实例对应的任务元数据可以不同,因而使用任务历史存储

下图(E-R图)展示了这些元素之间的关系:

image-20230209164147765

任务

任务元数据(Job)是用户对任务属性定义,包括任务类型调度时机、执行行为等。

image-20230209164403921
任务实例

任务实例(JobInstance)是一个确定的Job的一次运行实例

image-20230209164437216

触发器

核心职责

给定一系列任务,解析他们的触发规则,在规定的时间点触发任务的调度

设计约束

  • 需要支持大量任务
  • 需要支持秒级的调度
  • 周期任务需要多次执行
  • 需要保证秒级扫描的高性能并避免资源浪费

触发器方案

定期扫描+延时消息 (腾讯、字节方案)

定时扫描机器集群部署,通过分布式锁保证只有一台机器在调度

基本流程如下图

image-20230209165302910
时间轮 (Quartz方案)

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

其目的是便利任务列表,从中找到当前时间点需触发的任务列表

时间轮模型如下:

image-20230209165422824

实现原理如下:

image-20230209165716528image-20230209165723645

image-20230209165731285

image-20230209165754634

高可用

触发器的高可用在分布式定时任务框架中的重要性是显而易见的,一旦任务调度受到影响,或者负责扫描和触发的机器或服务挂了,就会出现不可逆转的灾难

而解决高可用问题的思路有如下几种:

  • 存储上,不同国别、业务做资源隔离
  • 运行时,不同国别、业务分开执行
  • 部署时,采用多机房集群化部署,避免单点故障,通过数据库锁或分布式锁保证任务只被触发一次

而高可用的问题又引发出了一系列的问题:

  • 只有一个触发器,如果这个触发器故障,整个平台就崩溃了
  • 有多个触发器构成集群,可以避免单点故障,弹需要避免同一个任务被多次触发,导致业务紊乱

接下来我们就引入了锁的概念

我们可以通过数据库行锁的形式,在触发调度之前,更新数据库中JobInstance的状态,成功抢锁的才会触发调度,但在这种情况下,多台机器频繁竞争数据库锁,节点越多会导致性能越差

或者我们可以使用分布式锁来解决这种问题,在触发调度之前,尝试抢占分布式锁,可使用Redis锁或Zookeeper锁

这样的方法性能较高,有较多公司使用这种方案

调度器

资源来源

调度器在定时任务资源来源方面主要分为两个大类,我们分别来介绍

业务系统提供机器资源

使用该方案的公司:

  • 美团、阿里、字节等等

优点:

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

缺点:

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

使用该方案的公司:

  • 字节跳动等

优点:

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

缺点:

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

资源调度

节点选择

而调度器选择使用哪个执行器节点进行定时任务的执行也主要分为三种情况:

  • 随机节点执行
    • 选择集群中一个可用的执行节点执行调度任务
    • 适用场景:定时对账
  • 广播执行
    • 在集群中所有的执行节点分发调度任务并执行
    • 适用场景:批量运维
  • 分片执行
    • 按照用户自定义的分片逻辑进行拆分,分发到集群中不同节点并行执行,提高资源利用效率
    • 适用场景:海量日志统计
任务分片

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

我们可以通过下图的模型来理解

image-20230209171502494

高级特性

任务编排

大多数分布式定时任务框架都支持使用有向无环图DAG (Directed Acyclic Graph)进行可视化的任务编排

就如下图所示,是一种编排的例子:

image-20230209171747846

故障转移

故障转移是为了确保部分执行单元任务失败时,任务最终成功

分片任务基于一致性hash策略分发任务,当某个Executor异常时,调度器会将任务分发到其他的Executor

image-20230209171903663

高可用

调度器可以做到集群部署,做到完全的无状态,依靠消息队列的重试机制保障任务一定会被调度

image-20230209171953617

执行器

执行器的基本框架如下图,基于注册中心,执行器可以做到弹性进行扩缩容

image-20230209172343622