关于任务调度:亿级异构任务调度框架设计与实践

背景阿里云日志服务作为云原生可观测与剖析平台。提供了一站式的数据采集、加工、查问剖析、可视化、告警、生产与投递等性能。全面晋升用户的研发、运维、经营、平安场景的数字化能力。 日志服务平台作为可观测性平台提供了数据导入、数据加工、汇集加工、告警、智能巡检、导出等性能,这些性能在日志服务被称为工作,并且具备大规模的利用,接下来次要介绍下这些工作的调度框架的设计与实际。 本次介绍次要分为四个局部: 任务调度背景可观测性平台的亿级任务调度框架设计任务调度框架在日志服务的大规模利用瞻望任务调度背景通用调度调度 在计算机外面是一个十分常见的技术,从单机到分布式再到大数据系统,调度的身影无处不在。这里尝试总结出调度的一些独特特色。 操作系统:从单机操作系统Linux来看,内核通过工夫片的形式来管制过程在处理器上的执行工夫,过程的优先级与工夫片挂钩,简略来说,过程的在单CPU或者某个CPU的执行由调度器来把握;K8s被称为分布式时代的操作系统,在Pod创立后,K8s的管制面调度器通过对节点进行打分排序,最终选出适宜的Node来运行Pod。大数据分析系统:从最早的MapReduce应用偏心调度器反对作业的优先级和抢占,到SQL计算引擎Presto通过Coordinator的调度器将执行打算中的任务分配到适宜的worker上来执行,Spark通过DAGScheduler拆分成Stage,TaskScheduler将Stage对应的TaskSet最终调度到适宜的Worker上来执行。任务调度框架:在数据处理中常见的ETL解决工作、定时工作,这些工作具备多模的特点:定时执行、继续运行、一次性执行等。在工作执行过程中须要思考工作的编排和状态一致性问题。 这里简略的对调度做一个形象,如上图所示,调度负责将不同的Task调配到不同的Resource上执行,Task能够是过程、Pod、子工作;Resource为具体执行Task工作的资源,能够是处理器、线程池、节点、机器。通过这个形象,能够看出调度在零碎中的地位。 调度的覆盖面很广,本文次要集中在任务调度框架的设计与实际,这里先通过一些例子来看下任务调度的一些特点,以下次要讲工作分为定时类的工作和依赖类的工作两种来开展。 任务调度定时类工作 定时执行能够了解为每个工作之间有工夫先后顺序,并且要在特定的工夫点执行,比方每隔1小时对日志进行监控,00点的监控工作须要首先执行,01点的监控工作须要在01点准时执行;同样,相似的定时场景,还有仪表盘订阅、定时计算等。 依赖类工作 除了定时执行,还有另外一种编排模式,比方程序依赖,各个工作之间有先后执行的依赖,也叫Pipeline形式,还有一种比拟常见的编排模式,拓扑依赖,也称为DAG,比方Task2/Task3须要等到Task1执行实现才能够执行,Task5须要等到Task3/Task4执行完才能够执行。 任务调度特点任务调度在执行的过程中须要尽可能平衡的将工作分派到适合的机器或者执行器下来执行,比方要依据执行器的以后负载状况,要依据工作本身的特色进行分派执行;在执行器执行的过程中也可能会解体,退出,这时候须要将工作迁徙到其余的执行器中。整个调度过程须要思考到调度策略、FailOver、工作迁徙等。接下来来看下任务调度的一个简略利用。 任务调度利用:一条日志的历险 上图中原始日志为一条Nginx拜访日志,其中包含IP、工夫、Method、URL、UserAgent等信息,这样一些原始日志并不利于咱们进行剖析,比方咱们想统计拜访最高的Top 10 URL,通过命令解决是这样的: cat nginx_access.log |awk '{print $7}'| sort|uniq -c| sort -rn| head -10 | more 抛开命令的复杂性和原始日志的数据量不谈,即便需要略微变动,命令就须要大量的改变,十分不利于保护,对日志进行剖析的正确形式必然是应用分布式日志平台进行日志剖析,原始日志蕴含着大量“信息”,然而这些信息的提取是须要一系列的流程。 首先是数据采集、须要通过Agent对散布在各个机器上的数据进行集中采集到日志平台,日志采集上来后须要进行荡涤,比方对于Nginx拜访日志应用正则提取,将工夫、Method、URL等重要信息提取进去作为字段进行存储并进行索引构建,通过索引,咱们能够应用类SQL的剖析语法对日志进行剖析、例如查看拜访的Top 10 URL,用SQL来表白就会十分简洁清晰: select url, count(1) as cnt from log group by url order by cnt desc limit 10 业务零碎只有在服务,日志就会一直产生,能够通过对流式的日志进行巡检,来达到零碎异样的检测目标,当异样产生时,咱们能够通过告警告诉到零碎运维人员。 通用流程提取从这样一个日志剖析零碎能够提取出一些通用的流程,这些通用的流程能够概括为数据摄入、数据处理、数据监测、数据导出。 除了日志,零碎还有Trace数据、Metric数据,它们是可观测性零碎的三大支柱。这个流程也实用于可观测性服务平台,接下来来看下一个典型的可观测服务平台的流程形成。 典型可观测服务平台数据流程 数据摄入:在可观测服务平台首先须要扩大数据起源,数据源可能包含各类日志、音讯队列Kafka、存储OSS、云监控数据等,也能够包含各类数据库数据,通过丰盛数据源的摄入,能够对系统有全方位的观测。数据处理:在数据摄入到平台后,须要对数据进行荡涤、加工,这个过程咱们把他统称数据处理,数据加工能够了解为数据的各种变换和富华等,汇集加工反对对数据进行定时rolling up操作,比方每天计算过来一天汇总数据,提供信息密度更高的数据。数据监测:可观测性数据自身反馈了零碎的运行状态,零碎通过对每个组件裸露特定的指标来裸露组件的衰弱水平,能够通过智能巡检算法对异样的指标进行监控,比方QPS或者Latency的陡增或陡降,当出现异常时能够通过告警告诉给相干运维人员,在指标的根底上能够做出各种运维或者经营的大盘,在每天定时发送大盘到群里也是一种场景的需要。数据导出:可观测性数据的价值往往随着工夫产生衰减,那么对于长时间的日志类数据出于留档的目标能够进行导出到其余平台。从以上四个过程咱们能够形象出各类工作,别离负责摄入、解决、检测等,比方数据加工是一种常驻工作,须要继续对数据流进行解决,仪表盘订阅是一种定时工作,须要定时收回仪表盘到邮件或者工作群中。接下来将要介绍对各类工作的调度框架。 可观测性平台的亿级任务调度框架设计可观测平台工作特点依据上面对可观测平台工作的介绍,能够总结一个典型的可观测平台的工作的特点: 业务简单,工作类型多:数据摄入,仅数据摄入单个流程波及数据源可能有几十上百个之多。用户量大,工作数数量多:因为是云上业务,每个客户都有大量的工作创立需要。SLA要求高:服务可用性要求高,后盾服务是降级、迁徙不能影响用户已有工作的运行。多租户:云上业务客户互相间接不能有影响。可观测平台任务调度设计指标 依据平台工作的特点,对于其调度框架,咱们须要达到上图中的指标 反对异构工作:告警、仪表盘订阅、数据加工、汇集加工每种工作的特点不一样,比方告警是定时类工作、数据加工是常驻类工作,仪表盘订阅预览是一次性工作。海量任务调度:对于单个告警工作,如果每分钟执行一次,一天就会有1440次调度,这个数量乘以用户数再乘以工作数,将是海量的任务调度;咱们须要达到的指标是工作数的减少不会对打爆机器的性能,特地是要做到程度扩缩容,工作数或者调度次数减少只须要线性减少机器即可。高可用:作为云上业务,须要达到后盾服务降级或者重启、甚至宕机对用户工作运行无影响的目标,在用户层面和后盾服务层面都须要具备工作运行的监控能力。简略高效的运维:对于后盾服务须要提供可视化的运维大盘,能够直观的展现服务的问题;同时也要对服务进行告警配置,在服务降级、公布过程中能够尽量无人值守。多租户:云上环境是人造有多租户场景,各个租户之间资源要做到严格隔离,相互之间不能有资源依赖、性能依赖。可扩展性:面对客户的新增需要,将来须要反对更多的工作类型,比方曾经有了MySQL、SqlServer的导入工作,在将来须要更多其余的数据库导入,这种状况下,咱们须要做到不批改任务调度框架,只须要批改插件即可实现。API化:除了以上的需要,咱们还须要做到工作的API化管控,对于云上用户,很多海内客户是应用API、Terraform来对云上资源做管控,所以要做到工作治理的API化。可观测平台任务调度框架总体概览基于上述的调度设计指标,咱们设计了可观测性任务调度框架,如上图所示,上面从下到上来介绍。 存储层:次要包含工作的元数据存储和工作运行时的状态和快照存储。工作的元数据次要包含工作类型,工作配置、任务调度信息,都存储在了关系型数据库;工作的运行状态、快照存储在了分布式文件系统中。服务层:提供了任务调度的外围性能,次要包含任务调度和工作执行两局部,别离对应后面讲的工作编排和工作执行模块。任务调度次要针对三种工作类型进行调度,包含常驻工作、定时工作、按需工作。工作执行反对多种执行引擎,包含presto、restful接口、K8s引擎和外部自研的ETL 2.0零碎。业务层:业务层包含用户间接在控制台能够应用到的性能,包含告警监控、数据加工、重建索引、仪表盘订阅、汇集加工、各类数据源导入、智能巡检工作、和日志投递等。接入层:接入层应用Nginx和CGI对外提供服务,具备高可用,地区化部署等个性。API/SDK/Terraform/控制台:在用户侧,能够应用控制台对各类工作进行治理,对于不同的工作提供了定制化的界面和监控,同时也能够应用API、SDK、Terraform对工作进行增删改查。工作可视化:在控制台咱们提供了工作执行的可视化和工作监控的可视化,通过控制台用户能够看出看到工作的执行状态、执行历史等,还能够开启内置告警对工作进行监控。任务调度框架设计要点接下来从几方面对任务调度框的设计要点进行介绍,次要包含以下几方面来介绍: 异构任务模型形象调度服务框架大规模工作反对服务高可用设计稳定性建设任务模型形象 接下来看下任务模型的形象: 对于告警监控、仪表盘订阅、汇集加工等须要定时执行的工作,形象为定时工作,反对定时和Cron表达式设置。对于数据加工、索引重建、数据导入等须要继续运行的工作,形象为常驻工作,这类工作往往只须要运行一次,能够有也能够没有完结状态。对于数据加工的预览、仪表盘订阅的预览等性能,是在用户点击时才会须要创立一个工作来执行,执行实现即可退出,不须要保留工作状态,这类工作形象为DryRun类型,或者按需工作。调度服务框架 服务根底框架应用了Master-Worker架构,Master负责工作的分派和Worker的管控,Master将数据抽象为若干Partitions,而后将这些Partitions分派给不同的Worker,实现了对工作的分而治之,在Worker执行的过程中Master还也能够依据Worker的负载进行Partitions的动静迁徙,同时在Worker重启降级过程中,Master也会对Partition进行移出和移入; 工作的调度次要在Worker层来实现,每个Worker负责拉取对应Partitions的工作,而后通过JobLoader对工作进行加载,留神:这里只会加载以后Worker对应Partitions的工作列表,而后Scheduler对工作进行调度的编排,这里会波及常驻工作、定时工作、按需工作的调度,Scheduler将编排好的工作发送到JobExecutor进行执行,JobExecutor在执行的过程中须要实时对工作的状态进行长久化保留到RedoLog中,在下次Worker降级重新启动的过程中,须要从RedoLog中加载工作的状态,从而保障工作状态的准确性。 ...

