大数据之azkaban与oozie

  当我们要做一个主题分析时,基本上都会有这样一个流程,采集数据,数据预处理,数据入库,数据分析等一系列的操作。但是这些操作往往我们需要布置做一遍,有时候甚至需要定时定点的去做,比如数据采集。当我们每天都需要做一系列的重复的工作时,我们肯定首先就是想到,能不能我只做一遍,剩下的交给一个机器人自动帮我完成或者交给电脑自动帮我完成。

  这时候领克就推出了一款叫做azkaban的工作流调度软件,是开源免费的。我们的Apache基金会呢也有一款开源的工作流调度软件,名为oozie。它俩都是作为工作流调度的软件,都能帮我们实现一系列工作的调度,但是它们之间实现的原理却不太一样。

Azkaban与Oozie的介绍

  Azkaban是由linkedin(领英)公司推出的一个批量工作流任务调度器,用于在一个工作流内以一个特定的顺序运行一组工作和流程。Azkaban使用job配置文件建立任务之间的依赖关系,并提供一个易于使用的web用户界面维护和跟踪你的工作流。

  Oozie 是一个用来管理 Hadoop生态圈job的工作流调度系统。由Cloudera公司贡献给Apache。Oozie是运行于Java servlet容器上的一个java web应用。Oozie的目的是按照DAG(有向无环图)调度一系列的Map/Reduce或者Hive等任务。Oozie 工作流由hPDL(Hadoop Process Definition Language)定义(这是一种XML流程定义语言)。

Azkaban与Oozie的原理

  Azkaban:

        

  mysql服务器: 存储元数据,如项目名称、项目描述、项目权限、任务状态、SLA规则等

   AzkabanWebServer:对外提供web服务,使用户可以通过web页面管理。职责包括项目管理、权限授权、任务调度、监控executor。

   AzkabanExecutorServer:负责具体的工作流的提交、执行。

  Oozie:

Oozie对工作流的编排,是基于workflow.xml文件来完成的。用户预先将工作流执行规则定制于workflow.xml文件中,并在job.properties配置相关的参数,然后由Oozie Server向MR提交job来启动工作流。

Azkaban与Oozie的安装

  Azkaban:

    Azkaban三种部署模式

    1. solo server mode:该模式中webServer和executorServer运行在同一个进程中,进程名是AzkabanSingleServer。使用自带的H2数据库。这种模式包含Azkaban的所有特性,但一般用来学习和测试。
    2. two-server mode: 该模式使用MySQL数据库, Web Server和Executor Server运行在不同的进程中。
    3. multiple-executor mode该模式使用MySQL数据库, Web Server和Executor Server运行在不同的机器中。且有多个Executor Server。该模式适用于大规模应用。

      Azkaban源码编译

      Azkaban3.x在安装前需要自己编译成二进制包。并且提前安装好Maven、Ant、Node等软件。

      编译环境

      yum install –y git

      yum install –y gcc-c++

     下载源码并解压

      wget https://github.com/azkaban/azkaban/archive/3.51.0.tar.gz

      tar -zxvf 3.51.0.tar.gz

      cd ./azkaban-3.51.0/

      编译源码

      ./gradlew build installDist -x test

      编译成功之后就可以在指定的路径下取得对应的安装包了。

      #solo-server模式安装包路径

      azkaban-solo-server/build/distributions/

      #two-server模式和multiple-executor模式web-server安装包路径

      azkaban-web-server/build/distributions/

      #two-server模式和multiple-executor模式exec-server安装包路径

      azkaban-exec-server/build/distributions/

      #数据库相关安装包路径

      azkaban-db/build/distributions/

      Azkaban的安装,这里就不讲solo模式的和two server模式的了,步骤都是一样的,只是安装的机器不同而已。

         节点规划

          

        安装包解压到指定目录

         mkdir /export/servers/azkaban

         tar -zxvf azkaban-web-server-0.1.0-SNAPSHOT.tar.gz –C /export/servers/azkaban/

         tar -zxvf azkaban-exec-server-0.1.0-SNAPSHOT.tar.gz –C /export/servers/azkaban/

          配置web-server服务器

        生成ssl证书:

          keytool -keystore keystore -alias jetty -genkey -keyalg RSA

          运行此命令后,会提示输入当前生成keystore的密码及相应信息,输入的密码请记住。

          完成上述工作后,将在当前目录生成keystore证书文件,将keystore拷贝到 azkaban web服务器根目录中。

          如: cp keystore azkaban-web-server-0.1.0-SNAPSHOT/

        配置conf/azkaban.properties:   

