分布式任务调度平台的研究(下)

阅读数:1 2020 年 2 月 10 日 21:02

分布式任务调度平台的研究(下)

接上文

三 、SIA-TASK 介绍

3.1 SIA-TASK 技术选型

sia-task-3.png

  • REST:一种软件架构风格。这里要求执行器暴露 Http 调用接口来达到跨平台的目的;

  • AOP:切面编程技术。在 Spring 项目扩展包 Hunter 中使用,保证 Task 被串行调用(单例单线程);

  • Quartz:功能强大,应用灵活,对单个任务的控制基本做到了极致。这里用来作为调度中心时钟组件;

  • MySQL:用于元数据存储与(暂时)日志存取;

  • Elastic:基于 Lucene 的搜索服务器,提供了一个分布式多用户能力的全文搜索引擎。用于日志的存储与查询;

  • SpringCloud:社区活跃的开发框架,也是公司指定的统一开发框架。用于快速开发,快速迭代;

  • MyBatis:一款优秀的持久层框架,支持定制化 SQL,存储过程以及高级映射。用于简化持久层开发;

  • Zookeeper:久经考验的注册中心。用来解决调度中心高可用,分布式一致性等问题。

3.2 SIA-TASK 设计思想

SIA-TASK 借鉴微服务设计思想,获取分布在每个执行器节点上的任务(Task)元数据,进行汇报,上传注册中心。利用在线可编辑方式支持任务在线编排、动态修改任务时钟;使用 Http 协议作为交互传输协议。数据交互格式统一使用 Json。用户通过编排器 (下文会做介绍) 进行操作,触发事件,调度器接收事件,由调度中心进行时钟解析,执行任务流程,进行任务通知。

3.3 SIA-TASK 基本概念

SIA-TASK 采用任务和调度分离的方式,业务的执行任务逻辑和调度逻辑完全分离。系统组成共涉及以下几个核心概念:

  • 任务(Task): 基本执行单元,执行器对外暴露的一个 HTTP 调用接口 ;

  • 作业(Job): 由一个或者多个存在相互逻辑关系(串行 / 并行)的任务组成,任务调度中心调度的最小单位 ;

  • 计划(Plan): 由若干个顺序执行的作业组成,每个作业都有自己的执行周期,计划没有执行周期 ;

  • 任务调度中心(Scheduler): 根据每个的作业的执行周期进行调度,即按照计划、作业、任务的逻辑进行 HTTP 请求 ;

  • 任务编排中心(Config): 编排中心使用任务来创建计划和作业 ;

  • 任务执行器(Executer): 接收 HTTP 请求进行业务逻辑的执行 ;

  • Hunter:Spring 项目扩展包,负责执行器中的任务抓取,上传注册中心,业务可依赖该组件进行 Task 编写。

3.4 SIA-TASK 系统架构

SIA-TASK 可以分为三大模块(调度中心、编排中心和执行器)、两大组件(持久化存储和注册中心)。这三大模块和两大组件的作用如下:

  • 任务调度中心:负责抢占 Job 和任务调度以及任务迁移等,是 SIA-TASK 的核心功能模块;

  • 任务编排中心:负责对在线任务进行逻辑编排,提供日志查看和实时监控功能;

  • 任务执行器:负责接收调度请求并执行任务逻辑;

  • 任务注册中心(ZK):协调 Job 和 Task、调度器等的工作流程;

  • 持久化存储(DB):记录项目的 Job 和 Task 数据,并提供日志存储。

SIA-TASK 使用 SpringBoot 体系作为架构选型,基于 Quartz 及 Zookeeper 进行二次开发,支持相应的特性功能,SIA-TASK 的逻辑架构图如下图所示:

sia-task-4.png

3.5 SIA-TASK 模块说明

3.5.1 任务调度中心

