作者 | 欧阳涛 招联金融大数据开发工程师

02 Master启动流程

2.10 WorkFlowExecutorThread 里执行 Submit StandByTask 方法

SubmitStandByTask干了5件事情:

  1. 从ReadyToSubmitTaskQueue中取出TaskInstance。
  2. (这个TaskInstance是可以重试并且设定为强制成功了的)把task放到completeTaskMap以及taskInstanceMap,并从队列中移除。
  3. 如果这个task是首次执行的话,就会先从task和ProcessInstance中获取参数(varPool)【这一步的方法是GetPreVarPool】
  4. 获取这个task依赖结果【这一步的方法是GetDependResultForTask】
  5. 根据第4步获取的依赖结果,如果依赖结果为失败或者不执行,就从队列中移除,并且放到FailedTaskMap里的。如果依赖结果为成功则将执行SubmitTaskExec方法,同时会放到CompleteTaskMap。至于SubmitTaskExec做了哪些事情将在2.11中说明。

2.11 WorkFlowExecutorThread里执行SubmitTaskExec方法

SumbitTaskExec干了9件事情:

  1. PackageTaskInstance封装了TaskInstance,就是将TaskInstance和ProcessInstance进行了绑定,并且获取到了MainJar,ResourceList这些信息。
  2. 根据TaskType获取CommonTaskProcessor,这里采用SPI机制获取。如果想具体了解SPI机制的,可以百度搜索AutoService注解以及ServiceLoad进行详细了解。
  3. CommonTaskProcessor初始化,也就是将TaskInstance、ProcessInstance、ProcessService、MasterConfig传递给CommonTaskProcessor。
  4. 通知流程所在的主机,通过netty发送Host和HostUpdateCommand。
  5. 将CommonTaskProcessor的Action为submit(提交)状态。(这步极为重要)
  6. 放入到ValidMap,TaskInstanceMap,ActiveTaskProcessorMaps里。
  7. 将CommonTaskProcessor的Action设置成Run状态的。
  8. 将task以及ProcessInstance放入到StateWheelExecuteThread进行checkout。
  9. 如果这个task执行完成就添加到StateEvents队列中。

下一节讲述commonTaskProcessor的submit状态。

2.12 CommonTaskProcessor里执行Submit Task方法

回顾一下上节的第5步,CommonTaskProcessor的Action设置为Submit之后,

去ComonTaskProcessor的父类BaseTaskProcessor找Action方法,在Action方法中有个Switch结构,很明显会进入Submit方法,之后就进入本节所说的SubmitTask方法的了。

SubmitTask在这里干了三件事情:

  1. ProcessService。SubmitTaskWithRetry可以重复5次(MasterConfig.GetTask CommitInterval)提交task任务,最后在ProcessServiceImpl执行submitTask。
  2. 将此task的信息插入到TaskGroupQueue数据表中。
  3. DispatchTask下发任务,将Task任务下发到实现了TaskPriorityQueue接口的TaskPriorityQueueImpl中去。

在ProcessServiceImpl如何执行submitTask将在2.13中说明,同时DispatchTask下发做了那些事情,将在2.15中说明。

2.13 ProcessServiceImpl里执行SubmitTask方法

ProcessServiceImpl是属于Service模块的,SubmitTask主要干了2件事情:

  1. SubmitTaskInstanceToDB 将任务实例保存到数据库中,当然这里面有数据结构(TaskInstance)的变化,纯属业务的改变的。
  2. 如果此非结束状态,CreateSubWorkerProcess创建子流程,如果没有子流程,直接跳过2.14的内容。进入2.15。创建子流程做了哪些事情将在2.14中说明。

2.14 ProcessServiceImpl里执行CreateSubWork Process方法

创建子流程需要干6件事情:

  1. FindWorkProcessMapByParent查找父流程与task绑定的ProcessInstanceMap,是流程实例与Task关系的表。
  2. SetProcessInstanceMap。设置刚刚查找的ProcessInstanceMap,如果能找到以前跑的ProcessInstanceMap,更新这个ProcessInstanceMap,如果没有找到就创建新的ProcessInstanceMap,并插入到数据库中。
  3. CreateSubProcessCommand,根据参数,父流程等创建子流程命令的(SubProcessCommand)。
  4. UpdateSubProcessDefinitionByParent根据父流程更新子流程的定义。
  5. InitSubInstanceState初始化子实例状态。
  6. CreateCommand将创建的子流程命令插入数据库中。

这里ProcessInstanceMap并不是jdk包下的map,而是表t_ds_relation_process_instance的数据的。里面存储了父流程实例以及任务的关系的。3到6这些步骤都是crud的业务,里面具体的细节就赘述了。

