浅谈分布式任务调度框架_资源调度框架_hitzbb的博客-程序员宅基地

技术标签: 架构  调度  java  框架  

1、前言

上一篇文章谈了单机的定时任务解决方案,只能在单个JVM进程中使用;而我们的现在基本上是分布式场景,需要一套在分布式环境下高性能、高可用、可扩展的分布式任务调度框架;是否将之前的单机解决方案部署到分布式就可以?面临的分布式场景如何实现分布式的任务调度,如何解决单点故障问题实现高可用?接下来我们首先分析分布式任务调度框架相对单机的优势以及结合几种任务调度框架分析是如何逐步实现分布式的高可用、效率的,最后综合比较下业界比较流行的框架,在项目开发中方便选择。

2、Why 分布式任务调度框架

背景

1、单点故障

举个例子,村里只有一口井,有口井突然被污染了,村里就都没有井水喝了;分布式就是平时挖了多口井,一口井出问题照样有水喝。
image.png

image.png

之前我们说到单机的定时任务可能机器存在异常,如果没有分布式任务调度,那这个机器上所有定时任务只能等到这个机器恢复后才可以执行,这显然可用性就很低。

分布式任务调度就是在集群中多台调度、多台执行,一台调度机器或者执行机器出问题,能够立刻故障转移,不影响后续任务的执行,提高整体的可用性。

2、性能瓶颈

都知道一台机器的CPU、内存资源是有限的,像我们单机任务都直接写在业务机器上,单机任务瓶颈立现;当定时任务多,每秒执行上W个定时任务,单机是难以支撑的,而且定时任务会影响到业务系统的资源,整个系统就会非常不可靠。单机靠多线程,单机瓶颈达到后就要依靠分布式集群来水平扩展,解决资源瓶颈问题。

3、协同效率

每个定时任务调度的使用业务方都需要自己在业务系统构造一套分布式定时任务调度框架吗?这显然是低效?专业分工是必然的发展趋势,这就需要分布式的任务调度框架的出现,其他业务作为接入方,使用即可,不需要再考虑分布式调度的调度策略的高可用、异常故障恢复、控制台配置等等问题,只需要专注业务逻辑即可。

3、演进过程

什么是分布式任务调度

分布式任务调度,三个关键词:分布式、任务调度、配置中心。
分布式:平台是分布式部署的,各个节点之间可以无状态和无限的水平扩展(保证可扩展);

任务调度:涉及到任务状态管理、任务调度请求的发送与接收、具体任务的分配、任务的具体执行;(集群中哪些机器什么时候执行什么任务,所以又需要一个可以感知整个集群运行状态的配置中心)

配置中心:可以感知整个集群的状态、任务信息的注册

常见的分布式任务调度框架一般有以下5个部分
1、控制台:负责调度任务的配置、任务状态、信息展示
2、接入:将控制台的任务转化下发给调度器,并且向注册中心注册任务
3、调度器:接收接入下发的调度任务,进行任务拆分下发,在注册中心找执行器,然后把任务下发到执行器执行,同时也注册到注册中心
4、执行器:接收调度任务,并且上报状态给注册中心
5、注册中心:机器、任务状态的同步、协调

现在林林总总的框架,大部分都是在Quartz的基础上进行改进,我们先来看看经典的Quartz怎么做的?

Quartz

Quartz是OpenSymphony开源组织在任务调度领域的一个开源项目,完全基于java实现。作为一个优秀的开源框架,Quartz具有以下特点:强大的调度功能、灵活的应用方式、分布式和集群能力,另外作为spring默认的调度框架,很容易实现与Spring集成,实现灵活可配置的调度功能。

Quartz框架的核心对象

Scheduler – 核心调度器,就是任务调度、分配的控制器
Job – 任务,代表具体要执行的任务,是个接口,里面有默认方法,开发者需要实现该接口,并且业务逻辑写在默认的execute方法中
JobDetail – 任务描述,描述job的静态消息,是调度器需要的数据,跟Job区分开来,主要是为了一个Job可以在多台机器并行,每个调度器new一个Job的实现类
Trigger – 触发器,用于定义任务调度的时间规则

#对象之间的关系

这是单机Quartz最小的执行单元的关系
image

集群部署

image.png

