Oozie入门

作者 Boris Lublinsky, Michael Segel ,译者 侯伯薇 发布于 2011年8月18日 |注意:QCon全球软件开发大会(北京)2016年4月21-23日,了解更多详情!

在Hadoop中执行的任务有时候需要把多个Map/Reduce作业连接到一起,这样才能够达到目的。[1]在Hadoop生态圈中,有一种相对比较新的组件叫做Oozie[2],它让我们可以把多个Map/Reduce作业组合到一个逻辑工作单元中,从而完成更大型的任务。本文中,我们会向你介绍Oozie以及使用它的一些方式。

什么是Oozie?

Oozie是一种Java Web应用程序,它运行在Java servlet容器——即Tomcat——中,并使用数据库来存储以下内容:

  • 工作流定义
  • 当前运行的工作流实例,包括实例的状态和变量

Oozie工作流是放置在控制依赖DAG(有向无环图 Direct Acyclic Graph)中的一组动作(例如,Hadoop的Map/Reduce作业、Pig作业等),其中指定了动作执行的顺序。我们会使用hPDL(一种XML流程定义语言)来描述这个图。

相关厂商内容

提高工程效率的各种最佳实践和典型思路

知道创宇技术副总裁余弦将担任QCon北京2016出品人

QCon北京2016大会,4月21-23日,与您相约北京国际会议中心,现在报名享8折优惠!

相关赞助商

QCon北京2016大会,4月21-23日,北京·国际会议中心,精彩内容邀您参与!

hPDL是一种很简洁的语言,只会使用少数流程控制和动作节点。控制节点会定义执行的流程,并包含工作流的起点和终点(start、end和fail节点)以及控制工作流执行路径的机制(decision、fork和join节点)。动作节点是一些机制,通过它们工作流会触发执行计算或者处理任务。Oozie为以下类型的动作提供支持: Hadoop map-reduce、Hadoop文件系统、Pig、Java和Oozie的子工作流(SSH动作已经从Oozie schema 0.2之后的版本中移除了)。

所有由动作节点触发的计算和处理任务都不在Oozie之中——它们是由Hadoop的Map/Reduce框架执行的。这种方法让Oozie可以支持现存的Hadoop用于负载平衡、灾难恢复的机制。这些任务主要是异步执行的(只有文件系统动作例外,它是同步处理的)。这意味着对于大多数工作流动作触发的计算或处理任务的类型来说,在工作流操作转换到工作流的下一个节点之前都需要等待,直到计算或处理任务结束了之后才能够继续。Oozie可以通过两种不同的方式来检测计算或处理任务是否完成,也就是回调和轮询。当Oozie启动了计算或处理任务的时候,它会为任务提供唯一的回调URL,然后任务会在完成的时候发送通知给特定的URL。在任务无法触发回调URL的情况下(可能是因为任何原因,比方说网络闪断),或者当任务的类型无法在完成时触发回调URL的时候,Oozie有一种机制,可以对计算或处理任务进行轮询,从而保证能够完成任务。

Oozie工作流可以参数化(在工作流定义中使用像${inputDir}之类的变量)。在提交工作流操作的时候,我们必须提供参数值。如果经过合适地参数化(比方说,使用不同的输出目录),那么多个同样的工作流操作可以并发。

一些工作流是根据需要触发的,但是大多数情况下,我们有必要基于一定的时间段和(或)数据可用性和(或)外部事件来运行它们。Oozie协调系统(Coordinator system)让用户可以基于这些参数来定义工作流执行计划。Oozie协调程序让我们可以以谓词的方式对工作流执行触发器进行建模,那可以指向数据、事件和(或)外部事件。工作流作业会在谓词得到满足的时候启动。

经常我们还需要连接定时运行、但时间间隔不同的工作流操作。多个随后运行的工作流的输出会成为下一个工作流的输入。把这些工作流连接在一起,会让系统把它作为数据应用的管道来引用。Oozie协调程序支持创建这样的数据应用管道。

安装Oozie