任务调度中心负责任务调度,管理调度信息,按照调度配置发出调度请求,自身不承担业务代码。调度系统与任务解耦,提高了系统可用性和稳定性,同时调度系统性能不再受限于任务模块;支持可视化、简单且动态地管理调度信息,包括任务新建,更新,删除和任务报警等,所有上述操作都会实时生效,同时支持监控调度结果以及执行日志,支持执行器故障恢复。

3.5.2 任务编排中心

任务编排中心是分布式调度中心支持在线任务模型编排的组件;依托于 UI 可进行 web 端任务编排;

我们可以通过上述基础模型来编排一些复杂的调度模型,例如:

architect-task-relationship.png

SIA-TASK 的 UI 编排界面:

architect-arrange-page.png

编排结束后查看 task 的编排信息如下图所示:

architect-relation.png

同时,编排中心还提供首页统计数据查看、调度监控、Job 管理、Task 管理以及日志管理功能。

3.5.3 任务执行器

负责接收调度请求并执行任务逻辑。任务模块专注于任务的执行等操作,开发和维护更加简单和高效;

执行器支持两种类型:

(1) 如果使用 sia-task-hunter,支持 SpringBoot 项目和 Spring 项目, 引入 sia-task-hunter,任务(Task)抓取客户端。合规的 HTTP 接口(称之为 Task)任务会自动被抓取并上传注册中心;

(2) 如果不使用 sia-task-hunter,只需提供任务可调用的 HTTP 接口,此时需要业务手动录入,且自行控制该任务的并发调用控制。

3.5.4 任务注册中心(Zookeeper)

分布式框架采用 Zookeeper 作为注册中心。

architect-zookeeper.png

(1) 任务注册 调度中心和执行集群都以 Zookeeper 作为注册中心,所有数据以节点及节点内容的形式注册,通过定时汇报主机状态保持存活在 Zookeeper 上。

(2) 元数据存储 注册中心不仅仅提供注册服务,并且存储每个执行器的信息(包括执行器实例信息,执行器上传的 Task 元数据,以及任务运行时的一些临时状态数据)。

(3) 事件发布 基于 Zookeeper 事件推送机制,进行任务的发布,通过平衡算法保证调度器任务抢占的分布均衡。

(4) 负载均衡 保证调度器获取执行 Job 的个数均衡,避免单一节点压力。

3.5.5 持久化存储(DB)

这里采用 MySQL 作为数据持久化解决方案。

除了 Task 动态元数据保存在注册中心之外,其他相关的元数据都存入 MySQL,包括但不限于:手动录入的 Task,配置的 Job 信息,编排的 Task 依赖信息,调度日志,业务人员操作日志,Task 执行日志等。

3.6 SIA-TASK 关键运行流程

3.6.1 任务发布流程

architect-task-publish.png

(1) 用户可以通过 UI 进行 Job 创建:可以选择 Job 类型,设置预警邮箱,设置 Job 描述。然后为创建的 Job 进行任务 Task 编排;

(2) Job 创建完毕并且设置 Task 编排关系后可进行任务发布,通过 UI 对相应的 Job 进行操作(激活,执行一次,停止以及删除操作);

(3) 用户的 Task 任务可以是通过抓取器抓取的,亦可以使用 UI 手动创建。

3.6.2 执行流程

architect-task-executer.png

(1) Job 创建完成之后,可以选择激活触发定时任务;

(2) Job 到达预订时间后,调度中心触发 Job,然后按照预定的 Task 编排逻辑通过 http 通知 Task 执行器进行执行,并异步监听任务执行结果;

(3) 若执行结果成功,则判断是否存在后置 Task,若存在,则继续下一次调度,若不存在,则说明该 Job 执行完毕,结束本次调用;若执行结果失败,则触发故障恢复策略:立即停止、忽略本次失败、多次尝试、转到其它执行器执行。

3.6.3 状态流转

Job 在整个生命周期内存在四种状态,分别是:已停止(NULL)、准备中(READY)、开始运行(RUNNING)、异常停止(STOP),状态流转及流转条件如下图所示。

architect-process.png

3.7 SIA-TASK 模块设计

