Oozie和Azkaban的技术选型和对比

OozieAzkaban的技术选型和对比

一.AzkabanOozie的工作流程

1.1 Azkaban工作流程

Azkaban将需要操作的信息打包成zip文件发送给Server端,Server对用户的信息进行存储。用户在Web UI 或者通过HTTP Client发送操作请求后,Server会根据用户定义的*.job文件(KV 匹配),执行zip包中的Jar文件。

源码的执行过程:

 

1.从Web页面提交工作流程:

Method.GET

/executor?projectId=33&project=testSpark&ajax=executeFlow&flow=test1&disabled=%5B%5D&failureEmailsOverride=false&successEmailsOverride=false&failureAction=finishCurrent&failureEmails=&successEmails=¬ifyFailureFirst=false¬ifyFailureLast=false&concurrentOption=ignore

 

用户提交任务后,发送任务的详情到服务器中,Azkaban客户端会对任务以及用户的信息进行校验,封装后首先将执行的信息(任务,时间,用户等)存入数据库中(表active_executing_flows),之后执行dispatch方法,对需要执行的任务流进行调度。

dispatch方法中,首先会更新executions_flows表,然后将操作的语句发送到指定的ip和端口进行执行。

 

2.服务器接收到了请求:如果是执行操作那么接收到的actiontypeexecute。接着服务器会从数据库中获取相应的工作流flow,服务器将flow封装成FlowRunner

FlowRunner的属性

 

ExecutorService

线程池对象

ExecId

从数据库中获取相应的flow

numJobThreads

默认10个线程

JobTypeManager

定义Job的插件,有以下几种插件

 

Set

将有向无环图中的node抽象成一个JobRunner进行运行

其中任务的执行是使用一个递归操作runReadyJob(),循环操作其中的node,也就是每个JobRunner

JobRunner的主要属性:

Job

执行任务的父类接口。

JobtypeManager

根据输入的type类型返回此节点需要执行的任务类型

JobId

唯一标识符

配置文件,Job的路径,监控FlowWatch.....

 

其中会根据需要操作的Flow来定义Jobtype。返回相应的类型。例如MR  返回的是JavaProcessJob

也就是说:每一个节点,是通过新建一个进程去运行。在这个进程中会执行多条command,通过process.run(),运行用户定义的job

PS.每条command都需要重新建立一个process

 

1.2  Oozie工作流程

Oozie中,用户需要准备以下文件:

Job.properties

Job文件存储HDFSResourceManager的配置

Workflow.xml

配置每个节点之间的依赖关系

Lib

存放着指定运行jar的关联包

.jar

运行的jar

 

用户需要将这些文件放置在一个文件夹下,然后上传至HDFS中。在客户端或者终端中发送请求去执行。

源码执行流程:

使用控制行操作:

1.首先调用:org.apache.oozie.cli.OozieCLI。首先根据不同的command类型调用不同的发送请求,例如使用MRCommand

 

在这个方法中会生成一个ClientSubmit指定的Properties(根据ClientCommand生成)。提交的对象是HTTPJobSubmit。调用该对象中的call方法和Server进行通信。最终返回一个jobIdMETHOD.POST

 

2.服务器端:首先调用相应的Servlet,调用提交作业方法,生成一个DAG图(DAGEngine,然后所有的操作都是基于DAG来实现的)。

A.如果我们在提交一个作业时生成了jobType那么,此时会选定不同的提交类型(类似于一个工厂模式),返回指定的信息。

B.首先它会调用SubmitXCommand.call()方法,将job的信息加入数据库中并且返回一个jobId

C.之后执行start(jobId)的方法,调用Xcommand.call()方法,生意Instrument对任务进行监控,在这个方法中会调用一个SignalXCommand.execute()方法。

Oozie的后端中会维护一个异步队列,在上述的execute中会根据job中的每一个action的类型,去生成相应的Command加入异步队列中。类型如下:

skipAction

SignXcommand

startAction

ActionStartXCommand

ForkAction

ActionStartXCommand 和上面的jobType不同

类似还有killActionXCommandworkflowNotifyActionXCommand

PS如果是MR 或者 Spark  映射ActionStartXCommand 类型。

D.在后端异步队列CallableQueueService中。(在这个方法中使用InstrumentJava进行进行监控)。会调用这些XCommandexecute方法,不同的类型会实例化不同的executor,例如MR Spark都会实例化JavaActionExecutor(同时还有SubWorkflowActionExecutor执行提交任务)。

E.在上述对象的execute方法中会根据配置生成JobClient,来获取正在运行的Running Job的信息以及提交Job  SubmitJob,返回一个jobId。如果获取正在运行的runningJob在这个对象中还有job.trackerUrl也就是任务的日志。可以供以后展示。

 

 

测试用例提交流程:

 

看测试用例提交Hadoop作业中,首先对连接进行验证,然后每次提交会生成一个JobClient,该Oozie作为一个ClientHadoop服务器发送操作job的请求。

 