我们可以把Oozie安装在现存的Hadoop系统中,安装方式包括tarball、RPM和Debian包等。我们的Hadoop部署是Cloudera的CDH3,其中已经包含了Oozie。因此,我们只是使用yum把它拉下来,然后在edge节点[1]上执行安装操作。在Oozie的发布包中有两个组件——Oozie-client和Oozie-server。根据簇集的规模,你可以让这两个组件安装在同一台edge服务器上,也可能安装在不同的计算机上。Oozie服务器中包含了用于触发和控制作业的组件,而客户端中包含了让用户可以触发Oozie操作并与Oozie服务器通信的组件。

想要了解更多关于安装过程的信息,请使用Cloudera发布包,并访问Cloudera站点[2]

注: 除了包括安装过程的内容之外,它还建议把下面的shell变量OOZIE_URL根据需要添加到.login、.kshrc或者shell的启动文件中:

(export OOZIE_URL=http://localhost:11000/oozie)

简单示例

为了向你展示Oozie的使用方法,让我们创建一个简单的示例。我们拥有两个Map/Reduce作业[3]——一个会获取最初的数据,另一个会合并指定类型的数据。实际的获取操作需要执行最初的获取操作,然后把两种类型的数据——Lidar和Multicam——合并。为了让这个过程自动化,我们需要创建一个简单的Oozie工作流(代码1)。

<!--
Copyright (c) 2011 NAVTEQ! Inc. All rights reserved.
NGMB IPS ingestor Oozie Script
-->
<workflow-app xmlns=‘uri:oozie:workflow:0.1‘ name=‘NGMB-IPS-ingestion‘>
    <start to=‘ingestor‘/>
    <action name=‘ingestor‘>
        <java>
            <job-tracker>${jobTracker}</job-tracker>
            <name-node>${nameNode}</name-node>
            <configuration>
                <property>
                    <name>mapred.job.queue.name</name>
                    <value>default</value>
                </property>
            </configuration>
            <main-class>com.navteq.assetmgmt.MapReduce.ips.IPSLoader</main-class>
            <java-opts>-Xmx2048m</java-opts>
            <arg>${driveID}</arg>
        </java>
        <ok to="merging"/>
        <error to="fail"/>
    </action>
    <fork name="merging">
        <path start="mergeLidar"/>
        <path start="mergeSignage"/>
    </fork>
    <action name=‘mergeLidar‘>
        <java>
            <job-tracker>${jobTracker}</job-tracker>
            <name-node>${nameNode}</name-node>
            <configuration>
                <property>
                    <name>mapred.job.queue.name</name>
                    <value>default</value>
                </property>
            </configuration>
            <main-class>com.navteq.assetmgmt.hdfs.merge.MergerLoader</main-class>
            <java-opts>-Xmx2048m</java-opts>
            <arg>-drive</arg>
            <arg>${driveID}</arg>
            <arg>-type</arg>
            <arg>Lidar</arg>
            <arg>-chunk</arg>
            <arg>${lidarChunk}</arg>
        </java>
    <ok to="completed"/>
    <error to="fail"/>
    </action>
    <action name=‘mergeSignage‘>
        <java>
            <job-tracker>${jobTracker}</job-tracker>
            <name-node>${nameNode}</name-node>
            <configuration>
                <property>
                    <name>mapred.job.queue.name</name>
                    <value>default</value>
                </property>
            </configuration>
            <main-class>com.navteq.assetmgmt.hdfs.merge.MergerLoader</main-class>
            <java-opts>-Xmx2048m</java-opts>
            <arg>-drive</arg>
            <arg>${driveID}</arg>
            <arg>-type</arg>
            <arg>MultiCam</arg>
            <arg>-chunk</arg>
            <arg>${signageChunk}</arg>
        </java>
        <ok to="completed"/>
        <error to="fail"/>
    </action>
    <join name="completed" to="end"/>
    <kill name="fail">
        <message>Java failed, error message[${wf:errorMessage(wf:lastErrorNode())}]</message>
    </kill>
    <end name=‘end‘/>
</workflow-app>

代码1: 简单的Oozie工作流

这个工作流定义了三个动作:ingestor、mergeLidar和mergeSignage。并把每个动作都实现为Map/Reduce[4]作业。这个工作流从start节点开始,然后把控制权交给Ingestor动作。一旦ingestor步骤完成,就会触发fork控制节点 [4],它会并行地开始执行mergeLidar和mergeSignage[5]。这两个动作完成之后,就会触发join控制节点[6]。join节点成功完成之后,控制权就会传递给end节点,它会结束这个过程。

创建工作流之后,我们需要正确地对其进行部署。典型的Oozie部署是一个HDFS目录,其中包含workflow.xml(代码1)、config-default.xml和lib子目录,其中包含有工作流操作所要使用的类的jar文件。

(点击可以查看大图)

图1: Oozie部署

config-default.xml文件是可选的,通常其中会包含对于所有工作流实例通用的工作流参数。代码2中显示的是config-default.xml的简单示例。

<configuration>
    <property>
        <name>jobTracker</name>
        <value>sachicn003:2010</value>
    </property>
    <property>
        <name>nameNode</name>
        <value>hdfs://sachicn001:8020</value>
    </property>
    <property>
        <name>queueName</name>
        <value>default</value>
    </property>
</configuration>

代码2: Config-default.xml

完成了工作流的部署之后,我们可以使用Oozie提供的命令行工具[5],它可以用于提交、启动和操作工作流。这个工具一般会运行在Hadoop簇集[7]的edge节点上,并需要一个作业属性文件(参见配置工作流属性),见代码3。

oozie.wf.application.path=hdfs://sachicn001:8020/user/blublins/workflows/IPSIngestion
jobTracker=sachicn003:2010
nameNode=hdfs://sachicn001:8020

代码3: 作业属性文件

有了作业属性,我们就可以使用代码4中的命令来运行Oozie工作流。

oozie job –oozie http://sachidn002.hq.navteq.com:11000/oozie/ -D driveID=729-pp00002-2011-02-08-09-59-34 -D lidarChunk=4 -D signageChunk=20 -config job.properties –run

列表4: 运行工作流命令

配置工作流属性

在config-default.xml、作业属性文件和作业参数中有一些重叠,它们可以作为命令行调用的一部分传递给Oozie。尽管文档中没有清晰地指出何时使用哪个,但总体上的建议如下:

  • 使用config-default.xml定义对于指定工作流从未改变过的参数。
  • 对于给定的工作流部署通用的参数,建议使用作业属性。
  • 对于指定的工作流调用特定的参数使用命令行参数。

Oozie处理这三种参数的方式如下:

  • 使用所有命令行调用的参数
  • 如果那里有任何无法解析的参数,那么就是用作业配置来解析
  • 一旦所有其它方式都无法处理,那么就试着使用config-default.xm。

我们可以使用Oozie控制台(图2)来观察工作流执行的进程和结果。

(点击可以查看大图)

图2: Oozie控制台

我们还可以使用Oozie控制台来获得操作执行的细节,比方说作业的日志[8](图3)。

(点击可以查看大图)

图3: Oozie控制台——作业日志

编程方式的工作流调用

尽管上面所述的命令行界面能够很好地用于手动调用Oozie,但有时使用编程的方式调用Oozie更具有优势。当Oozie工作流是特定的应用程序或者大型企业过程的一部分,这就会很有用。我们可以使用Oozie Web Services APIs [6]或者Oozie Java client APIs [7]来实现这种编程方式的调用。代码5中展现的就是很简单的Oozie Java客户端的例子,它会触发上面描述的过程。

package com.navteq.assetmgmt.oozie;

import java.util.LinkedList;
import java.util.List;
import java.util.Properties;

import org.apache.oozie.client.OozieClient;
import org.apache.oozie.client.OozieClientException;
import org.apache.oozie.client.WorkflowJob;
import org.apache.oozie.client.WorkflowJob.Status;

public class WorkflowClient {

    private static String OOZIE_URL = "http://sachidn002.hq.navteq.com:11000/oozie/";
    private static String JOB_PATH = "hdfs://sachicn001:8020/user/blublins/workflows/IPSIngestion";
    private static String JOB_Tracker = "sachicn003:2010";
    private static String NAMENode = "hdfs://sachicn001:8020";

    OozieClient wc = null;

    public WorkflowClient(String url){
        wc = new OozieClient(url);
    }

    public String startJob(String wfDefinition, List<WorkflowParameter> wfParameters)
        throws OozieClientException{

        // create a workflow job configuration and set the workflow application path
        Properties conf = wc.createConfiguration();
        conf.setProperty(OozieClient.APP_PATH, wfDefinition);

        // setting workflow parameters
        conf.setProperty("jobTracker", JOB_Tracker);
        conf.setProperty("nameNode", NAMENode);
        if((wfParameters != null) && (wfParameters.size() > 0)){
            for(WorkflowParameter parameter : wfParameters)
                conf.setProperty(parameter.getName(), parameter.getValue());
        }
        // submit and start the workflow job
        return wc.run(conf);
    }

    public Status getJobStatus(String jobID) throws OozieClientException{
        WorkflowJob job = wc.getJobInfo(jobID);
        return job.getStatus();
    }

    public static void main(String[] args) throws OozieClientException, InterruptedException{

        // Create client
        WorkflowClient client = new WorkflowClient(OOZIE_URL);
        // Create parameters
        List<WorkflowParameter> wfParameters = new LinkedList<WorkflowParameter>();
        WorkflowParameter drive = new WorkflowParameter("driveID","729-pp00004-2010-09-01-09-46");
        WorkflowParameter lidar = new WorkflowParameter("lidarChunk","4");
        WorkflowParameter signage = new WorkflowParameter("signageChunk","4");
        wfParameters.add(drive);
        wfParameters.add(lidar);
        wfParameters.add(signage);
        // Start Oozing
        String jobId = client.startJob(JOB_PATH, wfParameters);
        Status status = client.getJobStatus(jobId);
        if(status == Status.RUNNING)
             System.out.println("Workflow job running");
        else
             System.out.println("Problem starting Workflow job");
    }
}

代码5: 简单的Oozie Java客户端

在此,我们首先使用Oozie服务器URL对工作流客户端进行初始化。初始化过程完成之后,我们就可以使用客户端提交并启动作业(startJob方法),获得正在运行的作业的状态(getStatus方法),以及进行其他操作。

构建java动作,向工作流传递参数

在之前的示例中,我们已经展示了如何使用标签向Java节点传递参数。由于Java节点是向Oozie引入自定义计算的主要方法,因此能够从Java节点向Oozie传递数据也同样重要。

根据Java节点的文档[3],我们可以使用“capture-output””元素把Java节点生成的值传递回给Oozie上下文。然后,工作流的其它步骤可以通过EL-functions访问这些值。返回值需要以Java属性格式文件写出来。我们可以通过“JavaMainMapper.OOZIE_JAVA_MAIN_CAPTURE_OUTPUT_FILE”常量从System属性中获得这些属性文件的名称。代码6是一个简单示例,演示了如何完成这项操作。

package com.navteq.oozie;
import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.Properties;

public class GenerateLookupDirs {

    /**
    * @param args
    */
    public static final long dayMillis = 1000 * 60 * 60 * 24;
    private static final String OOZIE_ACTION_OUTPUT_PROPERTIES = "oozie.action.output.properties";

    public static void main(String[] args) throws Exception {
        Calendar curDate = new GregorianCalendar();
        int year, month, date;
        String propKey, propVal;

        String oozieProp = System.getProperty(OOZIE_ACTION_OUTPUT_PROPERTIES);
        if (oozieProp != null) {
            File propFile = new File(oozieProp);
            Properties props = new Properties();

            for (int i = 0; I < 8; ++i) {
                year = curDate.get(Calendar.YEAR);
                month = curDate.get(Calendar.MONTH) + 1;
                date = curDate.get(Calendar.DATE);
                propKey = "dir"+i;
                propVal = year + "-" +
                    (month < 10 ? "0" + month : month) + "-" +
                    (date < 10 ? "0" + date : date);
                props.setProperty(propKey, propVal);
                curDate.setTimeInMillis(curDate.getTimeInMillis() - dayMillis);
            }
            OutputStream os = new FileOutputStream(propFile);
            props.store(os, "");
            os.close();
        } else
            throw new RuntimeException(OOZIE_ACTION_OUTPUT_PROPERTIES
             + " System property not defined");
        }
}

代码6: 向Oozie传递参数

在这个示例中,我们假设在HDFS中有针对每个日期的目录。这样,这个类首先会获得当前日期,然后再获得离现在最近的7个日期(包括今天),然后把目录名称传递回给Oozie。

结论

在本文我们介绍了Oozie,它是针对Hadoop的工作流引擎,并且提供了使用它的简单示例。在下一篇文章中,我们会看到更复杂的例子,让我们可以更进一步讨论Oozie的特性。

致谢

非常感谢我们在Navteq的同事Gregory Titievsky,他为我们提供了一些例子。

关于作者

Boris Lublinsky是NAVTEQ公司的首席架构师,在这家公司中他的工作是为大型数据管理和处理、SOA以及实现各种NAVTEQ的项目定义架构的愿景。 他还是InfoQ的SOA编辑,以及OASIS的SOA RA工作组的参与者。Boris是一位作者,还经常发表演讲,他最新的一本书是《Applied SOA》。

Michael Segel在过去二十多年间一直与客户写作,识别并解决他们的业务问题。 Michael已经作为多种角色、在多个行业中工作过。他是一位独立顾问,总是期望能够解决所有有挑战的问题。Michael拥有俄亥俄州立大学的软件工程学位。



[1]edge节点是安装有Hadoop库的计算机,但不是真正簇集中的一部分。它是为能够连接到簇集中的应用程序所用的,并且会部署辅助服务以及能够直接访问簇集的最终用户应用程序。

[2]请参看Oozie安装的链接。

[3]这些作业的细节和本文无关,所以在其中没有描述。

[4]Map/Reduce作业能够以两种不同的方式在Oozie中实现——第一种是作为真正的Map/Reduce动作[2],其中你会指定Mapper和Reducer类以及它们的配置信息;第二种是作为Java动作[3],其中你会使用Hadoop API来指定启动Map/Reduce作业的类。因为我们所有的Java主函数都是使用Hadoop API,并且还实现了一些额外的功能,所以我们选择了第二种方法。

[5] Oozie确保两个动作会并行地提交给作业跟踪程序。在执行过程中实际的并行机制并不在Oozie的控制之内,并且依赖于作业的需求、簇集的能力以及Map/Reduce部署所使用的调度程序。

[6]join动作的功能是要同步fork动作启动的多个并行执行的线程。如果fork启动的所有执行的线程都能够成功完成,那么join动作就会等待它们全部完成。如果有至少一个线程执行失败,kill节点会“杀掉”剩余运行的线程。

[7] 这个节点不需要是安装了Oozie的计算机。

[8] Oozie的作业日志会包含工作流执行的细节,想要查看动作执行的细节,我们需要切换到Hadoop的Map/Reduce管理页面。

查看英文原文:Introduction to Oozie



给InfoQ中文站投稿或者参与内容翻译工作,请邮件至[email protected]。也欢迎大家加入到InfoQ中文站用户讨论组中与我们的编辑和其他读者朋友交流。

时间: 2024-10-03 16:37:59

Oozie入门的相关文章

课程路线

---恢复内容开始--- 云计算&大数据实战课程列表 first.课程说明: 本系列课程适合有一点编程基础的人员学习(比如java,python,c/c++),最好是java编程人员,特别是从事过j2ee开发的人员.学习完本套课程,可以帮助你成为大型项目架构师,特别是数据量大,并发量高的大型项目架构师,当然也能很大程度上提高你的薪资待遇. second.课程路线 third.Linux大纲 这章是基础课程,帮大家进入大数据领域打好Linux基础,以便更好地学习Hadoop,NoSQL,Oracl

大数据入门:各种大数据技术介绍

转自:http://www.aboutyun.com/thread-7569-1-1.html 大数据我们都知道hadoop,可是还会各种各样的技术进入我们的视野:Spark,Storm,impala,让我们都反映不过来.为了能够更好的架构大数据项目,这里整理一下,供技术人员,项目经理,架构师选择合适的技术,了解大数据各种技术之间的关系,选择合适的语言.我们可以带着下面问题来阅读本文章:1.hadoop都包含什么技术2.Cloudera公司与hadoop的关系是什么,都有什么产品,产品有什么特性

大数据入门基础系列之初步认识大数据生态系统圈(博主推荐)

之前在微信公众平台里写过 大数据入门基础系列之初步认识hadoop生态系统圈 http://mp.weixin.qq.com/s/KE09U5AbFnEdwht44FGrOA 大数据入门基础系列之初步认识大数据生态系统圈 1.概述 最近收到一些同学和朋友的邮件,说能不能整理一下 Hadoop 生态圈的相关内容,然后分享一些,我觉得这是一个不错的提议,于是,花了一些业余时间整理了 Hadoop 的生态系统,并将其进行了归纳总结,进而将其以表格的形式进行了罗列.涉及的内容有以下几点: 分布式文件系统

大数据学习应该如何入门

一.整体了解数据分析--5小时 新人们被"大数据"."人工智能"."21世纪是数据分析师的时代"等等信息吸引过来,立志成为一名数据分析师,于是问题来了,数据分析到底是干什么的?数据分析都包含什么内容? 市面上有很多讲数据分析内容的书籍,在此我推荐<深入浅出数据分析>,此书对有基础人士可称消遣读物, 但对新人们还是有一定的作用.阅读时可不求甚解,重点了解数据分析的流程.应用场景.以及书中提到的若干数据分析工具,无需纠结分析模型的实现.5

大数据入门学习路线分享,请大家收下

大数据的学习技术点Hadoop核心(1) 分布式存储基石:HDFSHDFS简介 入门演示 构成及工作原理解析:数据块,NameNode, DataNode.数据写入与读取过程.数据复制.HA方案.文件类型. HDFS常用设置 Java API代码演示(2) 分布式计算基础:MapReduceMapReduce简介.编程模型.Java API 介绍.编程案例介绍.MapReduce调优(3) Hadoop集群资源管家:YARNYARN基本架构 资源调度过程 调度算法 YARN上的计算框架离线计算(

大数据学习方向,从入门到精通

推荐一个大数据学习群 119599574晚上20:10都有一节[免费的]大数据直播课程,专注大数据分析方法,大数据编程,大数据仓库,大数据案例,人工智能,数据挖掘都是纯干货分享,你愿意来学习吗 很多初学者在萌生向大数据方向发展的想法之后,不免产生一些疑问,应该怎样入门?应该学习哪些技术?学习路线又是什么? 所有萌生入行的想法与想要学习Java的同学的初衷是一样的.岗位非常火,就业薪资比较高,,前景非常可观.基本都是这个原因而向往大数据,但是对大数据却不甚了解. 如果你想学习,那么首先你需要学会编

大数据hadoop入门之hadoop家族详解

大数据这个词也许几年前你听着还会觉得陌生,但我相信你现在听到hadoop这个词的时候你应该都会觉得"熟悉"!越来越发现身边从事hadoop开发或者是正在学习hadoop的人变多了.作为一个hadoop入门级的新手,你会觉得哪些地方很难呢?运行环境的搭建恐怕就已经足够让新手头疼.如果每一个发行版hadoop都可以做到像大快DKHadoop那样把各种环境搭建集成到一起,一次安装搞定所有,那对于新手来说将是件多么美妙的事情!闲话扯得稍微多了点,回归整体.这篇准备给大家hadoop新入门的朋友

新手入门大数据,理清学习路线是关键

学习大数据,首先我们要学习Java语言和Linux操作系统,这两个是学习大数据的基础,学习的顺序不分前后.Java:大家都知道Java的方向有JavaSE.JavaEE.JavaME,学习大数据要学习那个方向呢?只需要学习Java的标准版JavaSE就可以了,像Servlet.JSP.Tomcat.Struts.Spring.Hibernate,Mybatis都是JavaEE方向的技术在大数据技术里用到的并不多,只需要了解就可以了,当然Java怎么连接数据库还是要知道的,像JDBC一定要掌握一下

大数据技术之Hadoop入门

? 第1章 大数据概论 1.1 大数据概念 大数据概念如图2-1 所示. 图2-1 大数据概念 1.2 大数据特点(4V) 大数据特点如图2-2,2-3,2-4,2-5所示 图2-2 大数据特点之大量 图2-3 大数据特点之高速 图2-4 大数据特点之多样 图2-5 大数据特点之低价值密度 1.3 大数据应用场景 大数据应用场景如图2-6,2-7,2-8,2-9,2-10,2-11所示 图2-6 大数据应用场景之物流仓储 图2-7 大数据应用场景之零售 图2-8 大数据应用场景之旅游 图2-9