上图3个节点在数据库中都有同一份Job定义,如果某一个节点失效,那么Job会在其他节点上执行。因为每个节点上的代码都是一样的,那么如何保证只有一台机器上触发呢?答案是使用了数据库锁。在quartz集群解决方案了有张scheduler_locks,采用了悲观锁的方式对triggers表进行了行加锁,以保证任务同步的正确性。

简单来说,quartz的分布式调度策略是以数据库为边界的一种异步策略。各个调度器都遵守一个基于数据库锁的操作规则从而保证了操作的唯一性,同时多个节点的异步运行保证了服务的可靠。(实际上是用数据库锁作为分布式锁解决同步问题实现异步运行,跟redis、zk做分布式锁时是一样的)

但这种策略有自己的局限性:集群特性对于高CPU使用率的任务效果特别好,但是对于大量的短任务,各个节点都会抢占数据库锁,这样就出现大量的线程等待资源。

因此Quartz的分布式只解决了任务高可用(减少单点故障)的问题,处理能力瓶颈会在数据库,而且没有执行层面的任务分片,无法最大化效率,只能依靠shedulex调度层面做分片,但是调度层做并行分片难以结合实际的运行资源情况做最优的分片。

quartz通过数据库锁的方式来保证分布式环境下定时任务调度的同步,解决了单点故障,只引入了数据库,整体的结构简单;但是在效率上,由于数据库锁带来的竞争冲突,会使得在短任务较多时的低效,并且没有在执行时对任务分片,无法充分利用集群性能,也就是说没法真正的做到水平扩展,瓶颈被数据库锁限制住了。

Elastic-job

要解决这个分布式的水平扩展、效率问题,我们知道需要引入注册中心进行协调,这里当当退出的Elastic-job就是Quartz的基础上,引入ZK做注册中心。并且在2.0版本后出现了两个相互独立的产品线:Elastic-job-lite和Elastic-job-cloud。Elastic-job-lite定位为轻量级无中心化的解决方案,使用jar包的形式提供分布式任务的协调服务,外部依赖仅依赖于zookeeper。

elastic-job-lite的结构

这款轻量级的架构做了很多的改进,这里只谈到两点,
1、无中心调度节点
Elastic-job-lite并无作业调度中心节点,不像我们谈到单机定时任务调度有统一的排序队列,它是基于部署作业框架的程序在到达相应时间点时各自触发调度。注册中心仅用于作业注册和监控信息存储,而主作业节点仅用于处理分片和清理的功能。
2、实现弹性扩容
通过zookeeper来动态给job节点分片。如果很大体量的用户需要我们在特定的时间段内计算完成,那么我们肯定是希望我们的任务可以通过集群达到水平的扩展,集群里的每个节点都处理部分的用户,不管用户的数量有多大,我们只需要增加机器就可以了。
举个例子:比如我们希望3台机器跑job,我么将我们的任务分成3片,框架通过zk的协调,最终会让3台机器分配到0,1,2的任务片,比如server0->0、server1->1、server2->2,当server0执行时,可以只查询id%30的用户,server1可以只查询id%31的用户,server2可以只查询id%3==2的用户。

在以上的基础上再增加一个server3,此时,server3分不到任何的分片,没有分到任务分片的程序将不执行。如果此时server2挂了,那么server2被分到的任务分片将会分配给server3,所以server3就会代替server2执行。如果此时server3也挂了,那么框架也会自动的将server3的任务分片随机分配到server0或者server1,那么就可能成:server0->0、server1->1,2。

这样就没有基于数据库的锁冲突问题,也可以实现水平扩展

不过也是有问题的
1、分片数是由业务代码层决定,调度执行协调时没法进一步优化,比较静态,机器扩容后其实没法直接用到扩容后的性能
2、缺乏统一调度,每个调度任务有重复的调度开销(检测任务trigger),并且在实现复杂的dag调度时,只能把所有业务调度写在一个实现中,不够灵活。

阿里的定时任务框架

1、早期是:TBSchedule

也是基于Zk做注册中心
优点:是支持集群、分布式,灵活的任务分片,并且有动态的服务扩容和资源回收
缺点:使用的是Timer而不是线程池执行任务调度。TBSchedule的作业类型比较单一,只能是获取/处理数据一种模式,而且目前文档偏少

####2、目前推出了基于Akka架构的Schedulerx2.0
新一代定时任务,提供分布式执行、多种任务类型、统一日志等框架,用户只要依赖schedulerx-worker这个jar包,通过schedulerx2.0提供的编程模型,简单几行代码就能实现一套高可靠可运维的分布式执行引擎。在海量数据并行任务、复杂dag调度