其中操作hive hadoop spark 作业均是JavaActionExecutor,该执行器中会调用submitLauncher提交Hadoop作业。

1.3  小结

Azkaban的工作流运行是依靠操作进程来提交不同的命令的,它操作任务成功和失败的信息在于进程的相应,但是这并不能有效的管理任务的成功与失败。

Oozie 执行MR 任务是依靠HadoopJar包,以Server作为Client发送请求至集群进行操作。在此之前需要将任务所依赖执行的jar包上传至HDFS中才可执行。

通过了解OozieAzkaban的执行过程,个人任务使用Oozie作为底层的流程引擎比较合适,因为通过JobClient可以有效的监控正在执行的任务,获取任务的信息,如果使用Azkaban则只能获取进程执行的详情。

 

二.workflow.xml配置工作流流程

Oozie中每个工作流有不同的状态,具体如下:

PERP

工作流已经被定义但是没有执行

RUNNING

当一个工作流开始执行。它不会达到结束的状态只会出错结束或者挂起

SUSPENDED

工作流给挂起状态从RUNNING状态过来

SUCCESSED

工作流到达END节点

KILLED

工作流处于RUNNINGSUSPENDED状态被杀死

FAILED

工作流遇到错误停止

 

工作流节点有以下几种类型:

控制流节点:控制工作流开始和结束以及控制执行的路径

Start

<start to="[NODE-NAME]" />

第一个执行的节点

End

<end name="[NODE-NAME]" />

执行到该节点任务成功,一个工作流只能有一个end

Kill

<kill name="[NODE-NAME]">

<message>[MESSAGE-TO-LOG]message>

kill>

被杀死节点的名称和备注,达到该节点时,任务状态为KILLED

Decision

<decision name="[NODE-NAME]">

<switch>

<case to="[NODE_NAME]">[PREDICATE]case>

<default to="[NODE_NAME]" />

switch>

decision> 工作流执行到此处时会根据条件进行判断,满足条件的路径将被执行

Fork

<fork name="[FORK-NODE-NAME]">

<path start="[NODE-NAME]" />...

fork> 多个并发路径

Join

<join name="[JOIN-NODE-NAME]" to="[NODE-NAME]" />

Fork的多条路径会在Join处汇合,只有所有路径都到了,才会执行join.

 

动作类型节点:能够触发一个计算任务或者处理任务执行的节点。该类节点有以下的基本特性:

1.异步:Oozie会启动一个异步队列来执行某个工作流job,并通过回调机制以及轮询来获取任务的执行状态.

2.节点要么成功要么失败。

3.一个任务如果在某个节点失败了,那么Oozie提供一套恢复运行的策略,如果是状态转移失败,那么自动运行,否则需手动运行。

动作类节点主要有以下几大类:

MR

<action name="[NODE-NAME]">

<map-reduce>...启动一个MRJOB的执行,并且可以配置其中的其他任务,如streaming,pipes,file,archive

Hive

<hive xmlns="uri:oozie:hive-action:0.2">

<script>[HIVE-SCRIPT]script>

<param>[PARAM-VALUE]param>

执行hive查询sql

Sqoop

<sqoop xmlns="uri:oozie:sqoop-action:0.2">

Pig

启动脚本实现Job

Fs

<fs>

<delete path='[PATH]' />

<mkdir path='[PATH]' />

<move source='[SOURCE-PATH]' target='[TARGET-PATH]' />

....

fs>  操作HDFS

Java

OozieJava是有main方法执行的程序,他在服务器中以MR Job进行执行,这个Job只有一个Map程序,需要执行

namenode,jobTracker以及JVM和传输给主函数的参数

Sub-workflow

子流程动作,主流程执行过程中,遇到子流程点执行时,会一直等到子流程执行完后才跳转到下一个要执行的节点。

Shell

<shell xmlns="uri:oozie:shell-action:0.2">

<exec>[SHELL-COMMAND]exec>

<argument>[ARGUMENT-VALUE]argument>

执行shell语句

 

三.Oozie根据xml执行job

3.1新建workflow

可以根据hue中的方法进行新建,重写hue中的editor/workflow/new方法,不过得将pythonjava

3.2执行workflow

参考oozie中的提交作业的流程,看下操作的主要对象的属性信息:

WorkflowJobBean

startTimestamp

开始时间

endTimestamp

结束时间

app_path

jar包位置

Conf

配置文件的信息BLOB二进制大文件

Actions

List 一系列的执行节点

等等。。

 

这个是一个任务的基本属性,主要包含了一堆actions节点和conf配置文件。在提交代码的过程中,以MR 作业为例:

首先,在提交的过程中,会将用户的任务信息封装成一个workFlowJob以及workflowInstancejob的状态,执行路径等)并判断job的行为状态。