2.15 CommonTaskProcessor里执行Dispatch Task方法

DispatchTask方法干了三件事情:

  1. 获取TaskPriorityQueueImpl的bean。
  2. 将TaskInstance,ProcessInstance封装成TaskPriority。
  3. 将封装后的TaskPriority放到这bean下的queue中去,这个队列是jdk的PriorityBlockingQueue,是一个具有优先级别的无界阻塞队列。

此时将DispatchTask放进task,那如何消费队列中的task的呢?2.16将说明这个议题。

2.16 TaskPriorityQueueConsumer执行run和dispatchTask方法

TaskPriorityQueueConsumer是一个继承Thread的类。在MasterServer启动之后,根据Spring的特性,TaskPriorityQueueConsumer会创建一个对象由Spring管理。TaskPriority会执行init的方法。线程启动并且设置线程名字Task UpdateConsumerThread。

Run方法中以3(MasterConfig.getMasterDispatch Task ) 次拉取为循环,每次1秒从队列中(BatchDispatch)拉取TaskPriority,如果失败就有重新丢回到这队列中去。

随后对拉取的数据进行DispatchTask方法。

DispatchTask方法中做了三件事情:

  1. 从TaskPriority中取出context,根据Command,ExecutorType和Workergroup封装成Execution Context。
  2. 将ExecutionContext交给Executor Dispatcher进行Dispatcher,这将在2.17中说明。
  3. 如果发送成功,返回result为true。将TaskEvent添加到TaskEventService (addEvents)中,由TaskEventService进行管理的。TaskEventService的说明将在2.19中介绍。

2.17 ExecutorDispatcher里执行Dispatch方法

ExecutorDispatcher这个类就干了三件事情:

  1. ExecutorDispatcher此类实现了InitializingBean。也就是创建过程中执行了AfterPropertiesSet方法,ExecutorManagers注册了Worker和Client的ExecutorType。
  2. Dispatch方法中获取到了Worker的ExecutorType,然后进行HostManagar.select。在Select方法中会根据MasterConfig中的Host-selector策略选择机器,默认是Lower-weight。如果读者有自定义的需求,则可以实现HostManager接口的。(Lower-weight如何选择的,就不详细介绍了。因为难度并不大,也就是纯属业务的变化的,有兴趣就可以自行阅读的。)
  3. 选择完了Host之后,调用ExecutorManager进行execute。这里的EeforeExecute和AfterExecute是没有内容的,如果读者有需求,同样可以在此添加内容的。在2.18中会说明execute的内容。

2.18 NettyExecutorManager执行execute和doExecute方法

ExecutorManager目前就一个实现类,就是NettyExecutorManger。

在init方法中NettyRemotingClient注册了TaskExecuteResponse、TaskExecuteAck和

TaskKillResponse的Processor。这些Processor是用来让Master和Worker进行交互的。

在Executor方法中最核心的方法就是DoExecute。

在DoExecute中NettyRemotingClient根据有效的Host发送Command。如果发送失败了,剔除失败节点,将task重新添加到队列中。

至此,Master就以Command形式发送task信息给Worker,说明一下,此时的Command是Remote包下的Command,与前面的Command没有任何关系的,不要混淆了。Master和Worker的交互过程会在第四章节中讲述。

2.19 TaskEventService执行addEvents方法

先说说TaskEventService创建过程。这是由Spring管理的,然后执行Start方法之后,有两个线程创建出来,一个是TaskEventThread,另外一个是TaskEventHandlerThread。在TaskEventThread会从EventQueue中取出TaskEvent事件进行提交(submitTaskEvent)。而TaskEventHandlerThread会执行EventHandler方法。EventHandler中会从TaskExecuteThreadMap中取出数据来执行executeEvent方法。

那么TaskExecuteThreadMap如何插入数据的呢?答案就是本节所说的addEvents方法。

addEvents方法中会调用TaskExecuteThreadPool中的SubmitTaskEvent方法。而在SubmitTaskEvent方法中最核心的功能就是往TaskExecuteThreadMap放入数据,也就是以ProcessInstanceId为key,TaskExecuteThread为value的map,并且会调用TaskExecuteThrad的addEvent方法,将event放入到events队列中。

至于TaskExecuteThread做了哪些事情将在2.20中说明。

2.20 TaskExecuteThread执行Persist方法

接上文2.19的在TaskExecuteThreadPool中ExecuteEvent方法。

执行TaskExecuteThread中的run方法。在run方法中从events队列中取出TaskEvent,并执行Persist持久化操作的,将task信息保存到数据库中的。