可扩展的执行引擎

Worker总体架构参考Yarn的架构,分为TaskMaster, Container, Processor三层:

image

  • TaskMaster:类似于yarn的AppMaster,支持可扩展的分布式执行框架,进行整个jobInstance的生命周期管理、container的资源管理,同时还有failover等能力。默认实现StandaloneTaskMaster(单机执行),BroadcastTaskMaster(广播执行),MapTaskMaster(并行计算、内存网格、网格计算),MapReduceTaskMaster(并行计算、内存网格、网格计算)。
  • Container:执行业务逻辑的容器框架,支持线程/进程/docker/actor等。
  • Processor:业务逻辑框架,不同的processor表示不同的任务类型。

以MapTaskMaster为例,大概的原理如下图所示:

image

其借鉴了MapReduce的模式,支持Map、MapReduce模型,在海量数据分发多台机器的效率上非常方便,支持分布跑批,针对不同的跑批场景,map模型作业还提供了并行计算、内存网格、网格计算三种执行方式:

并行计算:子任务300以下,有子任务列表。
内存网格:子任务5W以下,无子任务列表,速度快。
网格计算:子任务100W以下,无子任务列表。

并行计算实例

考拉的kSchedule

这里再说一个考拉的分布式定时任务框架kSchedule,大体与elastic-job类似,
kschedule的部署架构

这里说一点,kSchedule的无侵入性做的更好,对于简单任务不需要事先Job接口,只需要把任务bean注册成容器的Service的public方法即可,然后再配置界面配置调度任务的方法和参数即可,大大的方便的简单任务的开发和配置工作;(其实就是实现了普通类的方法级别的定时任务配置,而一般的定时任务都是类继承Job类,重写execute方法)

这点在其他框架中实现时需要写个简单任务的调度分配任务,然后把普通类的方法和入参作为动态参数传到调度分配任务,然后利用反射,进行动态执行。

4、综合比较选型

简单几条原则
1、业务起步阶段:没有自主研发运维能力,选择业界使用最多最成熟的,最好是直接买,比如阿里云的Schedulerx2.0,把技术、运维都交给阿里云,只开发业务逻辑即可;或者Elastic-job-cloud版本,在私有云上部署,功能支持也比较完善,花钱都能解决
2、业务发展阶段:数据规模和任务规模都在扩大,有一定的研发能力,可以考虑接入成熟开源框架,比如quartz或者Elastic-job-lite都是开源的,几台机器搭建起来就可以跑,出问题了开源用解答的也比较多。每秒几千个任务没问题
3、业务成熟阶段:每秒任务扩大到几万、几十万个,而且业务个性化需要越来越多,比如各种调度策略,批处理任务的个性化支持,这时候要选择一个开源框架的基础上进行二次开发,目前quartz或者Elastic-job-lite都是不错的选择

具体的对比表格
各个框架对比文档—转自:分布式调度框架大集合

5、参考文章

分布式调度框架大集合
详解应对平台高并发的分布式调度框架TBSchedule
Quartz架构整理
开源的作业调度框架Quartz
考拉定时任务框架kSchedule
Schedulerx2.0分布式计算原理&最佳实践

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/hitzbb/article/details/106989669

智能推荐

步进电机丢步与闭环控制_步进电机闭环控制算法_wotaifuzao的博客-程序员宅基地

1.步进电机失步概念步进电动机正常工作时,每接收一个控制脉冲就移动一个步距角,即前进一步。若连续地输入控制脉冲,电动机就相应地连续转动。步进电动机失步包括丢步和越步。丢步时,转子前进的步数小于脉冲数;越步时,转子前进的步数多于脉冲数。一次丢步和越步的步距数等于运行拍数的整数倍。丢步严重时,将使转子停留在一个位置上或围绕一个位置振动,越步严重时,机床将发生过冲。2.丢步原因及策略(1)转子的...

前端开发的小细节_chuolizha8294的博客-程序员宅基地

雯雯木今天和大家分享下head标签里的一些小秘密:1,优先使用 IE 最新版本和 Chrome:<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />2,360 使用Google Chrome Frame...

RT-Thread嵌入式操作系统_rt thread_云-生的博客-程序员宅基地

