Oozie是一种java web应用程序,它运行在java servlet容器中,并使用数据库来存储一下内容:
Oozie工作流失放置在控制依赖DAG(有向无环图)中的一组动作(例如:hadoop的Map/Reduce作业、pig作业等),其中指定了动作执行的顺序。我们会使用hPDL(一种xml流程定义语言)来描述这个图。
hPDL是一种很简洁的语言,只会使用少数流程控制和动作节点。控制节点会定义执行的流程,并包含工作流的起点和终点(start、end和fail节点)以及控制工作流执行路径的机制(decision、fork和join节点)。动作节点是一些机制,通过他们工作流会触发执行计算或者处理任务。Oozie为一下类型的动作提供支持:Hadoop map-reduce、hadoop文件系统、pig、java和Oozie的子工作流(ssh动作已经从Oozie schema0.2之后的版本中移除了)。
所有动作节点处罚的计算和处理任务都不在Oozie之中—他们是由hadoop的map/reduce框架执行的。这种方法让oozie可以支持现在的hadoop用于负载均衡、灾难恢复的机制。这些任务主要是异步执行的(只有文件系统动作例外,它是同步处理的)。这意味着对于大多数工作触发的计算或处理任务的类型来说,在工作流操作转换到工作流的下一个节点之前都需要等待,直到计算或处理任务结束了之后才能够继续。Oozie可以通过两种不同的方式来检测计算或处理任务是否完成,也就是回调和轮询。当Oozie启动了计算或处理任务的时候,它会为任务提供唯一的回调URL,然后任务会在完成的时候发送通知给特定的URL。在任务无法触发回调URL的情况下(可能是因为任何原因,比方说网络闪断),或者当任务的类型无法在完成时触发回调URL的时候,Oozie有一种机制,可以对计算或处理任务进行轮询,从而保证能够完成任务。
Oozie工作流可以参数化(在工作流定义中使用像${inputDir}之类的变量)。在提交工作流操作的时候,我们必须提供参数值。如果经过合适地参数化(比方说,使用不同的输出目录),那么多个同样的工作流操作可以并发。
一些工作流是根据需要触发的,但是大多数情况下,我们有必要基于一定的时间段和(或)数据可用性和(或)外部事件来运行它们。Oozie协调系统(Coordinator system)让用户可以基于这些参数来定义工作流执行计划。Oozie协调程序让我们可以以谓词的方式对工作流执行触发器进行建模,那可以指向数据、事件和(或)外部事件。工作流作业会在谓词得到满足的时候启动。
经常我们还需要连接定时运行、但时间间隔不同的工作流操作。多个随后运行的工作流的输出会成为下一个工作流的输入。把这些工作流连接在一起,会让系统把它作为数据应用的管道来引用。Oozie协调程序支持创建这样的数据应用管道。
Oozie工作流程定义是一个DAG图,它由控制流节点或动作节点组成,各个节点又是通过转移的剑线相互连通。对于工作流一般对应存在流程定义语言,大多数都是基于XML定义的,oozie就是基于xml定义的,称为hPDL(hadoop process definition lanaguage).
当一个已经被创建的工作流Job开始执行的时候,就处于RUNNING状态。它不会达到结束状态,只能因为出错而结束,或者被挂起。
一个RUNNING状态的工作流Job会变成SUSPENDED状态,而且它会一直处于该状态,除非这个工作流Job被重新开始执行或者被杀死。
当一个RUNNING状态的工作流Job到达了end节点,它就变成了SUCCEEDED最终完成状态。
当一个工作流Job处于被创建后的状态,或者处于RUNNING、SUSPENDED状态时,被杀死,则工作流Job的状态变为KILLED状态。
上述各种状态存在相应的转移(工作流程因为某些事件,可能从一个状态跳转到另一个状态),其中合法的状态转移有如下几种,如下表所示:
工作流程定义中,控制工作流的开始和结束,以及工作流job的执行路径的几点,它定义了流程的开始(start节点)和结束(end节点和kill节点),同时提供了一种控制流程执行路径的机制(decision决策节点、fork分支节点、join会签节点)。通过上面提到的各种节点,我们大概应该能够知道他们的工作流中起着怎样的作用。下面是各节点的语法格式:
达到该节点,工作流job会变成success状态,表示成功完成。需要注意的是,一个工作流定义必须只能有一个end节点。
Kill元素的name属性,是要杀死的工作流节点的名称,message元素指定了工作流节点被杀死的备注信息。达到该节点,工作流job会变成状态KILLED。
Decision节点通过预定义一组条件,当工作流job执行到该节点时,会根据其中的条件进行判断选择,满足条件的路径将被执行。Decision节点通过switch…case语法来进行路径选择,只要有满足条件的判断,就会执行对应的路径,如果没有可以配置default元素指向的节点。
Fork元素下面会有多个path元素,指定了可以并发执行的多个执行路径。Fork中多个并发执行路径会在join节点的位置会和,只有所有的路径都到达后,才会继续执行join节点。
工作流程定义中,能够触发一个计算任务或者处理任务执行的节点。所有的动作(Action)都有一些基本的特性,如下:
*远程执行:对于Oozie来说动作节点的执行都是远程的,因为Oozie可能部署在一个单独的服务器上,而工作流job实在hadoop集群的节点上执行的。即使Oozie在hadoop集群的某个节点上,它也处于与hadoop进行独立无关的JVM实例中(Oozie部署在Servlet容器当中)
*异步性:动作节点的执行,对于Oozie来说是异步的。Oozie启动一个工作流Job,这个工作流Job便开始执行。Oozie可以通过两种方式来探测工作流Job的执行情况:一种是基于回调机制,对每个任务的执行(可以看成是动作节点的执行)都对应一个唯一的URL,如果任务执行结束或者执行失败,会通过回调这个URL通知Oozie已经完成;另一种就是轮询,Oozie不停地去查询任务执行的完成状态,如果由于网络故障回调机制失败,也会使用轮询的方式来处理。
*执行结果要么成功,要么失败:如果动作节点执行成功,则会转向ok节点;如果失败则会转向error节点。
*可恢复性:如果一个动作节点执行失败,Oozie提供了一些恢复执行的策略,这个要根据失败的特点来进行:如果是状态转移过程中失败,Oozie会根据指定的重试时间间隔去重新执行;如果不是转移性质的失败,则只能通过手工干预来进行恢复;如果重试恢复执行都没有解决问题,则最终会跳转到error节点。
FS动作主要是基于HDFS的一些基本操作,如删除路径、创建路径、移动文件、设置文件全乡等等。语法格式:
map-reduce动作会在工作流Job中启动一个MapReduce Job任务运行,我们可以详细配置这个MapReduce Job。另外,可以通过map-reduce元素的子元素来配置一些其他的任务,如streaming、pipes、file、archive等等。下面给出包含这些内容的语法格式说明:
Hive主要是基于类似SQL的HQL语言的,它能够方便地操作HDFS中数据,实现对海量数据的分析工作。Hive动作的语法格式如下所示:
Sqoop是一个能够在Hadoop和结构化存储系统之间进行数据的导入导出的工具,Sqoop动作的语法格式如下:
该动作主要是通过ssh登录到一台主机,能够执行一组shell命令,它在Oozie schema 0.2中已经被删除。语法格式:
Java动作是执行一个具有main入口方法的应用程序,在Oozie工作流定义中,会作为一个MapReduce Job执行,这个Job只有一个Map任务。我们需要指定NameNode、JobTracker的信息,还有配置一个Java应用程序的JVM选项参数(java-opts),以及传给主函数(arg)。语法格式:
Sub-workflow动作是一个子流程的动作,主流程执行过程中,遇到子流程节点执行时,会一直等待子流程节点执行完成后,才能继续跳转到下一个要执行的节点。语法格式:
Oozie除了可以使用Properties文件定义一些属性之外,还提供了一些内置的EL函数,能够方便地实现流程的定义和控制,下面我们分组列表说明:
如果path不是目录或者path是一个文件,则返回-1,否则返回该path下所有文件的字节数
在我们做一个简单的hive action 的过程中,需要两个文件,一个是workflow.xml和script.q文件。分别如下:
在我们编写oozie的工作流程中,通过官网实例我们知道,在编写hive action的workflow.xml的过程中需要指定hive-site.xml文件位置。指定方式如下:
但是在实际操作过程中,我们发现即使指定了hive-site.xml的位置,但是配置文件中的配置信息并没有起作用。这个问题还在查找过程中。
当前的解决方案,就是把必要的配置信息,直接写到workflow.xml中,这样在使用的过程中就可以避免配置项不起作用的问题。
通过http的方式可以向oozie提交工作流。但是需要注意的是,我们的工作流所需要的工作环境(以hive action为例,所需文件有:script.q和workflow.xml)需要提前初始化好,这样通过http方式直接通知oozie服务器端,运行该工作流即可,下面是一个详细的例子说明(以hive action为例):
在实际的项目中,虽然要求工作环境需要提前准备好,但是在实际操作中可以非常灵活的处理,比如我们需要执行的hql需要根据上面的程序动态生成。这是我们只需要把hql语句写入到script.q文件中,然后把文件重新上传到hdfs工作目录中就可以正常工作了。
注意:在run.sh脚本中,需要传递的config.xml文件需要采用绝对路径,负责run.sh脚本中的指令找不到该文件。
再用程序的实现过程中,我们可以通过个编程语言提供的curl库动态的实现。还有一个简单的方法就是通过各种语言,启动一个管道执行shell指令,完成执行。
Oozie所支持的工作流为:通过在workflow中定义将多个action,并按照一定的顺序组织起来,然后作为一个整体按照既定的顺序和配置逐一运行。一个工作流一旦定义,通过启动该工作流job,就会执行该工作流中所包含的的多个action,直到完成,这就是工作流job的生命周期。
如果有一个工作流job,希望每天半夜00:00启动运行,我们能够想到的就是通过编写一个定时任务脚本来调度程序运行。如果有有多个工作流job,使用crontab的方式调用可能需要编写大量的脚本,还要通过脚本来控制好每个工作流job的执行时序问题,不但脚本不好维护,而且监控也不太方便。基于这样的背景,oozie提出了Coordinator的概念,将每一个工作流job作为一个动作(Action)来运行,相当于工作流定义中的一个执行节点,这样就能够将多个工作流job组织起来,称为coordinator job。可以指定触发时间和频率,还可以配置数据集、并发数等。一个coordinator job包含在job外部设置执行周期和频率的语义,类似在工作流外部增加了一个协调器来管理这些工作流的运行。
在官方发行的包中自带了一个简单的例子,它能够实现定时调度一个工作流job运行,这个例子中给出的一个空的工作流job,并通过coordinator系统系统调度起来。例子中3个配置文件,分别如下:
运行上面的命令后,在控制台上会返回这个job id,然后我们可以通过控制台查看该job id工作流执行的状态。
Control元素定义了一个Coordinator job的控制信息,主要包含如下三个配置元素:
超时时间,单位为分钟。当一个Coordinator Job启动的时候,会初始化多个Coordinator动作,timeout用来限制这个初始化过程。默认值为-1,表示永远不超时,如果为0 则总是超时。
配置多个Coordinator Job并发执行的策略:默认是FIFO。另外还有两种:LIFO(最新的先执行)、LAST_ONLY(只执行最新的Coordinator Job,其它的全部丢弃)。
Coordinator job中有一个dataset的概念,他可以为实际计算提供计算的数据,主要是指HDFS上的数据目录和文件,能够配置数据集生成的频率(Frequency)、URI模板、时间等信息,下面看一下dataset的语法格式:
上面会每天生成一个用户事件表,可以供hive查询分析,这里指定了这二个数据集的位置,后续计算会使用这部分数据。其中uri-template指定了一个匹配的模板,满足这个模板的路径都会被作为计算的基础数据。
另外,还有一种定义dataset集合的方式,将多个dataset合并成一个组来定义,语法格式如下:
注意:通过实践得知,dataset主要是为后面的input-events和output-events服务的;在dataSet中定义了数据模板,通过这个模板,可以将其配置为目录,也可以将其配置为文件路径,有用户自己选择。但是,dataSet配置的模板路径,dataSet是不会自动生成的,使用的前提是,配置的模板路径已经存在,否则,后面的程序不会运行。
一个Coordinator应用的数据事件指定了要执行一个Coordinator动作必须满足的输入条件,在Oozie当前版本,只支持使用dataset实例。
一个Coordinator动作可能会生成一个或者多个dataset实例,在oozie当前版本中,输出事件只支持输出dataset实例。
返回日期时间:从一个Coordinator动作(Action)创建时开始计算,第n个dataset实例执行时间
表示时间偏移,如果一个Coordinator动作创建时间为T,n为正数表示向时刻T之后偏移,n为负数向向时刻T之前偏移,timeUnit表示时间单位(选项有MINUTE、HOUR、DAY、MONTH、YEAR)
指定的第n天的小时数,n0表示向后数第n天的小时数,n=0表示当天小时数,n0表示向前数第n天的小时数
指定的第n个月的天数,n0表示向后数第n个月的天数,n=0表示当月的天数,n0表示向前数第n个月的天数