在Persist方法中,重点是Switch结构下的内容。根据DISPATCH,RUNNING,RESULT,执行不同的方法,封装不同的TaskInstance内容保存到数据库中,并发送请求给Worker。

另外构建StateEvent对象,交给WorkerflowExecuteThreadPool进行处理持久化后的StateEvent对象。stateEvent应该如何处理呢?请参考2.22的内容。

2.21 MasterSchedulerService总结

MasterServer的MasterSchedulerService已经基本讲完。回到最开始的MasterServer这部分,发现MasterSchedulerService后面的两个bean没有讲,也就是EventExecuteService以及FailoverExecute Thread.这两个都是线程的,将在2.22和2.23中说明这最后两个bean。

2.22 EventExecuteService线程的run方法

在MasterServer调用Start方法后,EventExeuctor Service的run方法执行过程如下:

  1. 每100毫秒执行EventHandler方法。
  2. 每次执行EventHandler方法时,从2.5章节的第3步ProcessInstance ExecCacheManager中取出WorkFlowExecutorThread,通过WorkflowExecuteThreadPool执行ExecuteEvent方法。
  3. 在ExecuteEvent方法中, 可以发现最核心的方法就是HandlerEvents方法。
  4. 在HandlerEvents中可以发现,从2.11章节的第9步的StateEvents队列取出StateEvent,然后在通过StateEventHandler方法进行判断的。
  5. 在WorkflowExecutorThread的stateEventHandler方法中,根据StateEventType的不同,以有6种不同类型的方法去调用,分别为PROCESS_STATE _CHANGE、TASK_STATE_CHANGE、PROCESS_TIMEOUT、TASK_TIMEOUT、TASK_RETRY、PROCESS_BLOCKED。通过不同的type调用不同的方法,如PROCESS_STATE_CHANGE调用ProcessStateChangeHandler方法,这里就不详细讲述各个方法的内容了,其本质上也都是内存数据结构的变化。

P.S.:

  1. 如果StateEventHandler方法中某一类型成功执行,则从StateEvents队列中移除它了。
  2. 返回到WorkflowExecuteThreadPool类的ExecuteEvent方法中,执行完第3步之后,会有个回调函数,失败就执行OnFailure方法。成功就执行OnSuccess方法,NotifyProcessChanged通知流程改变中,要么NotifyMyself,要么通知其他流程NotifyProcessChanged的。

2.23 FailoverExecutorThread线程的Run方法

此节为机器故障切换执行的线程,主要干了5件事情。具体执行流程如下:

  1. Run方法中FailoverService.checkMaster Failover检查是否需要切换的host。
  2. 如果有host的话,就进入FailoveMaster WithLock方法。在此方法中,从zk中通过分布式锁来进行切换机器,也就是进入FailoverMaster方法。
  3. 在FailoverMaster中,从ProcessSerivce里(QueryNeedFailover ProcessInstance)查询所需要切换的流程实例(NeedFailover ProcessInstanceList)。
  4. 接下来,就是通过zk获取有效的WorkerServers.failoverTaskInstance来切换task。在切换task时有三个步骤,分别是:当是Yarnjobs时,则直接杀掉 ; 改变task的状态,也就是从Running到Needfailover ; WorkflowExecutor ThreadPool提交StateEvent。
  5. 在ProcessService中处理该切换的流程,增加切换流程实例的Command,插入数据库中。

下两章将继续讲述Worker和Master与Worker的交互。