# Azkaban Personalization Settings
azkaban.name=Test
azkaban.label=My Local Azkaban
azkaban.color=#FF3601
azkaban.default.servlet.path=/index
web.resource.dir=web/
default.timezone.id=Asia/Shanghai # 时区注意后面不要有空格

# Azkaban UserManager class
user.manager.class=azkaban.user.XmlUserManager
user.manager.xml.file=conf/azkaban-users.xml

# Azkaban Jetty server properties. 开启使用ssl 并且知道端口
jetty.use.ssl=true
jetty.ssl.port=8443
jetty.maxThreads=25

# Azkaban Executor settings  指定本机Executor的运行端口
executor.host=localhost
executor.port=12321

#  KeyStore for SSL ssl相关配置  注意密码和证书路径
jetty.keystore=keystore
jetty.password=123456
jetty.keypassword=123456
jetty.truststore=keystore
jetty.trustpassword=123456

# Azkaban mysql settings by default. Users should configure their own username and password.
database.type=mysql
mysql.port=3306
mysql.host=node-1
mysql.database=azkaban_two_server
mysql.user=root
mysql.password=hadoop
mysql.numconnections=100

#Multiple Executor 设置为false
azkaban.use.multiple.executors=true
#azkaban.executorselector.filters=StaticRemainingFlowSize,MinimumFreeMemory,CpuStatus 
azkaban.executorselector.comparator.NumberOfAssignedFlowComparator=1
azkaban.executorselector.comparator.Memory=1
azkaban.executorselector.comparator.LastDispatched=1
azkaban.executorselector.comparator.CpuUsage=1

        添加azkaban.native.lib=false 和 execute.as.user=false属性:

1 mkdir -p plugins/jobtypes
2 
3 vim commonprivate.properties
4 #键入下方代码
5 azkaban.native.lib=false
6 
7 execute.as.user=false
8 
9 memCheck.enabled=false

       exec-server服务器配置

        配置conf/azkaban.properties:

 1 # Azkaban Personalization Settings
 2 azkaban.name=Test
 3 azkaban.label=My Local Azkaban
 4 azkaban.color=#FF3601
 5 azkaban.default.servlet.path=/index
 6 web.resource.dir=web/
 7 default.timezone.id=Asia/Shanghai
 8 
 9 # Azkaban UserManager class
10 user.manager.class=azkaban.user.XmlUserManager
11 user.manager.xml.file=conf/azkaban-users.xml
12 
13 # Loader for projects
14 executor.global.properties=conf/global.properties
15 azkaban.project.dir=projects
16 
17 # Where the Azkaban web server is located
18 azkaban.webserver.url=https://node-2:8443
19 
20 # Azkaban mysql settings by default. Users should configure their own username and password.
21 database.type=mysql
22 mysql.port=3306
23 mysql.host=node-1
24 mysql.database=azkaban_two_server
25 mysql.user=root
26 mysql.password=hadoop
27 mysql.numconnections=100
28 
29 # Azkaban Executor settings
30 executor.maxThreads=50
31 executor.port=12321
32 executor.flow.threads=30

      集群启动

          先启动exec-server,再启动web-server。启动webServer之后进程失败消失,可通过安装包根目录下对应启动日志进行排查。

          

           需要手动激活executor

            cd  /export/servers/azkaban/execserver

            curl -G "node-2:$(<./executor.port)/executor?action=activate" && echo

          

             然后重新启动webServer就可以了。

  Oozie:

      修改hadoop相关配置

        配置httpfs服务 

        修改hadoop的配置文件 core-site.xml

 1 <!--允许通过httpfs方式访问hdfs的主机名、域名;-->
 2 <property>
 3         <name>hadoop.proxyuser.root.hosts</name>
 4         <value>*</value>
 5 </property>
 6 <!--允许访问的客户端的用户组-->
 7 <property>
 8         <name>hadoop.proxyuser.root.groups</name>
 9         <value>*</value>
10 </property>

         配置jobhistory服务

        修改hadoop的配置文件mapred-site.xml

 1 <property>
 2   <name>mapreduce.jobhistory.address</name>
 3   <value>node-1:10020</value>
 4   <description>MapReduce JobHistory Server IPC host:port</description>
 5 </property>
 6 
 7 <property>
 8   <name>mapreduce.jobhistory.webapp.address</name>
 9   <value>node-1:19888</value>