November 29, 2022 · 1 min · jiezi

关于任务调度:挑战海量数据基于Apache-DolphinScheduler对千亿级数据应用实践

点亮 ⭐️ Star · 照亮开源之路 GitHub:https://github.com/apache/dol... 精彩回顾 近期,初灵科技的大数据开发工程师钟霈合在社区活动的线上 Meetup 上中,给大家分享了《基于 Apache DolphinScheduler 对千亿级数据的利用实际》主题演讲。 咱们对于千亿级数据量的数据同步需要,进行剖析和选型后,初灵科技最终决定应用DolphinScheduler进行任务调度,同时须要周期性调度 DataX、SparkSQL 等形式进行海量数据迁徙。在日常大数据工作中,利用DolphinScheduler缩小日常运维工作量。 讲师介绍 钟霈合 初灵科技 大数据开发工程师 演讲纲要: 背景介绍海量数据处理利用场景将来的布局背景介绍01 自研任务调度咱们公司后期始终是用的自研的任务调度框架,随着这个调度畛域开源软件的倒退,涌现了很多像海豚调度这样十分优良的任务调度零碎,而咱们的需要曾经到了必须要引入新的任务调度零碎水平,来保障技术的更新迭代。 02 需要剖析1、反对多租户的权限管制 咱们在日常工作中不止研发会进行工作的调度,其余的业务部门和厂商都可能会在DS上跑一些工作,如果没有多租户的权限管制的话,那整个集群应用起来都会十分的凌乱。 2、上手简略,反对可视化工作治理 上手简略,因为咱们团队外部在很多时候,开发会给到数仓/业务团队去应用,如果任务调度上手十分艰难,如果须要进行大量的配置或者编写代码,绝对老本就要高很多,置信在很多大数据团队都会存在这个需要,并且有些我的项目须要疾速迭代,所以对于选型的工具必然是上手简略的。 3、反对对工作及节点状态进行监控 咱们对任务调度原生监控次要有两点需要,第一是服务器的监控,能够间接通过任务调度web页面去看,第二是任务调度的监控,针对工作是否胜利、执行工夫等相干数据和状态可能高深莫测。 4、反对较为不便的重跑、补数 咱们数据有实时、周期和离线三局部的,数据个性产生了这个需要,比方对于每15分钟或者每小时的数据工作,如果不能很好的反对重跑和补数的话,对咱们影响还是比拟大的。 5、反对高可用HA、弹性扩容、故障容错 集群运维和故障治理方面也是须要反对的。 6、反对工夫参数 有时候须要基于工夫参数进行数据的ETL周期操作。 03 任务调度比照 Crontab 在Unix和类Unix零碎中周期性地执行指令或脚本,用来在Linux上间接执行脚本,但只能用来运行脚本。 不反对多租户权限治理、平台治理、散发执行等性能,在咱们公司中的利用是在一些特点服务器跑一些长期的脚本。 并且原生Crontab只反对分钟级别的调度,不反对重跑。 Rundeck Rundeck是一个基于Java和Grails的开源的运维自动化工具,提供了Web治理界面进行操作,同时提供命令行工具和WebAPI的访问控制形式。 像Ansible之类的工具一样,Rundeck可能帮忙开发和运维人员更好地治理各个节点。 分为企业版和免费版,免费版对于咱们来说性能还是有点欠缺的。 Quartz Quartz 是一款开源且丰盛个性的任务调度库,是基于Java实现的任务调度框架,可能集成与任何的java利用。 须要应用Java编程语言编写任务调度,这对于非研发团队而言,是无奈去推广应用的。 xxl-job 是一款国产开发的轻量级散布式调度工具,但性能比海豚调度少。 其不依赖于大数据组件,而是依赖于MySQL,和海豚调度的依赖项是一样的。 Elastic-Job 是基于Quartz 二次开发的弹性分布式任务调度零碎,初衷是面向高并发且简单的工作。 设计理念是无中心化的,通过ZooKeeper的选举机制选举出主服务器,如果主服务器挂了,会从新选举新的主服务器。 因而elasticjob具备良好的扩展性和可用性,然而应用和运维有肯定的复杂度。 Azkaban Azkaban也是一个轻量级的任务调度框架,但其毛病是可视化反对不好,工作必须通过打一个zip包来进行实现,不是很不便。 AirFlow AirFlow是用Python写的一款任务调度零碎,界面很高大上,但不符合中国人的应用习惯。 须要应用Python进行DAG图的绘制,无奈做到低代码任务调度。 Oozie 是集成在Hadoop中的大数据任务调度框架,其对工作的编写是须要通过xml语言进行的。 ...