RT-Thread嵌入式操作系统 1一、系统架构二、文件结构1、RT-Thread 完整版2、RT-Thread Nano版3 源文件的文件说明4 移植后的文件层次三、系统启动四、用户代码一、系统架构  RT-Thread,全称是 Real Time-Thread,顾名思义,它是一个嵌入式实时多线程操作系统。  RT-Thread 主要采用 C 语言编写,浅显易懂,方便移植。它把面向对象的设计方法应用到实时系统设计中,使得代码风格优雅、架构清晰、系统模块化并且可裁剪性非常好。针对资源受限的微控制器(

git创建本地远程仓库_git建立远程仓库_Mr_lee123的博客-程序员宅基地

一、创建远程仓库(1)在磁盘内新建一个仓库文件夹,名称自定义,我这里是“GIT”(此仓库等同于github内新建的远程仓库)。(2)创建仓库打开“GIT”文件夹--右键“git creat repository here”如果这个仓库仅作为仓库使用,可勾选“make it bare”,如果要在这个文件夹内工作就不勾选。仓库创建成功二、clone仓库在空项...

恶意代码分析实战06-01_Elwood Ying的博客-程序员宅基地

本次实验我们将会分析lab19-2文件。先来看看要求解答的问题Q1.这段shellcode被注入到什么进程中?Q2.这段shellcode位于哪里?Q3.这段shellcode是如何被编码的?Q4.这段shellcode手动导入了哪个函数?Q5.这段shellcode和什么网络主机进行通信?Q6.这段shellcode做了什么?首先载入IDA第一处call是调用sub_4010b0,跟入该函数从其关键函数调用可知,这个函数为当前进程提供合适的权限,使其允许调试返回main接着是调

STM32—SPI详解_stm32spi配置_WangLanguager的博客-程序员宅基地

一.什么是SPISPI是串行外设接口(Serial Peripheral Interface)的缩写,SPI是一种高速、全双工、同步通信的通信总线,被广泛应用在ADC、LCD等与MCU的通信过程中,特点就是快。二.SPI协议就像IIC、串口一样,SPI也有其通信协议,我们一般按照分层的思想来学习SPI的协议,主要分为物理层和协议层。物理层首先看一下SPI通信设备之间的常用连接方式,主机和从机之间通过三条总线和片选线组成:NSS:片选设备线,每个从机都有自己的一条单独的总线与主机连接,此总线的作用就是为主机选

随便推点

【深度学习系列】用Tensorflow进行图像分类_图像分类tensorflow_一代人78的博客-程序员宅基地

  上个月发布了四篇文章,主要讲了深度学习中的“hello world”----mnist图像识别,以及卷积神经网络的原理详解,包括基本原理、自己手写CNN和paddlepaddle的源码解析。这篇主要跟大家讲讲如何用PaddlePaddle和Tensorflow做图像分类。所有程序都在我的github里,可以自行下载训练。  在卷积神经网络中,有五大经典模型,分别是:LeNet-5,AlexNet,GoogleNet,Vgg和ResNet。本文首先自己设计一个小型CNN网络结构来对图像进行分类,再了解

HP LoadRunner 12.02 Tutorial T7177-88037教程独家中文版_aab438346的博客-程序员宅基地

LoadRunner 12.02教程独家中文版 Tylan独家呕血翻译转载请注明出自“天外归云”的博客园Welcome to the LoadRunner TutorialLoadRunner所包含的组件如下所示:Vugen:Virtual User Generator,虚拟用户发生器的简称,用来录制用户的业务流程,创建自动化性能测试脚本,亦称之为...

深入浅出JVM_vinoYang的博客-程序员宅基地

JVM 内部关键组件以及相关机制、原理简介。

[lambda]使用forEach导致项目启动报错java.lang.ArrayIndexOutOfBoundsException: 20993_用lamdba表达式写启动项目会报错_暮念朝兮的博客-程序员宅基地

web项目应用开发时,在一个bean中定义了一个实例方法,并使用forEach对实例方法中的一个局部List集合遍历,产生如下报错完整报错信息Failed startup of context [email protected]{/vipSystem,D:\gaotime-vip-online\gaotime-admin\webapps\vipSystem\src\main\webapp}java.lang.ArrayIndexOutOf.

开源网络框架_xiaohao_880的博客-程序员宅基地

Ion Retrofit Volley Glide Picasso Fresco

推荐文章

热门文章

相关标签