达人专栏 | 还不会用 Apache Dolphinscheduler?大佬用时一个月写出的最全入门教程【三】的更多相关文章

  1. 【达人专栏】还不会用Apache Dolphinscheduler吗,大佬用时一个月写出的最全入门教学【二】

    02 Master启动流程 2.1 MasterServer的启动 在正式开始前,笔者想先鼓励一下大家.我们知道启动Master其实就是启动MasterServer,本质上与其他SpringBoot项 ...

  2. 我在Apache DolphinScheduler的心路历练

    摘要:Apache DolphinScheduler 目前是 Apache 孵化项目,目前正在快速发展中.加入Apache DolphinScheduler社区已一年多,已有 400+ 公司在生产上使 ...

  3. 金秋十月 - Apache DolphinScheduler 收获 2 位新 Committer

    点击上方蓝字关注 Apache DolphinScheduler Apache DolphinScheduler(incubating),简称"DS", 中文名 "海豚调 ...

  4. 本周六 Apache DolphinScheduler & Doris 将联合线上 Meetup

    活动背景 2020年,大数据成为国家基建的一个重要组成,大数据在越来越多的领域展现威力.随着大数据的应用场景越来越多,大家对数据的响应速度和数据加工工作流的方便程度也提出了更高的要求.在这种背景下,相 ...

  5. Apache DolphinScheduler之最美好的遇见

    关于 Apache DolphinScheduler社区 Apache DolphinScheduler(incubator) 于17年在易观数科立项,19年3月开源, 19 年8月进入Apache ...

  6. 活动回顾|Apache DolphinScheduler x Pulsar 在线 Meetup

    关于 Apache DolphinScheduler: " Apache DolphinScheduler(Incubating) 是一个分布式去中心化.易扩展的可视化工作流任务调度系统,致 ...

  7. Apache DolphinScheduler & Doris 将于本周六联合进行线上 Meetup

    01 - 活动介绍 2020年,大数据成为国家基建的一个重要组成,大数据在越来越多的领域展现威力.随着大数据的应用场景越来越多,大家对数据的响应速度和数据加工工作流的方便程度也提出了更高的要求.在这种 ...

  8. Apache DolphinScheduler 需要的sudo,还可以这么玩,长见识了!

    Apache DolphinScheduler(incubator)需要的sudo,还可以这么玩,长见识了! 在新一代大数据任务调度 - Apache DolphinScheduler(以下简称dol ...

  9. Apache DolphinScheduler新一代分布式工作流任务调度平台实战-上

    概述 定义 dolphinscheduler 官网地址 https://dolphinscheduler.apache.org/ dolphinscheduler GitHub地址 https://g ...

随机推荐

  1. css3常用动画

    //有道云笔记链接 http://note.youdao.com/s/72qbBVyv  

  2. 从标准输入流中读取并执行shell指定函数

    巧妙的ohmytmux配置 看oh my tmux的配置,发现他们很巧妙的将配置和shell函数放到一个文件里 比如切换鼠标模式的相关配置和shell函数, # : << EOF # .. ...

  3. 对抗噪音,一键清晰,HMS Core音频编辑服务给你“录音棚”般的体验

    短视频时代来临,一部手机就可以玩转多种花样,所以越来越多的自由创作者加入这个行业,平时生活中用手机拍短视频.街头唱歌的非专业从业者随处可见.离开了录音棚,没有专业.统一的录音设备,无论在家里还是在路边 ...

  4. 关于c#多线程中的几个信号量

    信号量在c#多线程通信中主要用来向阻塞的线程传达信号从而使得阻塞线程继续执行 多线程信号(线程交互):通常是指线程必须等待一个线程或者多个线程通知交互(释放信号)才可以继续执行 在c#中信号量主要有这 ...

  5. 基于.NetCore开发博客项目 StarBlog - (9) 图片批量导入

    系列文章 基于.NetCore开发博客项目 StarBlog - (1) 为什么需要自己写一个博客? 基于.NetCore开发博客项目 StarBlog - (2) 环境准备和创建项目 基于.NetC ...

  6. 浅析 2D 组态与 2.5D 组态的区别 | 空调装配生产线与化工安全流程

    前言 为了更有效辨别 2D 与 2.5D 之间的区别,图扑软件选用 2D 空调装配生产线与 2.5D 化工厂安全流程作比较.通过自主研发的 HT 产品,采用 B/S 架构快速搭建零代码拖拽式 Web ...

  7. JAVA - 启动一个线程是用run()还是start()?

    JAVA - 启动一个线程是用run()还是start()? 启动一个线程是调用start()方法,使线程所代表的虚拟处理机处于可运行状态,这意味着它可以由JVM调度并执行.这并不意味着线程就会立即运 ...

  8. uniapp使用scroll-view与swiper组件实现tab滑动切换页面需要注意的问题

    效果图: tab栏可以滑动,切换页面跟随tab栏同步滑动.这里需要注意的是使用swiper组件时,它会有一个默认的高度,你必须动态的获取数据列表的高度覆盖原来的默认高度. 下面是代码 html < ...

  9. 通过Go语言创建CA与签发证书

    本篇文章中,将描述如何使用go创建CA,并使用CA签署证书.在使用openssl创建证书时,遵循的步骤是 创建秘钥 > 创建CA > 生成要颁发证书的秘钥 > 使用CA签发证书.这种 ...

  10. 软件测试—Day2

    day2 Q:面试过程中,性能测试你测试什么?关注的点是什么? A:程序的响应时间,系统的吞吐量,以及并发用户数,和tps,qps,以及DB的IOPS,和服务器的系统资源(CPU和内存).通过一定的工 ...