October 11, 2022 · 2 min · jiezi

关于任务调度:Tokio解析之任务调度

简介Tokio 是 Rust 世界里最驰名的异步执行框架,该框架包罗了简直所有异步执行的接口,包含但不限于文件、网络和文件系统治理。在这些方便使用的高层接口之下则是一些“基石”,他们并不存在于用户间接交互的接口中,而是藏于表层之下默默实现工作。这其中就包含了线程池,执行异步工作的根本单元,本文就来介绍一下 tokio 的线程池及其调度,尽可能阐明其中乏味的关键点。本文波及的代码次要在 tokio/src/runtime 下。 线程池线程池的概念在许多语言中都有,个别大家应用线程池的起因是缩小创立和销毁线程带来的性能损失。在 tokio 中线程池被用作执行异步 task 的执行资源,例如下列代码其实就是创立了一个异步工作放到了 tokio 线程池中: tokio::spawn( // This is an async task async { ... });至于如何寄存这些 task,有几种不言而喻的抉择(并非只有这几种): 将所有的待执行 task 都放到一个公共的队列中(即全局队列),每个线程都从这个队列中拿取信息。每个线程本人一个独立队列,只抓取本人队列中的 task 执行,队列中 task 空了就歇着。每个线程本人一个独立队列,首先抓取本人队列中的 task 执行,如果本人的队列为空,则从其余线程的队列中偷取。第一种实现很蹩脚,无论如何优化那个公共队列——用锁或者原子操作——竞争带来的性能降落是无奈防止的。这里须要指明一点,用原子操作并不是没有竞争,原子操作是将竞争放到了硬件,竞争多了效率依然不好。 第二种实现也不太好,当一个线程堆满工作时,他的工作来不及执行,而其余闲暇线程“无事可做”,造成线程间的不平等。这种不平等也会使得多线程并行执行的劣势施展不进去。 第三种实现则是当初罕用的“工作偷取(Work Stealing)”形式,该办法防止了上述两种办法的问题,但在实现细节上依然有许多值得优化的中央。 Work Steal如何能力高效Work Steal 的实现办法尽管很间接,然而有个问题依然无奈防止,存在两个或者多个线程同时从一个队列中拿取 task。想要线程平安,要么采纳锁,要么采纳无锁数据结构。Tokio 在晚期版本中采纳了基于 crossbeam 的无锁队列,然而 Tokio 作者认为这种实现依然太重了(epoch-based gc 依然效率不高,此为 Tokio 作者观点,本文作者未试验论证),因而之后采纳了当初的实现办法。 当初 Tokio 工作队列实现依然是无锁的,采纳的是环形队列数据结构,即 ring buffer。该数据结构为了可能晓得哪些 slot 曾经被应用,个别会应用两个 index —— head 和 tail,从 tail 初放入 item,从 head 处拿出 item,如下图所示: ...

October 7, 2022 · 2 min · jiezi

关于任务调度:实现一个任务调度系统看这篇就够了

浏览一篇「定时工作框架选型」的文章时,一位网友的留言电到了我: 我看过那么多所谓的教程,大部分都是教“如何应用工具”的,没有多少是教“如何制作工具”的,能教“如何仿造工具”的都曾经是百里挑一,中国 软件行业,缺的是真正能够“制作工具”的程序员,而相对不缺那些“应用工具”的程序员! ...... ”这个业界最不须要的就是“会应用XX工具的工程师”,而是“有创造力的软件工程师”!业界所有的饭碗,实质就是“有创造力的软件工程师”提供进去的啊!写这篇文章,想和大家从头到脚说说任务调度,心愿大家读完之后,可能了解实现一个任务调度零碎的外围逻辑。 1 QuartzQuartz是一款Java开源任务调度框架,也是很多Java工程师接触任务调度的终点。 下图显示了任务调度的整体流程: Quartz的外围是三个组件。 工作:Job 用于示意被调度的工作;触发器:Trigger 定义调度工夫的元素,即依照什么工夫规定去执行工作。一个Job能够被多个Trigger关联,然而一个Trigger 只能关联一个Job;调度器 :工厂类创立Scheduler,依据触发器定义的工夫规定调度工作。 上图代码中Quartz 的JobStore是 RAMJobStore,Trigger 和 Job 存储在内存中。 执行任务调度的外围类是 QuartzSchedulerThread 。 调度线程从JobStore中获取须要执行的的触发器列表,并批改触发器的状态;<font color="red">Fire</font>触发器,批改触发器信息(下次执行触发器的工夫,以及触发器状态),并存储起来。最初创立具体的执行工作对象,通过worker线程池执行工作。接下来再聊聊 Quartz 的集群部署计划。 Quartz的集群部署计划,须要针对不同的数据库类型(MySQL , ORACLE) 在数据库实例上创立Quartz表,JobStore是: JobStoreSupport 。 这种计划是分布式的,没有负责集中管理的节点,而是利用数据库行级锁的形式来实现集群环境下的并发管制。 scheduler实例在集群模式下首先获取{0}LOCKS表中的行锁,Mysql 获取行锁的语句: {0}会替换为配置文件默认配置的QRTZ_。sched_name为利用集群的实例名,lock_name就是行级锁名。Quartz次要有两个行级锁触发器拜访锁 (TRIGGER_ACCESS) 和 状态拜访锁(STATE_ACCESS)。 这个架构解决了工作的散布式调度问题,同一个工作只能有一个节点运行,其余节点将不执行工作,当碰到大量短工作时,各个节点频繁的竞争数据库锁,节点越多性能就会越差。 2 分布式锁模式Quartz的集群模式能够程度扩大,也能够散布式调度,但须要业务方在数据库中增加对应的表,有肯定的强侵入性。 有不少研发同学为了防止这种侵入性,也摸索出分布式锁模式。 业务场景:电商我的项目,用户下单后一段时间没有付款,零碎就会在超时后敞开该订单。 通常咱们会做一个定时工作每两分钟来查看前半小时的订单,将没有付款的订单列表查问进去,而后对订单中的商品进行库存的复原,而后将该订单设置为有效。 咱们应用Spring Schedule的形式做一个定时工作。 @Scheduled(cron = "0 */2 * * * ? ")public void doTask() { log.info("定时工作启动"); //执行敞开订单的操作 orderService.closeExpireUnpayOrders(); log.info("定时工作完结"); }在单服务器运行失常,思考到高可用,业务量激增,架构会演进成集群模式,在同一时刻有多个服务执行一个定时工作,有可能会导致业务错乱。 解决方案是在工作执行的时候,应用Redis 分布式锁来解决这类问题。 @Scheduled(cron = "0 */2 * * * ? ")public void doTask() { log.info("定时工作启动"); String lockName = "closeExpireUnpayOrdersLock"; RedisLock redisLock = redisClient.getLock(lockName); //尝试加锁,最多期待3秒,上锁当前5分钟主动解锁 boolean locked = redisLock.tryLock(3, 300, TimeUnit.SECONDS); if(!locked){ log.info("没有取得分布式锁:{}" , lockName); return; } try{ //执行敞开订单的操作 orderService.closeExpireUnpayOrders(); } finally { redisLock.unlock(); } log.info("定时工作完结");} ...

January 24, 2022 · 2 min · jiezi

关于任务调度:任务调度系统系列之Airflow

这是任务调度零碎调研系列文章的开篇,后续会陆续调研Oozie,Azkaban,Dolphin Scheduler等零碎。本文的次要内容是来自对官网文档和网上相干材料的调研,并非基于理论应用的经验总结,文章中难免会有一些不尽的细节或者对于Airflow谬误的观点,如有不当之处,欢送斧正交换。 Airflow是一个基于Python开发的,通过编程的形式创立、调度和监控工作流(workflow)的平台。最早由Maxime Beauchemin于2014年10月在Airbnb创立,并且从创立之初就以开源的模式开发。2016年3月进入Apache基金孵化器,2019年1月正式成为Apache顶级我的项目。 官网文档中,特意强调了应用代码定义工作流的长处,使得工作流的保护、版本治理、测试和合作变得更加容易,间接复用代码开发过程中用到工具、零碎就能够了,无需再反复造轮子,能够像开发软件系统一样开发数据工作,继续集成也是开箱即用。然而数据工作的测试向来不是一件简略的事件,不晓得在理论应用中基于Airflow的数据开发CI/CD晦涩度如何。这种基于Python代码定义工作流的形式应用门槛略微高了一点。基于代码定义flow中节点的依赖关系,并不如通过界面拖拽那么直观,是不是也会使易用性大大折扣? 架构如上图所示,Airflow次要由以下几个局部组成: DAG目录(DAG Directory)存储定义DAG的Python文件的目录,调度器、执行器和执行节点会读取该目录下的文件获取DAG相干信息,所以要确保所有节点上DAG目录的数据同步。如何确保文件同步到也是一项简单的工程。 数据库(Metadata Database)数据库次要用于存储系统的配置信息(零碎变量,数据源链接信息,用户信息等)、解析DAG文件生成的DAG对象和工作执行的状态等信息。 调度器(Scheduler)独立部署的过程,负责触发执行定时调度的工作流。调度器次要负责两件事:1)定时扫描DAG文件目录,解析变更或新增的DAG文件,并将解析后生成的DAG对象(Serialized DAG)存储到数据库;2)扫描数据库中的DAG对象,如果满足调度执行条件,则触发生成工作实例并提交给Executor执行。 调度器高可用从2.0开始,Airflow调度器反对高可用部署,采纳了我之前实现调度服务高可用时应用的策略,通过数据库行锁的机制,实现多主的高可用。这样实现的益处是缩小了leader选举、节点故障转移的复杂度。多个节点同时工作相较于主从模式也能获取较好的解决性能,能够通过横向扩大调度器晋升调度服务的解决能力,但究竟要受限于底层单点数据库的解决能力。如果执行事务的时长比拟久,特地是事务中存在校验并发限度、资源应用配额的操作时,就很容易造成死锁,所以在Airflow理论部署中,高可用对数据库有着非凡的要求,须要数据库反对SKIP LOCKED或者NOWAIT。 执行器(Executor)执行器负责执行或者提交执行工作实例(Task Instances)。执行器在理论部署中集成在调度器过程内,Airflow提供了两种类型的执行器,1)本地执行器,工作间接在调度器所在节点上执行;2)近程执行器,依据各执行器的实现形式,将工作提交到近程执行节点上执行。如果零碎自带的执行器无奈满足你的业务需要,能够自行实现自定义执行器。 零碎自带本地执行器: Debug Executor: 次要用于在IDE中对工作进行测试执行。Local Executor:在调度器本地新建过程执行工作实例,能够通过parallelism参数管制最大工作并发数。Sequential Executor: 能够了解为最大并发数1的Local Executor。零碎自带近程执行器: Celery Executor:Celery是一个基于Python开发的分布式异步音讯工作队列,通过它能够轻松的实现工作的异步解决。Celery Executor将工作发送到音讯队列(RabbitMQ, Redis等),而后 Celery Worker 从音讯队列中生产执行工作,并将执行后果写入到Celery的Backend中。Celery Executor 通过队列(queues)实现资源隔离,定义工作时指定应用的具体队列,则该工作只能由相应队列的worker执行。然而这个资源隔离的粒度有点粗,如果想实现更细粒度的资源,能够抉择 Kubernetes Executor。Kubernetes Executor: 通过K8S集群执行工作。Kubernetes Executor调用K8S API申请Worker Pod,而后由Pod负责工作的执行。CeleryKubernetes Executor:是下面两个执行器的组合,因为Airflow部署时只能指定一种类型执行器,如果既须要通过Celery执行又想提交到K8S集群执行,则能够抉择该执行器。Dask Executor: Dask是基于Python实现的分布式计算框架,Dask Executor次要是通过Dask分布式集群执行工作。近程执行时所有执行节点都会间接数据库,鉴于弹性伸缩是Airflow的一大个性,如果执行节点规模太大对数据库造成的压力不可小觑,所以为什么要采纳执行节点直连数据的形式呢? 执行节点(worker)负责具体任务的执行,依据执行器不同,可能是调度器所在节点,Celery Worker节点,K8S Pod等。 WebServer WebServer次要为用户提供了治理DAG(启用、禁用,手动执行),查看和操作DAG的执行状态,管理系统权限,查看和批改系统配置,治理数据源等性能。前文提到的通过代码定义依赖关系不直观的问题,Airflow在WebServer给了解决方案,运行DAG,而后通过WebServer的Graph视图以可视化的形式展现DAG。如果肯定要在执行前可视化的形式查看DAG也能够在命令行执行airflow dags show生成Graph视图的图片。兴许是我调研的还不够深刻,难道就没有实时可视化展现DAG的计划? 性能个性工作流定义 Airflow通过Python代码以DAG的模式定义工作流,以下代码片段定义了上图由7个工作节点组成的DAG。 // 从2021年1月1日开始,每天零点调度with DAG( "daily_dag", schedule_interval="@daily", start_date=datetime(2021, 1, 1)) as dag: ingest = DummyOperator(task_id="ingest") analyse = DummyOperator(task_id="analyze") check = DummyOperator(task_id="check_integrity") describe = DummyOperator(task_id="describe_integrity") error = DummyOperator(task_id="email_error") save = DummyOperator(task_id="save") report = DummyOperator(task_id="report") ingest >> analyse // 通过`>>`,`<<`定义节点依赖关系 analyse.set_downstream(check) // 通过`set_downstream`,`set_upstream`定义节点依赖关系 check >> Label("No errors") >> save >> report // 通过`Label`正文依赖关系 check >> Label("Errors found") >> describe >> error >> reportDAG由节点、节点间的依赖关系以及节点间的数据流组成。节点的类型次要有以下三种: ...