10   <description>MapReduce JobHistory Server Web UI host:port</description>
11 </property>
12 <!-- 配置运行过的日志存放在hdfs上的存放路径 -->
13 <property>
14     <name>mapreduce.jobhistory.done-dir</name>
15     <value>/export/data/history/done</value>
16 </property>
17 
18 <!-- 配置正在运行中的日志在hdfs上的存放路径 -->
19 <property>
20     <name>mapreduce.jobhistory.intermediate-done-dir</name>
21     <value>/export/data/history/done_intermediate</value>
22 </property>

        重启history-server服务、重启Hadoop集群服务。

        上传oozie的安装包并解压

        oozie的安装包上传到/export/softwares

          tar -zxvf oozie-4.1.0-cdh5.14.0.tar.gz

        解压hadooplibs到与oozie平行的目录

          cd /export/servers/oozie-4.1.0-cdh5.14.0

          tar -zxvf oozie-hadooplibs-4.1.0-cdh5.14.0.tar.gz -C ../

        添加相关依赖

          oozie的安装路径下创建libext目录

            cd /export/servers/oozie-4.1.0-cdh5.14.0

            mkdir -p libext

          拷贝hadoop依赖包到libext

            cd /export/servers/oozie-4.1.0-cdh5.14.0

            cp -ra hadooplibs/hadooplib-2.6.0-cdh5.14.0.oozie-4.1.0-cdh5.14.0/* libext/

          上传mysql的驱动包到libext

            mysql-connector-java-5.1.32.jar

          添加ext-2.2.zip压缩包到libext

            ext-2.2.zip

          修改oozie-site.xml

          cd /export/servers/oozie-4.1.0-cdh5.14.0/conf

          vim oozie-site.xml

          oozie默认使用的是UTC的时区,需要在oozie-site.xml当中配置时区为GMT+0800时区

 1      <property>
 2         <name>oozie.service.JPAService.jdbc.driver</name>
 3         <value>com.mysql.jdbc.Driver</value>
 4     </property>
 5     <property>
 6         <name>oozie.service.JPAService.jdbc.url</name>
 7         <value>jdbc:mysql://node-1:3306/oozie</value>
 8     </property>
 9     <property>
10         <name>oozie.service.JPAService.jdbc.username</name>
11         <value>root</value>
12     </property>
13     <property>
14         <name>oozie.service.JPAService.jdbc.password</name>
15         <value>hadoop</value>
16     </property>
17     <property>
18             <name>oozie.processing.timezone</name>
19             <value>GMT+0800</value>
20     </property>
21 
22     <property>
23         <name>oozie.service.coord.check.maximum.frequency</name>
24         <value>false</value>
25     </property>     
26 
27     <property>
28         <name>oozie.service.HadoopAccessorService.hadoop.configurations</name>
29         <value>*=/export/servers/hadoop-2.7.5/etc/hadoop</value>
30     </property>

           初始化mysql相关信息

          上传oozie的解压后目录的下的yarn.tar.gz到hdfs目录

              bin/oozie-setup.sh  sharelib create -fs hdfs://node-1:9000 -locallib oozie-sharelib-4.1.0-cdh5.14.0-yarn.tar.gz

          本质上就是将这些jar包解压到了hdfs上面的路径下面去

          创建mysql数据库

              mysql -uroot -p

              create database oozie;

          初始化创建oozie的数据库表

              cd /export/servers/oozie-4.1.0-cdh5.14.0

              bin/oozie-setup.sh  db create -run -sqlfile oozie.sql

          打包项目,生成war包

              cd /export/servers/oozie-4.1.0-cdh5.14.0

              bin/oozie-setup.sh  prepare-war

         配置oozie环境变量     

1 vim /etc/profile
2 export OOZIE_HOME=/export/servers/oozie-4.1.0-cdh5.14.0
3 export OOZIE_URL=http://node03.hadoop.com:11000/oozie
4 export PATH=$PATH:$OOZIE_HOME/bin
5 source /etc/profile

         启动关闭oozie服务

          启动命令

            cd /export/servers/oozie-4.1.0-cdh5.14.0

            bin/oozied.sh start

          关闭命令

            bin/oozied.sh stop

          如果意外关闭或者关机没关闭,那么重启之后再次启动会报错,需先删除上次启动时产生的pid文件,并且kill刚刚启动失败的进程,再次启动即可

            

          浏览器web UI页面

          http://node-1:11000/oozie/

Azkaban与Oozie实战

    Azkaban使用实战

      shell command调度

        创建job描述文件

        vim command.job

#command.job
type=command                                                    
command=echo 'hello'

      将job资源文件打包成zip文件

        zip command.job

      通过azkaban的web管理平台创建project并上传job压缩包

      首先创建Project

        

       上传zip包

        

       启动执行该job

        

         job依赖调度

         创建有依赖关系的多个job描述

            第一个job:foo.job

1 # foo.job
2 type=command
3 command=echo foo

            第二个job:bar.job依赖foo.job

1 # bar.job
2 type=command
3 dependencies=foo
4 command=echo bar

           将所有job资源文件打到一个zip包中

           在azkaban的web管理界面创建工程并上传zip包

            启动工作流flow

     HDFS任务调度

1 # fs.job
2 type=command
3 command=/home/hadoop/apps/hadoop-2.6.1/bin/hadoop fs -mkdir /azaz

        除了job文件内容不一样,其他步骤都是一致的

     MAPREDUCE任务调度

1 # mrwc.job
2 type=command
3 command=/home/hadoop/apps/hadoop-2.6.1/bin/hadoop  jar hadoop-mapreduce-examples-2.6.1.jar wordcount /wordcount/input /wordcount/azout

      除了job文件内容不一样,其他步骤都是一致的

    HIVE脚本任务调度

1 # hivef.job
2 type=command
3 command=/home/hadoop/apps/hive/bin/hive -f 'test.sql'

      除了job文件内容不一样,其他步骤都是一致的,这里既可以执行SQL文件也可以执行SQL语句,语法见hive篇

      定时任务调度

    

     上述图片中,选择左边schedule表示配置定时调度信息,选择右边execute表示立即执行工作流任务。

    

   Oozie使用实战:

      yarn容器资源分配属性

        yarn-site.xml  

 1 <!—节点最大可用内存,结合实际物理内存调整 -->
 2 <property>
 3         <name>yarn.nodemanager.resource.memory-mb</name>
 4         <value>3072</value>
 5 </property>
 6 <!—每个容器可以申请内存资源的最小值,最大值 -->
 7 <property>
 8         <name>yarn.scheduler.minimum-allocation-mb</name>
 9         <value>1024</value>
10 </property>
11 <property>
12         <name>yarn.scheduler.maximum-allocation-mb</name>
13         <value>3072</value>
14 </property>
15 
16 <!—修改为Fair公平调度,动态调整资源,避免yarn上任务等待(多线程执行) -->
17 <property>
18  <name>yarn.resourcemanager.scheduler.class</name>
19  <value>org.apache.hadoop.yarn.server.resourcemanager.scheduler.fair.FairScheduler</value>
20 </property>
21 <!—Fair调度时候是否开启抢占功能 -->
22 <property>
23         <name>yarn.scheduler.fair.preemption</name>
24         <value>true</value>
25 </property>
26 <!—超过多少开始抢占,默认0.8-->
27     <property>
28         <name>yarn.scheduler.fair.preemption.cluster-utilization-threshold</name>
29         <value>1.0</value>
30 </property>

       mapreduce资源申请配置

        设置mapreduce.map.memory.mb和mapreduce.reduce.memory.mb配置

          否则Oozie读取的默认配置 -1, 提交给yarn的时候会抛异常Invalid resource request, requested memory < 0, or requested memory > max configured, requestedMemory=-1, maxMemory=8192

mapred-site.xml

1 <!—单个maptask、reducetask可申请内存大小 -->
2 <property>
3         <name>mapreduce.map.memory.mb</name>
4         <value>1024</value>
5 </property>
6 <property>
7         <name>mapreduce.reduce.memory.mb</name>
8         <value>1024</value>
9 </property>

      更新hadoop配置重启集群

          重启hadoop集群

           重启oozie服务

      Oozie调度shell脚本

         准备配置模板    

#把shell的任务模板拷贝到oozie的工作目录当中去
cd /export/servers/oozie-4.1.0-cdh5.14.0
cp -r examples/apps/shell/ oozie_works/

#准备待调度的shell脚本文件
cd /export/servers/oozie-4.1.0-cdh5.14.0
vim oozie_works/shell/hello.sh
#注意:这个脚本一定要是在我们oozie工作路径下的shell路径下的位置
#!/bin/bash
echo "hello world" >> /export/servers/hello_oozie.txt

         修改配置模板

            修改job.properties

            cd /export/servers/oozie-4.1.0-cdh5.14.0/oozie_works/shell

            vim job.properties  

1 nameNode=hdfs://node-1:8020 #HadoopNameNode地址
2 jobTracker=node-1:8032    #Hadoop ResourceManager地址
3 queueName=default        
4 examplesRoot=oozie_works
5 oozie.wf.application.path=${nameNode}/user/${user.name}/${examplesRoot}/shell #地址一定要跟你上传到HDFS上的路径保持一致
6 EXEC=hello.sh

        jobTracker:在hadoop2当中,jobTracker这种角色已经没有了,只有resourceManager,这里给定resourceManager的IP及端口即可。

          queueName:提交mr任务的队列名;

          examplesRoot:指定oozie的工作目录;

          oozie.wf.application.path:指定oozie调度资源存储于hdfs的工作路径;

          EXEC:指定执行任务的名称。

      修改workflow.xml

 1 <workflow-app xmlns="uri:oozie:workflow:0.4" name="shell-wf">
 2 <start to="shell-node"/>
 3 <action name="shell-node">
 4     <shell xmlns="uri:oozie:shell-action:0.2">
 5         <job-tracker>${jobTracker}</job-tracker>
 6         <name-node>${nameNode}</name-node>
 7         <configuration>
 8             <property>
 9                 <name>mapred.job.queue.name</name>
10                 <value>${queueName}</value>
11             </property>
12         </configuration>
13         <exec>${EXEC}</exec>
14         <file>/user/root/oozie_works/shell/${EXEC}#${EXEC}</file>
15         <capture-output/>
16     </shell>
17     <ok to="end"/>
18     <error to="fail"/>
19 </action>
20 <decision name="check-output">
21     <switch>
22         <case to="end">
23             ${wf:actionData('shell-node')['my_output'] eq 'Hello Oozie'}
24         </case>
25         <default to="fail-output"/>
26     </switch>
27 </decision>
28 <kill name="fail">
29     <message>Shell action failed, error message[${wf:errorMessage(wf:lastErrorNode())}]</message>
30 </kill>
31 <kill name="fail-output">
32     <message>Incorrect output, expected [Hello Oozie] but was [${wf:actionData('shell-node')['my_output']}]</message>
33 </kill>
34 <end name="end"/>
35 </workflow-app>

      上传调度任务到hdfs

        注意:上传的hdfs目录为/user/root,因为hadoop启动的时候使用的是root用户,如果hadoop启动的是其他用户,那么就上传到/user/其他用户

        cd /export/servers/oozie-4.1.0-cdh5.14.0

        hdfs dfs -put oozie_works/ /user/root

       执行调度任务

        通过oozie的命令来执行调度任务

        cd /export/servers/oozie-4.1.0-cdh5.14.0

        bin/oozie job -oozie http://node-1:11000/oozie -config oozie_works/shell/job.properties  -run

     从监控界面可以看到任务执行成功了。

      

      可以通过jobhistory来确定调度时候是由那台机器执行的。

     Oozie调度Hive

    准备配置模板

      cd /export/servers/oozie-4.1.0-cdh5.14.0

      cp -ra examples/apps/hive2/ oozie_works/

     修改配置模板

      修改job.properties

        cd /export/servers/oozie-4.1.0-cdh5.14.0/oozie_works/hive2

        vim job.properties

1 nameNode=hdfs://node-1:8020
2 jobTracker=node-1:8032
3 queueName=default
4 jdbcURL=jdbc:hive2://node-1:10000/default
5 examplesRoot=oozie_works
6 
7 oozie.use.system.libpath=true
8 # 配置我们文件上传到hdfs的保存路径 实际上就是在hdfs 的/user/root/oozie_works/hive2这个路径下
9 oozie.wf.application.path=${nameNode}/user/${user.name}/${examplesRoot}/hive2

    workflow.xml无变化,之后的步骤都是一样的,执行之后可以在监控页面进行查看,但是执行之前确保hiveserver2的服务一定要启动。

   Oozie调度MapReduce    

       准备配置模板

          准备mr程序的待处理数据。用hadoop自带的MR程序来运行wordcount。

          准备数据上传到HDFS的/oozie/input路径下去

          hdfs dfs -mkdir -p /oozie/input

          hdfs dfs -put wordcount.txt /oozie/input

 

       拷贝MR的任务模板

          cd /export/servers/oozie-4.1.0-cdh5.14.0

          cp -ra examples/apps/map-reduce/ oozie_works/

        删掉MR任务模板lib目录下自带的jar包

          cd /export/servers/oozie-4.1.0-cdh5.14.0/oozie_works/map-reduce/lib

          rm -rf oozie-examples-4.1.0-cdh5.14.0.jar

 

      拷贝官方自带mr程序jar包到对应目录

          cp /export/servers/hadoop-2.7.5/share/hadoop/mapreduce/hadoop-mapreduce-examples-2.7.5.jar /export/servers/oozie-4.1.0-cdh5.14.0/oozie_works/map-reduce/lib/


      修改配置模板

          修改job.properties

          cd /export/servers/oozie-4.1.0-cdh5.14.0/oozie_works/map-reduce

          vim job.properties

1 nameNode=hdfs://node-1:8020
2 jobTracker=node-1:8032
3 queueName=default
4 examplesRoot=oozie_works
5 
6 oozie.wf.application.path=${nameNode}/user/${user.name}/${examplesRoot}/map-reduce/workflow.xml
7 outputDir=/oozie/output
8 inputdir=/oozie/input

          修改workflow.xml

          cd /export/servers/oozie-4.1.0-cdh5.14.0/oozie_works/map-reduce

          vim workflow.xml

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <workflow-app xmlns="uri:oozie:workflow:0.5" name="map-reduce-wf">
 3     <start to="mr-node"/>
 4     <action name="mr-node">
 5         <map-reduce>
 6             <job-tracker>${jobTracker}</job-tracker>
 7             <name-node>${nameNode}</name-node>
 8             <prepare>
 9                 <delete path="${nameNode}/${outputDir}"/>
10             </prepare>
11             <configuration>
12                 <property>
13                     <name>mapred.job.queue.name</name>
14                     <value>${queueName}</value>
15                 </property>
16         <!-- 开启使用新的API来进行配置 -->
17                 <property>
18                     <name>mapred.mapper.new-api</name>
19                     <value>true</value>
20                 </property>
21 
22                 <property>
23                     <name>mapred.reducer.new-api</name>
24                     <value>true</value>
25                 </property>
26 
27                 <!-- 指定MR的输出key的类型 -->
28                 <property>
29                     <name>mapreduce.job.output.key.class</name>
30                     <value>org.apache.hadoop.io.Text</value>
31                 </property>
32 
33                 <!-- 指定MR的输出的value的类型-->
34                 <property>
35                     <name>mapreduce.job.output.value.class</name>
36                     <value>org.apache.hadoop.io.IntWritable</value>
37                 </property>
38 
39                 <!-- 指定输入路径 -->
40                 <property>
41                     <name>mapred.input.dir</name>
42                     <value>${nameNode}/${inputdir}</value>
43                 </property>
44 
45                 <!-- 指定输出路径 -->
46                 <property>
47                     <name>mapred.output.dir</name>
48                     <value>${nameNode}/${outputDir}</value>
49                 </property>
50 
51                 <!-- 指定执行的map类 -->
52                 <property>
53                     <name>mapreduce.job.map.class</name>
54                     <value>org.apache.hadoop.examples.WordCount$TokenizerMapper</value>
55                 </property>
56 
57                 <!-- 指定执行的reduce类 -->
58                 <property>
59                     <name>mapreduce.job.reduce.class</name>
60                     <value>org.apache.hadoop.examples.WordCount$IntSumReducer</value>
61                 </property>
62                 <!--  配置map task的个数 -->
63                 <property>
64                     <name>mapred.map.tasks</name>
65                     <value>1</value>
66                 </property>
67 
68             </configuration>
69         </map-reduce>
70         <ok to="end"/>
71         <error to="fail"/>
72     </action>
73     <kill name="fail">
74         <message>Map/Reduce failed, error message[${wf:errorMessage(wf:lastErrorNode())}]</message>
75     </kill>
76     <end name="end"/>
77 </workflow-app>
View Code

        这一步最为复杂与繁琐,一定要细心,要彻底理解MR 程序的运行步骤,设置好每个步骤的Key和value的类型与对应类的类名。

        后续步骤没有什么变化,运行MR程序调度最重要也是最容易出错就是workflow.xml配置的错误。报错仔细检查

  Oozie任务串联

      在实际工作当中,肯定会存在多个任务需要执行,并且存在上一个任务的输出结果作为下一个任务的输入数据这样的情况,所以我们需要在workflow.xml配置文件当中配置多个action,实现多个任务之间的相互依赖关系。

      需求:首先执行一个shell脚本,执行完了之后再执行一个MR的程序,最后再执行一个hive的程序。

      准备工作目录

        cd /export/servers/oozie-4.1.0-cdh5.14.0/oozie_works

        mkdir -p sereval-actions

       准备调度文件

        将之前的hive,shell, MR的执行,进行串联成到一个workflow当中。

        cd /export/servers/oozie-4.1.0-cdh5.14.0/oozie_works

        cp hive2/script.q sereval-actions/

        cp shell/hello.sh sereval-actions/

        cp -ra map-reduce/lib sereval-actions/

     修改配置模板

        cd /export/servers/oozie-4.1.0-cdh5.14.0/oozie_works/sereval-actions

        vim workflow.xml

  1 <workflow-app xmlns="uri:oozie:workflow:0.4" name="shell-wf">
  2 <start to="shell-node"/>
  3 <action name="shell-node">
  4     <shell xmlns="uri:oozie:shell-action:0.2">
  5         <job-tracker>${jobTracker}</job-tracker>
  6         <name-node>${nameNode}</name-node>
  7         <configuration>
  8             <property>
  9                 <name>mapred.job.queue.name</name>
 10                 <value>${queueName}</value>
 11             </property>
 12         </configuration>
 13         <exec>${EXEC}</exec>
 14         <!-- <argument>my_output=Hello Oozie</argument> -->
 15         <file>/user/root/oozie_works/sereval-actions/${EXEC}#${EXEC}</file>
 16 
 17         <capture-output/>
 18     </shell>
 19     <ok to="mr-node"/>
 20     <error to="mr-node"/>
 21 </action>
 22 
 23 <action name="mr-node">
 24         <map-reduce>
 25             <job-tracker>${jobTracker}</job-tracker>
 26             <name-node>${nameNode}</name-node>
 27             <prepare>
 28                 <delete path="${nameNode}/${outputDir}"/>
 29             </prepare>
 30             <configuration>
 31                 <property>
 32                     <name>mapred.job.queue.name</name>
 33                     <value>${queueName}</value>
 34                 </property>
 35                 <!--  
 36                 <property>
 37                     <name>mapred.mapper.class</name>
 38                     <value>org.apache.oozie.example.SampleMapper</value>
 39                 </property>
 40                 <property>
 41                     <name>mapred.reducer.class</name>
 42                     <value>org.apache.oozie.example.SampleReducer</value>
 43                 </property>
 44                 <property>
 45                     <name>mapred.map.tasks</name>
 46                     <value>1</value>
 47                 </property>
 48                 <property>
 49                     <name>mapred.input.dir</name>
 50                     <value>/user/${wf:user()}/${examplesRoot}/input-data/text</value>
 51                 </property>
 52                 <property>
 53                     <name>mapred.output.dir</name>
 54                     <value>/user/${wf:user()}/${examplesRoot}/output-data/${outputDir}</value>
 55                 </property>
 56                 -->
 57                 
 58                    <!-- 开启使用新的API来进行配置 -->
 59                 <property>
 60                     <name>mapred.mapper.new-api</name>
 61                     <value>true</value>
 62                 </property>
 63 
 64                 <property>
 65                     <name>mapred.reducer.new-api</name>
 66                     <value>true</value>
 67                 </property>
 68 
 69                 <!-- 指定MR的输出key的类型 -->
 70                 <property>
 71                     <name>mapreduce.job.output.key.class</name>
 72                     <value>org.apache.hadoop.io.Text</value>
 73                 </property>
 74 
 75                 <!-- 指定MR的输出的value的类型-->
 76                 <property>
 77                     <name>mapreduce.job.output.value.class</name>
 78                     <value>org.apache.hadoop.io.IntWritable</value>
 79                 </property>
 80 
 81                 <!-- 指定输入路径 -->
 82                 <property>
 83                     <name>mapred.input.dir</name>
 84                     <value>${nameNode}/${inputdir}</value>
 85                 </property>
 86 
 87                 <!-- 指定输出路径 -->
 88                 <property>
 89                     <name>mapred.output.dir</name>
 90                     <value>${nameNode}/${outputDir}</value>
 91                 </property>
 92 
 93                 <!-- 指定执行的map类 -->
 94                 <property>
 95                     <name>mapreduce.job.map.class</name>
 96                     <value>org.apache.hadoop.examples.WordCount$TokenizerMapper</value>
 97                 </property>
 98 
 99                 <!-- 指定执行的reduce类 -->
100                 <property>
101                     <name>mapreduce.job.reduce.class</name>
102                     <value>org.apache.hadoop.examples.WordCount$IntSumReducer</value>
103                 </property>
104                 <!--  配置map task的个数 -->
105                 <property>
106                     <name>mapred.map.tasks</name>
107                     <value>1</value>
108                 </property>
109 
110             </configuration>
111         </map-reduce>
112         <ok to="hive2-node"/>
113         <error to="fail"/>
114     </action>
115 
116 
117 
118 
119 
120 
121  <action name="hive2-node">
122         <hive2 xmlns="uri:oozie:hive2-action:0.1">
123             <job-tracker>${jobTracker}</job-tracker>
124             <name-node>${nameNode}</name-node>
125             <prepare>
126                 <delete path="${nameNode}/user/${wf:user()}/${examplesRoot}/output-data/hive2"/>
127                 <mkdir path="${nameNode}/user/${wf:user()}/${examplesRoot}/output-data"/>
128             </prepare>
129             <configuration>
130                 <property>
131                     <name>mapred.job.queue.name</name>
132                     <value>${queueName}</value>
133                 </property>
134             </configuration>
135             <jdbc-url>${jdbcURL}</jdbc-url>
136             <script>script.q</script>
137             <param>INPUT=/user/${wf:user()}/${examplesRoot}/input-data/table</param>
138             <param>OUTPUT=/user/${wf:user()}/${examplesRoot}/output-data/hive2</param>
139         </hive2>
140         <ok to="end"/>
141         <error to="fail"/>
142     </action>
143 <decision name="check-output">
144     <switch>
145         <case to="end">
146             ${wf:actionData('shell-node')['my_output'] eq 'Hello Oozie'}
147         </case>
148         <default to="fail-output"/>
149     </switch>
150 </decision>
151 <kill name="fail">
152     <message>Shell action failed, error message[${wf:errorMessage(wf:lastErrorNode())}]</message>
153 </kill>
154 <kill name="fail-output">
155     <message>Incorrect output, expected [Hello Oozie] but was [${wf:actionData('shell-node')['my_output']}]</message>
156 </kill>
157 <end name="end"/>
158 </workflow-app>
View Code

        其实仔细观察就会发现,这里面的逻辑就是开始节点指定要执行的任务,然后执行完的动作中指定另一个任务,以此类推。

     job.properties配置文件

nameNode=hdfs://node-1:8020
jobTracker=node-1:8032
queueName=default
examplesRoot=oozie_works
EXEC=hello.sh
outputDir=/oozie/output
inputdir=/oozie/input
jdbcURL=jdbc:hive2://node-1:10000/default
oozie.use.system.libpath=true
# 配置我们文件上传到hdfs的保存路径 实际上就是在hdfs 的/user/root/oozie_works/sereval-actions这个路径下
oozie.wf.application.path=${nameNode}/user/${user.name}/${examplesRoot}/sereval-actions/workflow.xml

    剩余的步骤都是一样的。执行完到监控系统上查看执行情况。

 Oozie定时调度

  在oozie当中,主要是通过Coordinator 来实现任务的定时调度, Coordinator 模块主要通过xml来进行配置即可。

  Coordinator 的调度主要可以有两种实现方式

  第一种:基于时间的定时任务调度:

  oozie基于时间的调度主要需要指定三个参数,第一个起始时间,第二个结束时间,第三个调度频率;

  第二种:基于数据的任务调度, 这种是基于数据的调度,只要在有了数据才会触发调度任务。

     准备配置模板

  第一步:拷贝定时任务的调度模板

  cd /export/servers/oozie-4.1.0-cdh5.14.0

  cp -r examples/apps/cron oozie_works/cron-job

   第二步:拷贝我们的hello.sh脚本

  cd /export/servers/oozie-4.1.0-cdh5.14.0/oozie_works

  cp shell/hello.sh  cron-job/

     修改配置模板

       修改job.properties

        cd /export/servers/oozie-4.1.0-cdh5.14.0/oozie_works/cron-job

        vim job.properties

 1 nameNode=hdfs://node-1:8020
 2 jobTracker=node-1:8032
 3 queueName=default
 4 examplesRoot=oozie_works
 5 
 6 oozie.coord.application.path=${nameNode}/user/${user.name}/${examplesRoot}/cron-job/coordinator.xml
 7 #start:必须设置为未来时间,否则任务失败
 8 start=2019-05-22T19:20+0800
 9 end=2019-08-22T19:20+0800
10 EXEC=hello.sh
11 workflowAppUri=${nameNode}/user/${user.name}/${examplesRoot}/cron-job/workflow.xml

       修改coordinator.xml

        vim coordinator.xml

 1 <!--
 2     oozie的frequency 可以支持很多表达式,其中可以通过定时每分,或者每小时,或者每天,或者每月进行执行,也支持可以通过与linux的crontab表达式类似的写法来进行定时任务的执行
 3     例如frequency 也可以写成以下方式
 4     frequency="10 9 * * *"  每天上午的09:10:00开始执行任务
 5     frequency="0 1 * * *"  每天凌晨的01:00开始执行任务
 6  -->
 7 <coordinator-app name="cron-job" frequency="${coord:minutes(1)}" start="${start}" end="${end}" timezone="GMT+0800"
 8                  xmlns="uri:oozie:coordinator:0.4">
 9         <action>
10         <workflow>
11             <app-path>${workflowAppUri}</app-path>
12             <configuration>
13                 <property>
14                     <name>jobTracker</name>
15                     <value>${jobTracker}</value>
16                 </property>
17                 <property>
18                     <name>nameNode</name>
19                     <value>${nameNode}</value>
20                 </property>
21                 <property>
22                     <name>queueName</name>
23                     <value>${queueName}</value>
24                 </property>
25             </configuration>
26         </workflow>
27     </action>
28 </coordinator-app>

         workflow.xml跟之前的一样,剩余步骤相同,上传到HDFS上执行,在监控系统查看

两个工作流调度的系统,就大致这些内容了,更深层次的使用,可以参考官网文档。

原文地址:https://www.cnblogs.com/sky9408251/p/12069277.html