然后,对这个Job中的每个action进行遍历,判断action属于哪种类型,然后放入后端的异步队列中。

异步队列会执行其中每一个action,执行时生成一个executor,这个执行器在操作的过程中会根据每一个actionxml文件生成org.apache.hadoop.conf.configuration actionConfig对象,循环遍历每个action的节点xml映射去填充这个对象的属性。

最终根据actionConf生成一个jobClient,发送用户的请求。

 

四.如何运行Spark作业

4.1 Oozie

Oozie中对spark作业的执行有其自定义的一套执行器----sparkActionExecutor,这个执行器继承了JavaActionExecutor

在这个执行器中,主要作用是定义好spark作业的配置信息以及在生成Client的时候定义的Configuration actionConfig对象的初始化。

也就是说,spark对象会根据不同的配置初始化相应的JobClient用于发送spark任务jar包,其具体的流程和HadoopActionExecutor相似,都是调用JavaActionExecutorexecute()方法。

4.2 Azkaban

Azkaban的底层是将命令封装成一个进程进行执行,在这个过程中我们可以自定义相关命令。发送jar包进行执行。

4.3 小结

如果从操作的角度上来说,那么Azkaban直接上传jar包然后执行,其过程更为简易,并且用户操作相对于Oozie来说更为简单,困难在于,不能直接将所需要操作的shell语句编写入口提供给用户。需要根据WEB UI的返回值,生成操作命令。

Oozie的配置相对于复杂,但是它已经提供了一套相对于比较完整的WEB 页面接口以及HUE中配置workflow.xml的代码。困难点在于将用户编写的操作流程以xml形式形象的展示出来。

 

五.OozieAzkaban如何判断任务是否完成

5.1 Oozie判断任务是否完成

如果任务正在运行的过程中,那么当前这个任务会被存储在数据库中,并且状态标记为RUNNING。当任务在执行的过程中,如果不出错且不出现挂起的状态,则任务状态不会变化。

当任务操作结束后(无论错误还是成功执行完成),Oozie会操作回调接口,具体操作流程如下:

1.生成CompletedActionXCommand,封装当前action的信息。

2.在这个对象的execute方法中,如果当前action的状态为PREP,则将继续轮询,会将轮询的命令加入执行的异步队列中,并设置相应的延时执行。

3.如果任务正处于RUNNING中,那么会在异步队列中加入ActionCheckXCommand对象,在这其中例如使用MR,则会生成JavaActionExecutor 类型的执行器。

4.执行这个执行器中的check方法。根据jobId生成jobClient获取HADOOP中正在运行的RUNNING JOB

5.如果job.isComplete(),会判断任务是否结束。结束是否运行成功,有相应接口。(判断成功与否包括org.apache.hadoop.mapred.Counters)代码位于:

/oozie/action/hadoop/LauncherMapperHelper/isMainSucessful。成功返回SUCCESSED,失败FAILED

6.如果任务未结束,则任务设置为RUNNING

最终每次jobClient查询结束需要close()Oozie会将每次运行的状态信息存储于数据库中。

 

5.2Azkaban判断任务是否完成

Azkaban在提交任务之后会在Client运行一个Process,不断的向Server发送查询请求。发送的请求:

/executor?execid=55&ajax=fetchexecflowupdate&lastUpdateTime=1470735951842

ServerAzkaban会维护一个ConcurrentHashMap存储着执行的flow。这个hashmap是放在内存中的。由于Azkaban操作的颗粒度是进程,进程的执行成功或者失败都会影响这个hashmap

但是进程的执行结果无法直接反应任务是否执行成功。

六.总结

综上述的几点对比Oozie以及Azkaban,个人觉得选择Oozie作为流程引擎的选型比较好,理由如下:

1.Oozie是基于Hadoop系统进行操作,而Azkaban是基于命令行进行操作。使用hadoop提供的第三方包JobClient比直接在底层跑shell命令开发成本小,可能遇到的坑也少(一个是基于平台,一个是基于系统)。

2.Oozie的操作是放在Hadoop中,而Azkaban的运行是服务器运行shell命令。为保证服务器的稳定,使用Oozie靠谱点。

3.Ooize提供查询任务执行状态,Azkaban查询的是进程执行的结果,如果某进程执行的shell命令出错,其进程仍展示位成功,混淆了任务输出。

4.Oozie将任务执行的状态持久化到数据库中,Azkaban将任务的状态存储在服务器内存中,如果掉电,则Azkaban会丢失任务信息。

5.Ooize中定义的action类型更为丰富,而Azkaban中的依赖较为简单,当面对复杂的逻辑时Oozie执行的比较顺畅(网上说的,但是没有实践的数据。。。)。

 

Oozie作为流程引擎的难点:

1.定义workflow.xml的过程,需要保证有效的完成用户的逻辑且运行的过程中job不出错。

2.部署有点麻烦。

3.学习的成本会略高。

你可能感兴趣的:(oozie)