SIA-TASK 的物理网络拓扑图如下所示:

architect-net.png

SIA-TASK 的模块间交互设计思路: (1) 通过编排中心创建 Task 任务或通过 Hunter 自动抓取,并将 Task 信息异步保存到 DB;创建 Job 并激活,在 zookeeper 中创建 JobKey;

(2) 调度中心会监听 zookeeper 中 JobKey 创建事件,然后抢占创建的 Job,抢占成功后加入 quartz 定时任务,当时间到达即触发 Job 运行。调度中心异步调用执行器服务执行 Job 中的 Task (可能存在多个 Task ,遵循 Task 失败策略),并将结果返回到调度中心;

(3) 将 Job 执行状态随时在 zookeeper 上更改,通过编排中心的查询接口可以进行查询;

(4) Job 执行结束后,等待下一次执行。

3.7.1 任务编排中心设计

编排中心可以与 DB 和 zookeeper 进行数据交互,其主要功能可分为三方面:

  • 数据持久化接口服务;

  • zookeeper 上元数据变更;

  • 数据可视化:查看系统各种统计数据等。

编排中心首页监控展示如下:

architect-home.png

3.7.2 任务调度中心设计

调度中心主要与 DB、ZK 和执行器进行交互,其主要功能可分为以下几个方面:

  • Job 执行日志记录

  • ZK 中 Job 状态变更

  • 调用执行器服务执行 Job

  • 调度中心高可用

  • Job 调度线程池

3.7.3 任务执行器设计

执行器可以与 ZK 和调度中心进行交互,其主要功能可分为两个方面:

  • 接受调度中心的调度,执行定时任务,并将结果返回到调度中心;

  • 自动抓取执行器上的 Task 任务,提交到 ZK。

执行器 Task 示例:

@OnlineTask(description = "在线任务示例",enableSerial=true)
@RequestMapping(value = "/example", method = { RequestMethod.POST }, produces = "application/json;charset=UTF-8")
@CrossOrigin(methods = { RequestMethod.POST }, origins = "*")
@ResponseBody
public String example(@RequestBody String json) {   
    /**
     * TODO:客户端业务逻辑处理
     */
    Map info = new HashMap();
    info.put("status", "success");
    info.put("result", "as you need");
    return JSONHelper.toString(info);
}

由此可见,任务 Task 编写非常简单。

3.8 SIA-TASK 高可用设计

分布式服务一般都要考虑高可用方案,同样 SIA-TASK 为了保证高可用,针对不同的服务组件进行了不同维度增强。

3.8.1 任务编排中心的高可用

SIA-TASK 通过前后端分离、服务拆分等措施实现了编排中心的高可用。当集群中某实例失效后,不会影响集群的其它实例,因此无需特殊操作即可使用集群中其它的可用编排中心;

3.8.2 任务调度中心的高可用

3.8.2.1 异常转移

如果调度中心集群中的某个实例节点服务宕机后,这个实例节点上的所有 Job 会平滑迁移到集群中可用的实例上,不会造成定时任务的执行缺失,同时,当崩溃后的实例修复成功重新接入该集群时,会继续抢占 Job 提供服务。

3.8.2.2 配置线程池

调度采用线程池方式实现,避免单线程因阻塞而引起任务调度延迟。 程池里的线程数,默认值是 10,当执行任务会并发执行多个耗时任务时,要根据业务特点选择线程池的大小。

org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool org.quartz.threadPool.threadCount = 60
org.quartz.threadPool.threadPriority = 5
org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread = true

SIA-TASK 根据 quartz 自身提供的 threadPool 基础上再次进行线程池的利用。进行线程池重新定义,针对每个 Job 去分配一个独有的线程池。线程池的大小可根据 Job 自身编排的 Task 个数的大小进行动态伸缩,从而保证每个 Job 的调度线程完全独立,不在会因为编排 Task 个数的陡增而耗尽线程资源。同时提供线程池资源的回收逻辑,在 Job 进行永久性终止时回收为期分配的线程池资源。