January 21, 2022 · 1 min · jiezi

关于任务调度:带你剖析鸿蒙轻内核任务栈的源代码

摘要:本文率领大家一起学习了鸿蒙轻内核的工作栈、工作上下文的根底概念,分析了工作栈初始化的代码。本文分享自华为云社区《鸿蒙轻内核M核源码剖析系列七 工作及任务调度(1)工作栈》,原文作者:zhushy 。 咱们本文开始要剖析下工作及任务调度模块。首先,咱们介绍下工作栈的根底概念。工作栈是高地址向低地址成长的递加栈,栈指针指向行将入栈的元素地位。初始化后未应用过的栈空间初始化的内容为宏OS_TASK_STACK_INIT代表的数值0xCACACACA,栈顶初始化为宏OS_TASK_MAGIC_WORD代表的数值0xCCCCCCCC。一个工作栈的示意图如下,其中,栈底指针是栈的最大的内存地址,栈顶指针,是栈的最小的内存地址,栈指针从栈底向栈顶方向成长。 工作上下文(Task Context)是工作及任务调度模块的另外一个重要的概念,它指的是工作运行的环境,例如包含程序计数器、堆栈指针、通用寄存器等内容。在多任务调度中,工作上下文切换(Task Context Switching)属于核心内容,是多个工作运行在同一CPU核上的根底。在任务调度时,保留退出运行状态的工作应用的寄存器信息到工作栈,还会从进入运行状态的工作的栈中读取上下文信息,复原寄存器信息。 上面,咱们分析下工作栈、工作栈初始化的源代码,若波及开发板局部,以开发板工程targets\cortex-m7_nucleo_f767zi_gcc\为例进行源码剖析。首先,看下工作上下文构造体。 1、 TaskContext上下文构造体定义在文件kernel\arch\arm\cortex-m7\gcc\los_arch_context.h中,定义的上下文的构造体如下,次要是浮点寄存器,通用寄存器。 typedef struct TagTskContext {#if ((defined(__FPU_PRESENT) && (__FPU_PRESENT == 1U)) && \ (defined(__FPU_USED) && (__FPU_USED == 1U))) UINT32 S16; UINT32 S17; UINT32 S18; UINT32 S19; UINT32 S20; UINT32 S21; UINT32 S22; UINT32 S23; UINT32 S24; UINT32 S25; UINT32 S26; UINT32 S27; UINT32 S28; UINT32 S29; UINT32 S30; UINT32 S31;#endif UINT32 uwR4; UINT32 uwR5; UINT32 uwR6; UINT32 uwR7; UINT32 uwR8; UINT32 uwR9; UINT32 uwR10; UINT32 uwR11; UINT32 uwPriMask; UINT32 uwR0; UINT32 uwR1; UINT32 uwR2; UINT32 uwR3; UINT32 uwR12; UINT32 uwLR; UINT32 uwPC; UINT32 uwxPSR;#if ((defined(__FPU_PRESENT) && (__FPU_PRESENT == 1U)) && \ (defined(__FPU_USED) && (__FPU_USED == 1U))) UINT32 S0; UINT32 S1; UINT32 S2; UINT32 S3; UINT32 S4; UINT32 S5; UINT32 S6; UINT32 S7; UINT32 S8; UINT32 S9; UINT32 S10; UINT32 S11; UINT32 S12; UINT32 S13; UINT32 S14; UINT32 S15; UINT32 FPSCR; UINT32 NO_NAME;#endif} TaskContext;2、 工作栈相干函数2.1 工作栈初始化函数在文件kernel\arch\arm\cortex-m7\gcc\los_context.c中定义了工作栈初始化函数VOID *HalTskStackInit(t()。该函数被文件kernel\src\los_task.c中的函数UINT32 OsNewTaskInit()调用实现工作初始化,并进一步在创立工作函数UINT32 LOS_TaskCreateOnly()中调用,实现新创建工作的工作栈初始化。 ...

June 9, 2021 · 3 min · jiezi

为何EasyScheduler升级v110后定时任务不调度执行

一、背景EasyScheduler升级v1.1.0后,进行任务测试,发现只能调度执行新的定时任务,而不能调度旧的定时任务。二、那么问题来了究竟是哪里出问题了? 1.我的操作步骤出现了bug?2.EasyScheduler官方的升级脚本有问题?然而,从v1.0.3升级到v1.1.0完全是按照https://dolphinscheduler.apache.org/en-us/docs/release/upgrade.html官方手册进行操作的,所以操作步骤肯定没有问题。 经过和EasyScheduler负责人沟通后,确定是升级程序的一个bug,使得定时任务ID和定时触发器关联失败,导致旧的定时任务无法被调度。 那么问题发现了,该如何快速解决呢?有遇到同样问题的朋友,给出了一种方案,先手动下线定时器然后再手动上线即可恢复。但是这个显然不可行,上千个任务如何进行手动操作?但是为了确认有效性,通过测试了一个后,发现依然无效。最终pass该种方案。 经过分析,发现EasyScheduler调度定时任务主要用到的表为qrtz_cron_triggers,qrtz_job_details,qrtz_triggers。解决方案也不麻烦,既然都关联错误了,那么直接全部清除上述三个表中数据,然后写个脚本程序,把所有项目工作流定时器进行下线再上线即可自动补全数据,这是目前最快速的解决方案。而官方修复该bug需要等到下一个版本发布,由于EasyScheduler贡献给了apapche,第一个版本还需要等待2~3个多月才能发版,所以等待不是最佳选择。 三、总结不要过分相信未经大量考研的开源产品,因为开源产品也和公司内部平台或者程序一样,都只是一套研发系统,需要经过千锤万打,才能方得始终既然使用某个开源产品,就要知己知彼,方能百战不殆定位各种问题以及快速得出最佳解决方案有一个为开源做贡献的心,每个平台起步都是艰辛的,需要我们的支持和滋养最后,希望EasyScheduler(现在的DolphinScheduler)能够越来越好!

October 23, 2019 · 1 min · jiezi

宜信开源微服务任务调度平台SIATASK入手实践

引言最近宜信开源微服务任务调度平台SIA-TASK,SIA-TASK属于分布式的任务调度平台,使用起来简单方便,非常容易入手,部署搭建好SIA-TASK任务调度平台之后,编写TASK后配置JOB进行调度,进而实现整个调度流程。本文新建了JOB示例,该JOB关联了前后级联的两个TASK,TASKONE(前置TASK)和TASKTWO(后置TASK),主要阐述一个JOB怎样关联配置两个级联TASK,以及该JOB是如何通过SIA-TASK实现任务调度,最终实现对两个TASK执行器的调用。 拓展阅读:宜信开源|宜信开源微服务任务调度平台SIA—TASK宜信开源|分布式任务调度平台SIA-TASK的架构设计与运行流程 首先,根据部署文档来搭建任务调度平台。源码地址:https://github.com/siaorg/sia... 官方文档:https://github.com/siaorg/sia... 任务调度平台主要由任务编排中心、任务调度中心以及ZK和DB等第三方服务构成,搭建SIA-TASK任务调度平台需要的主要工作包括: 1.MySQL的搭建及根据建表语句建表 2.zookeeper安装 3.SIA-TASK前端项目打包及部署 4.任务编排中心(sia-task-config)部署 5.任务调度中心(sia-task-scheduler)部署 从github上clone代码仓库并下载源码后,可根据SIA-TASK部署指南,搭建SIA-TASK任务调度平台并启动,详见SIA-TASK部署指南 搭建好SIA-TASK任务调度平台后,下一步就是TASK执行器实例的编写啦。 其次,根据开发文档来编写TASK执行器实例并启动。根据SIA-TASK开发指南,编写了两个TASK示例,TASKONE(前置TASK)和TASKTWO(后置TASK),具体开发规则见SIA-TASK开发指南,TASK示例关键配置即代码在下文有详细展示与介绍。 该示例为springboot项目,并且需要通过POM文件引入SIA-TASK的执行器关键依赖包sia-task-hunter来实现task执行器的自动抓取,首先需要将SIA-TASK源码中的sia-task-hunter包用mvn install命令打包为jar包安装至本地仓库,SIA-TASK源码中的sia-task-hunter包如下图示: 然后就可以进行示例的编写,示例主要包括以下几部分: 配置POM文件关键依赖 <!-- 此处添加个性化依赖(sia-task-hunter) --> <dependency> <groupId>com.sia</groupId> <artifactId>sia-task-hunter</artifactId> <version>1.0.0</version> </dependency>配置文件主要配置项 # 项目名称(必须) spring.application.name: onlinetask-demo # 应用端口号(必须) server.port: 10086 # zookeeper地址(必须) zooKeeperHosts: *.*.*.*:2181,*.*.*.*:2181,*.*.*.*:2181 # 是否开启 AOP 切面功能(默认为true) spring.aop.auto: true # 是否开启 @OnlineTask 串行控制(如果使用则必须开启AOP功能)(默认为true)(可选) spring.onlinetask.serial: true编写TASK执行器主要代码@Controllerpublic class OpenTestController { @OnlineTask(description = "success,无入参",enableSerial=true) @RequestMapping(value = "/success-noparam", method = { RequestMethod.POST }, produces = "application/json;charset=UTF-8") @CrossOrigin(methods = { RequestMethod.POST }, origins = "*") @ResponseBody public String taskOne() { Map<String, String> info = new HashMap<String, String>(); info.put("result", "success-noparam"); info.put("status", "success"); System.out.println("调用taskOne任务成功"); return JSONHelper.toString(info); } @OnlineTask(description = "success,有入参",enableSerial=true) @RequestMapping(value = "/success-param", method = { RequestMethod.POST }, produces = "application/json;charset=UTF-8") @CrossOrigin(methods = { RequestMethod.POST }, origins = "*") @ResponseBody public String taskTwo(@RequestBody String json) { Map<String, String> info = new HashMap<String, String>(); info.put("result", "success-param"+"入参是:"+json); info.put("status", "success"); System.out.println("调用taskTwo任务成功"); return JSONHelper.toString(info); }}当编写完TASK执行器实例后,启动该执行器所在进程启动日志如下图: ...

June 18, 2019 · 1 min · jiezi

宜信开源分布式任务调度平台SIATASK的架构设计与运行流程

一、分布式任务调度的背景无论是互联网应用或者企业级应用,都充斥着大量的批处理任务。我们常常需要一些任务调度系统来帮助解决问题。随着微服务化架构的逐步演进,单体架构逐渐演变为分布式、微服务架构。在此背景下,很多原先的任务调度平台已经不能满足业务系统的需求,于是出现了一些基于分布式的任务调度平台。 1.1 分布式任务调度的演进在实际业务开发过程中,很多时候我们无可避免地需要使用一些定时任务来解决问题。通常我们会有多种解决方案:使用 Crontab 或 SpringCron (当然这种情况可能机器很少而且任务简单又不是很多的情况下)。然而,当应用复杂度升高、定时任务数量增多且任务之间产生依赖关系时,Crontab 进行定时任务的管理配置就会非常混乱,严重影响工作效率。这时就会产生一系列问题: 任务管理混乱,生命周期无法统一协调管理;任务之间如果存在依赖关系,难以编排。随着互联网的发展,分布式服务架构势越来越流行。相应的也需要一个分布式任务调度系统来管理分布式架构中的定时任务。 1.2 分布式任务调度架构 当垂直应用越来越多,应用之间交互也会越来越复杂,通常我们采用分布式或者微服务架构,将核心业务抽取出来,形成单独的服务。一个独立的微服务群体逐渐形成稳定的服务中心,使得业务应用能更快地响应多变的市场需求。 此时,用于提高业务复用及整合的分布式服务框架成为关键。同时,由于服务独立,一般能做到定时任务独立的情况,任务的更改对于整体系统的影响小之又小。通常我们会采用任务与调度分离的方式(如上图所示),任务的执行逻辑无需关注调度与编排,同时可以保证执行器和调度的高可用,易于开发和维护。 1.3 分布式任务调度优势在分布式服务架构的基础上,由于独立业务的数量可能很多,此时如果定时任务单独在该服务中实现,很可能会出现难以管理的情况,且避免不了由于定时任务的更改而导致的业务重启。因此,一个独立的分布式任务调度系统是很必要的,可以用来全局统筹管理所有的定时任务。同时,将任务的配置单独抽离出来,作为该分布式任务调度系统的功能,就能做到定时任务的更改不影响任何业务,也不影响整个系统: 通过调度与任务分离的方式进行管理,大大降低了开发和维护成本;分布式部署,保证了系统的高可用性、伸缩性、负载均衡,提高了容错性;可以通过控制台部署和管理定时任务,方便灵活高效;任务都可以持久化到数据库,避免了宕机和数据丢失带来的隐患,同时有完善的任务失败重做机制和详细的任务跟踪及告警策略。二、分布式任务调度技术选型2.1 分布式任务调度考虑因素 任务编排:多个业务之间的定时任务存在流程次序。任务分片:对于一个大型任务,需要分片并行执行。跨平台:除了使用 Java 技术栈(SpringBoot、Spring等)的项目之外,还有使用其他语言的应用。无侵入:业务不希望与调度高耦合,只关注业务的执行逻辑。故障转移:任务执行过程中遇到问题有补偿措施,减少人工介入。高可用:调度系统自身必须保证高可用。实时监控:实时获取任务的执行状态。可视化:任务调度的操作提供可视化页面,方便使用。动态编辑:业务的任务时钟参数可能变动,不希望停机部署。2.2 SIA-TASK与其它分布式任务调度技术比较SIA是宜信公司基础开发平台Simple is Awesome的简称,SIA-TASK(微服务任务调度平台)是其中的一项重要产品,SIA-TASK契合当前微服务架构模式,具有跨平台、可编排、高可用、无侵入、一致性、异步并行、动态扩展、实时监控等特点。 开源地址:https://github.com/siaorg/sia-task 我们先对比市场上主流的开源分布式任务调度框架,分析其优缺点,然后再介绍我们的技术选型。 Quartz: Quartz 是 OpenSymphony 开源组织在任务调度领域的一个开源项目,完全基于 Java 实现。该项目于 2009 年被 Terracotta 收购,目前是 Terracotta 旗下的一个项目。相比于 JDK 或 Spring 提供的定时任务,Quartz 对单个任务的控制基本做到了极致,以其强大功能和应用灵活性,在企业应用中发挥了巨大的作用。然而 Quartz 并不支持任务的编排(任务之间有依赖),而且不支持任务分片。TBSchedule: TBSchedule 是一个支持分布式的调度框架,能让一种批量任务或者不断变化的任务,被动态地分配到多个主机的 JVM 中,不同的线程组中并行执行。基于 ZooKeeper 的纯 Java 实现,由 Alibaba 开源。TBSchedule 侧重于任务的分发,支持任务分片,但是没有任务编排,也不是跨平台的。Elastic-Job: Elastic-Job 是当当开源的一个分布式调度解决方案,由两个相互独立的子项目Elastic-Job-Lite 和 Elastic-Job-Cloud 组成。Elastic-Job 支持任务分片(作业分片一致性),但是没有任务编排,也不是跨平台的。Saturn: Saturn 是唯品会开源的分布式,高可用的调度服务。Saturn 在 Elastic-Job 做二次开发,支持监控、任务分片、跨平台,但是没有任务编排。Antares: Antares 是基于 Quartz 的分布式调度,支持分片、支持树形任务依赖,但不是跨平台的。Uncode-Schedule: Uncode-Schedule 是基于 Zookeeper 的分布式任务调度组件。支持所有任务在集群中不重复、不遗漏的执行。支持动态添加和删除任务。但是不支持任务分片,也没有任务编排,还不是跨平台的。XXL-JOB: XXL-JOB 是一个轻量级分布式任务调度平台,其核心设计目标是开发迅速、学习简单、轻量级、易扩展。XXL-JOB 支持分片,简单支持任务依赖,支持子任务依赖,不是跨平台的。下面我们简单对比下 SIA-TASK 与这些任务调度框架: ...

June 4, 2019 · 2 min · jiezi

Schedulerx20分布式计算原理最佳实践

1. 前言Schedulerx2.0的客户端提供分布式执行、多种任务类型、统一日志等框架,用户只要依赖schedulerx-worker这个jar包,通过schedulerx2.0提供的编程模型,简单几行代码就能实现一套高可靠可运维的分布式执行引擎。 这篇文章重点是介绍基于schedulerx2.0的分布式执行引擎原理和最佳实践,相信看完这篇文章,大家都能写出高效率的分布式作业,说不定速度能提升好几倍:) 2. 可扩展的执行引擎Worker总体架构参考Yarn的架构,分为TaskMaster, Container, Processor三层: TaskMaster:类似于yarn的AppMaster,支持可扩展的分布式执行框架,进行整个jobInstance的生命周期管理、container的资源管理,同时还有failover等能力。默认实现StandaloneTaskMaster(单机执行),BroadcastTaskMaster(广播执行),MapTaskMaster(并行计算、内存网格、网格计算),MapReduceTaskMaster(并行计算、内存网格、网格计算)。Container:执行业务逻辑的容器框架,支持线程/进程/docker/actor等。Processor:业务逻辑框架,不同的processor表示不同的任务类型。以MapTaskMaster为例,大概的原理如下图所示: 3. 分布式编程模型之Map模型Schedulerx2.0提供了多种分布式编程模型,这篇文章主要介绍Map模型(之后的文章还会介绍MapReduce模型,适用更多的业务场景),简单几行代码就可以将海量数据分布式到多台机器上进行分布式跑批,非常简单易用。 针对不同的跑批场景,map模型作业还提供了并行计算、内存网格、网格计算三种执行方式: 并行计算:子任务300以下,有子任务列表。内存网格:子任务5W以下,无子任务列表,速度快。网格计算:子任务100W以下,无子任务列表。4. 并行计算原理因为并行任务具有子任务列表: 如上图,子任务列表可以看到每个子任务的状态、机器,还有重跑、查看日志等操作。 因为并行计算要做到子任务级别的可视化,并且worker挂了、重启还能支持手动重跑,就需要把task持久化到server端: 如上图所示: server触发jobInstance到某个worker,选中为master。MapTaskMaster选择某个worker执行root任务,当执行map方法时,会回调MapTaskMaster。MapTaskMaster收到map方法,会把task持久化到server端。同时,MapTaskMaster还有个pull线程,不停拉取INIT状态的task,并派发给其他worker执行。5. 网格计算原理网格计算要支持百万级别的task,如果所有任务都往server回写,server肯定扛不住,所以网格计算的存储实际上是分布式在用户自己的机器上的: 如上图所示: server触发jobInstance到某个worker,选中为master。MapTaskMaster选择某个worker执行root任务,当执行map方法时,会回调MapTaskMaster。MapTaskMaster收到map方法,会把task持久化到本地h2数据库。同时,MapTaskMaster还有个pull线程,不停拉取INIT状态的task,并派发给其他worker执行。6. 最佳实践6.1 需求 举个例子: 读取A表中status=0的数据。处理这些数据,插入B表。把A表中处理过的数据的修改status=1。数据量有4亿+,希望缩短时间。6.2 反面案例 我们先看下如下代码是否有问题? public class ScanSingleTableProcessor extends MapJobProcessor { private static int pageSize = 1000; @Override public ProcessResult process(JobContext context) { String taskName = context.getTaskName(); Object task = context.getTask(); if (WorkerConstants.MAP_TASK_ROOT_NAME.equals(taskName)) { int recordCount = queryRecordCount(); int pageAmount = recordCount / pageSize;//计算分页数量 for(int i = 0 ; i < pageAmount ; i ++) { List<Record> recordList = queryRecord(i);//根据分页查询一页数据 map(recordList, "record记录");//把子任务分发出去并行处理 } return new ProcessResult(true);//true表示执行成功,false表示失败 } else if ("record记录".equals(taskName)) { //TODO return new ProcessResult(true); } return new ProcessResult(false); }}如上面的代码所示,在root任务中,会把数据库所有记录读取出来,每一行就是一个Record,然后分发出去,分布式到不同的worker上去执行。逻辑是没有问题的,但是实际上性能非常的差。结合网格计算原理,我们把上面的代码绘制成下面这幅图: ...

May 31, 2019 · 2 min · jiezi

XXL-JOB v2.0.2,分布式任务调度平台

v2.0.2 Release Notes1、底层通讯方案优化:升级较新版本xxl-rpc,由"JETTY"方案调整为"NETTY_HTTP"方案,执行器内嵌netty-http-server提供服务,调度中心复用容器端口提供服务;2、任务告警逻辑调整,改为通过扫描失败日志方式触发。一方面精确扫描失败任务,降低扫描范围;另一方面取消内存队列,降低线程内存消耗;3、Quartz触发线程池废弃并替换为 "XxlJobThreadPool",降低线程切换、内存占用带来的消耗,提高调度性能;4、调度线程池隔离,拆分为"Fast"和"Slow"两个线程池,1分钟窗口期内任务耗时达500ms超过10次,该窗口期内判定为慢任务,慢任务自动降级进入"Slow"线程池,避免耗尽调度线程,提高系统稳定性;5、执行器热部署时JobHandler重新初始化,修复由此导致的 "jobhandler naming conflicts." 问题;6、新增Class的加载缓存,解决频繁加载Class会使jvm的方法区空间不足导致OOM的问题;7、任务支持更换绑定执行器,方便任务分组转移和管理;8、调度中心告警邮件发送组件改为 “spring-boot-starter-mail”;9、记住密码功能优化,选中时永久记住;非选中时关闭浏览器即登出;10、项目依赖升级至较新稳定版本,如quartz、spring、jackson、groovy、xxl-rpc等等;11、精简项目,取消第三方依赖,如 commons-collections4、commons-lang3 ;12、执行器回调日志落盘方案复用RPC序列化方案,并移除Jackson依赖;13、底层Log调优,应用正常终止取消异常栈信息打印;14、交互优化,尽量避免新开页面窗口;仅WebIDE支持新开页,并提供窗口快速关闭按钮;任务启、停、删除、触发等轻操作提示改为toast方式,15、任务暂停、删除优化,避免quartz delete不完整导致任务脏数据;16、任务回调、心跳注册成功日志优化,非核心常规日志调整为debug级别,降低冗余日志输出;17、调整首页报表默认区间为本周,避免日志量太大查询缓慢;18、LRU路由更新不及时问题修复;19、任务失败告警邮件发送逻辑优化;20、调度日志排序逻辑调整为按照调度时间倒序,兼容TIDB等主键不连续日志存储组件;21、执行器优雅停机优化;22、连接池配置优化,增强连接有效性验证;23、JobHandler#msg长度限制,修复异常情况下日志超长导致内存溢出的问题;24、升级xxl-rpc至较新版本,修复springboot 2.x版本兼容性问题;简介XXL-JOB是一个轻量级分布式任务调度平台,其核心设计目标是开发迅速、学习简单、轻量级、易扩展。现已开放源代码并接入多家公司线上产品线,开箱即用。 特性1、简单:支持通过Web页面对任务进行CRUD操作,操作简单,一分钟上手;2、动态:支持动态修改任务状态、启动/停止任务,以及终止运行中任务,即时生效;3、调度中心HA(中心式):调度采用中心式设计,“调度中心”基于集群Quartz实现并支持集群部署,可保证调度中心HA;4、执行器HA(分布式):任务分布式执行,任务"执行器"支持集群部署,可保证任务执行HA;5、注册中心: 执行器会周期性自动注册任务, 调度中心将会自动发现注册的任务并触发执行。同时,也支持手动录入执行器地址;6、弹性扩容缩容:一旦有新执行器机器上线或者下线,下次调度时将会重新分配任务;7、路由策略:执行器集群部署时提供丰富的路由策略,包括:第一个、最后一个、轮询、随机、一致性HASH、最不经常使用、最近最久未使用、故障转移、忙碌转移等;8、故障转移:任务路由策略选择"故障转移"情况下,如果执行器集群中某一台机器故障,将会自动Failover切换到一台正常的执行器发送调度请求。9、阻塞处理策略:调度过于密集执行器来不及处理时的处理策略,策略包括:单机串行(默认)、丢弃后续调度、覆盖之前调度;10、任务超时控制:支持自定义任务超时时间,任务运行超时将会主动中断任务;11、任务失败重试:支持自定义任务失败重试次数,当任务失败时将会按照预设的失败重试次数主动进行重试;其中分片任务支持分片粒度的失败重试;12、任务失败告警;默认提供邮件方式失败告警,同时预留扩展接口,可方面的扩展短信、钉钉等告警方式;13、分片广播任务:执行器集群部署时,任务路由策略选择"分片广播"情况下,一次任务调度将会广播触发集群中所有执行器执行一次任务,可根据分片参数开发分片任务;14、动态分片:分片广播任务以执行器为维度进行分片,支持动态扩容执行器集群从而动态增加分片数量,协同进行业务处理;在进行大数据量业务操作时可显著提升任务处理能力和速度。15、事件触发:除了"Cron方式"和"任务依赖方式"触发任务执行之外,支持基于事件的触发任务方式。调度中心提供触发任务单次执行的API服务,可根据业务事件灵活触发。16、任务进度监控:支持实时监控任务进度;17、Rolling实时日志:支持在线查看调度结果,并且支持以Rolling方式实时查看执行器输出的完整的执行日志;18、GLUE:提供Web IDE,支持在线开发任务逻辑代码,动态发布,实时编译生效,省略部署上线的过程。支持30个版本的历史版本回溯。19、脚本任务:支持以GLUE模式开发和运行脚本任务,包括Shell、Python、NodeJS、PHP、PowerShell等类型脚本;20、命令行任务:原生提供通用命令行任务Handler(Bean任务,"CommandJobHandler");业务方只需要提供命令行即可;21、任务依赖:支持配置子任务依赖,当父任务执行结束且执行成功后将会主动触发一次子任务的执行, 多个子任务用逗号分隔;22、一致性:“调度中心”通过DB锁保证集群分布式调度的一致性, 一次任务调度只会触发一次执行;23、自定义任务参数:支持在线配置调度任务入参,即时生效;24、调度线程池:调度系统多线程触发调度运行,确保调度精确执行,不被堵塞;25、数据加密:调度中心和执行器之间的通讯进行数据加密,提升调度信息安全性;26、邮件报警:任务失败时支持邮件报警,支持配置多邮件地址群发报警邮件;27、推送maven中央仓库: 将会把最新稳定版推送到maven中央仓库, 方便用户接入和使用;28、运行报表:支持实时查看运行数据,如任务数量、调度次数、执行器数量等;以及调度报表,如调度日期分布图,调度成功分布图等;29、全异步:任务调度流程全异步化设计实现,如异步调度、异步运行、异步回调等,有效对密集调度进行流量削峰,理论上支持任意时长任务的运行;30、跨平台:原生提供通用HTTP任务Handler(Bean任务,"HttpJobHandler");业务方只需要提供HTTP链接即可,不限制语言、平台;31、国际化:调度中心支持国际化设置,提供中文、英文两种可选语言,默认为中文;32、容器化:提供官方docker镜像,并实时更新推送dockerhub,进一步实现产品开箱即用;33、线程池隔离:调度线程池进行隔离拆分,慢任务自动降级进入"Slow"线程池,避免耗尽调度线程,提高系统稳定性;;文档地址中文文档技术交流社区交流

April 22, 2019 · 1 min · jiezi