public static ExecutorService getExecutorService(String JobKey) {

    ExecutorService exec = executorPool.get(JobKey);
     if (exec == null) {
        LOGGER.info(Constants.LOG_PREFIX + "Initialize thread pool for running Jobs,Job is {}",JobKey);
      exec = Executors.newCachedThreadPool();
      executorPool.putIfAbsent(JobKey, exec);
      exec = executorPool.get(JobKey);
  }
    return exec;
}
3.8.2.3 全日志跟踪

SIA-TASK 针对 Job 的整个调度生命周期进行全面跟踪,利用 AOP 进行日志增强,调度中心每触发一次 Job 调度就会进行日志记录。同时针对 Job 编排的 Task 执行也会进行记录任务日志。

日志分为 Job 日志和 Task 日志:

  • Job 日志:包含调度器信息,调度时间,调度状态以及其他附加属性。

  • Task 日志:包含执行器信息,执行时间,执行状态,返回信息以及其他附加属性。

3.8.2.4 异步封装
  • SIA-TASK 从一开始设计就考虑了任务进行远程调用对调度中心并发线程资源的损耗。对于 Job 封装的 Task 远程调度,全部采用异步调用,每次任务请求逻辑的耗时非常的轻量化。只仅仅一次见到的 http 请求。

  • 支持 Task 进行用户自定义超时设置,支持两种模式的超时:connecttimeout,readtimeout。支持用户可以根据业务的具体执行周期来进行超时设置。

public interface RestTemplate {

/**
 * 异步 Post 方法 * @param request
 * @param responseType
 * @param uriVariables
 * @param  * @return
 */
  ListenableFuture postAsyncForEntity(Request request, Class responseType, Object... uriVariables); }
3.8.2.5 自定义调度器资源池

architect-scheduler-pool.png

SIA-TASK 从物理资源角度设计了调度资源池,出于一些特殊情况的考量我们针对调度器进行了池化;调度器可以通过不同的操作进行状态的转变,从而进行能力的转化。

  • 工作调度器资源池:管理具备获取任务能力并且可以实际获取任务的调度器资源。

  • 下线调度器资源池:管理具备获取任务能力但是实际不允许获取的调度器资源。

  • 离线调度器资源池:管理下线调度器资源池中已经宕机的调度器资源。

3.8.3 任务执行器的高可用

  • 考虑网络的不稳定性,SIA-TASK 针对网络的不稳定性也做出了非常重要的设计,对于节点的连通性的测试支持以及针对 Task 运行实例节点健康的预感知,保证提前感知 Task 实例节点的健康情况,保证调度 Task 高可用。

  • 同时也保证了执行器实例针对网络导致链接中断的问题,SIA-TASK 重新设计了 zookeeper 的重连机制,保证 Task 运行实例节点因网络问题丢失链接后还能进行恢复重试,直到恢复正常后并入执行池中正常接收任务的调度。

  • 一般来说,执行器也是集群部署的。作为 Task 的执行单元,如果在执行器集群中一台机器上执行失败,调度中心会根据失败策略来做故障转移。这里提供了两种故障转移策略:轮询转移和最大补偿转移。轮询转移为对可用的执行器列表进行轮询,若有一个执行器执行成功,则 Task 执行成功,若全部执行失败,则 Task 执行失败。最大补偿转移为首先在本执行器再次执行若干次,若执行成功,则不会转移,若还是执行失败,则执行轮询转移策略。

四 、总结

至此对微服务任务调度平台 SIA-TASK 做了一个简要的介绍,包括设计背景,架构设计,以及产品组件功能与特性。微服务任务调度平台 SIA-TASK 基本上解决了当前的业务需求,提供简单高效的编排调度服务。SIA-TASK 会持续迭代,提供更为完善的服务。之后也会提供相关技术文档和使用文档。

本文转载自宜信技术学院网站。

原文链接: http://college.creditease.cn/detail/253

评论

发布