为什么要有Oozie?
在数据业务场景,对于数据的处理往往是分阶段处理,而不同的阶段可能采用了不同的技术框架去完成这个业务需求,且可能在不同的阶段要干不同的事。
炒饭(锅) à 吃饭(碗) à 筷子(动手)
要吃饭就要等炒饭先用锅炒好,要用筷子动手吃饭就要等碗里装了饭,这是一个流水线式的过程,如果用设定时间的方式,到了什么时候就拿完去装饭,但如果今天兼职的人特别多,那么炒的饭必然就多了,时间也长了,但是设定时间到了,还没炒好,可是有一堆人挤在厨房喊要饭,问题就出现了。
于是有的人会想,如果有一个监督人帮我去这个监控、通知、控制好整个流程,那样多好啊,厨房就不会给天天催了,也不会发生拥挤的情况。
小结:一个完整的数据分析系统通常是由大量的任务单元组成,Shell脚本、Java程序、MapReduce程序、Hive脚本等等,各个任务单元之间存在时间先后及前后依赖关系。
为了很好的组织这样的复杂执行计划,需要一个工作流调度系统来调用执行。
简单的工作流调度:Liunx的crontab来定义
复杂的工作流调度:Oozie、Azakaban等。。。
主流几款工作流调度框架
特性 | Hamake | Oozie | Azkaban | Cascading |
工作流描述语言 | XML | XML (xPDL based) | text file with key/value pairs | Java API |
依赖机制 | data-driven | explicit | explicit | explicit |
是否要web容器 | No | Yes | Yes | No |
进度跟踪 | console/log messages | web page | web page | Java API |
Hadoop job调度支持 | no | yes | yes | yes |
运行模式 | command line utility | daemon | daemon | API |
Pig支持 | yes | yes | yes | yes |
事件通知 | no | no | no | yes |
需要安装 | no | yes | yes | no |
支持的hadoop版本 | 0.18+ | 0.20+ | currently unknown | 0.18+ |
重试支持 | no | workflownode evel | yes | yes |
运行任意命令 | yes | yes | yes | yes |
Amazon EMR支持 | yes | no | currently unknown | yes |
什么是Oozie?
Oozie(驯象人)是一个基于工作流引擎的开源框架,由Cloudera公司贡献给Apache的,用在一个工作流内以一个特定顺序运行一组工作或流程。
Oozie在集群中扮演的是定时调度任务,多任务,并开源按照业务逻辑顺序调度。
组成
Workflow:顺序执行流程节点,执行分支多节点或合并多分点为一个分支。
Coordinator:定时触发Workflow
BundleJob:绑定多个Coordinator
Oozie节点
控制流节点(Control Flow Nodes):一般都是定义在工作流开始或结束,比如start、end、kill等,以及提供工作流的执行路径。
动作节点(Action Nodes):执行具体动作的节点。
案例
job.properties
#NameNode地址
nameNode=hdfs://hadoop-senior00-levi.com:8082
#ResourceManager地址,默认端口8032
jobTracker=hadoop-senior00-levi.com:8032
#内部的Event队列名称
queueName=default
examplesRoot=oozie-apps
#程序位置
oozie.wf.application.path=${nameNode}/user/${user.name}/${examplesRoot}/shell
#执行这个脚本
EXEC1=test1.sh
EXEC2=test2.sh
workflow.xml
<workflow-app xmlns="uri:oozie:workflow:0.4" name="shell-wf">
<start to="shell-node1"/>
<action name="shell-node1">
<shell xmlns="uri:oozie:shell-action:0.2">
<job-tracker>${jobTracker}</job-tracker>
<name-node>${nameNode}</name-node>
<configuration>
<property>
<name>mapred.job.queue.name</name>
<value>${queueName}</value>
</property>
</configuration>
<exec>${EXEC1}</exec>
<!-- <argument>my_output=Hello Oozie</argument> -->
<file>/user/admin/oozie-apps/shell/${EXEC1}#${EXEC1}</file>
<capture-output/>
</shell>
<ok to=" shell-node2"/>
<error to="fail"/>
</action>
<action name="shell-node2">
<shell xmlns="uri:oozie:shell-action:0.2">
<job-tracker>${jobTracker}</job-tracker>
<name-node>${nameNode}</name-node>
<configuration>
<property>
<name>mapred.job.queue.name</name>
<value>${queueName}</value>
</property>
</configuration>
<exec>${EXEC2}</exec>
<!-- <argument>my_output=Hello Oozie</argument> -->
<file>/user/admin/oozie-apps/shell/${EXEC2}#${EXEC2}</file>
<capture-output/>
</shell>
<ok to="end"/>
<error to="fail"/>
</action>
<decision name="check-output">
<switch>
<case to="end">
${wf:actionData('shell-node')['my_output'] eq 'Hello Oozie'}
</case>
<default to="fail-output"/>
</switch>
</decision>
<kill name="fail">
<message>Shell action failed, error message[${wf:errorMessage(wf:lastErrorNode())}]</message>
</kill>
<kill name="fail-output">
<message>Incorrect output, expected [Hello Oozie] but was [${wf:actionData('shell-node')['my_output']}]</message>
</kill>
<end name="end"/>
</workflow-app>
test1.sh
#!/bin/bash
/usr/bin/date > /tmp/test.log
test2.sh
#!/bin/bash
/usr/bin/date > /tmp/test.log
执行:
上传到HDFS:
hdfs dfs -rmr /user/levi/oozie-apps
hdfs dfs -put oozie-apps/ /user/levi
执行任务:
bin/oozie job --oozie http://hadoop-senior00-levi.com:11000/oozie -config oozie-apps/shell/job.properties -run
使用注意事项
- 启动不了,则到oozie-server/temp查看是否有*.pid文件,有就删除后在启动。
- 如果无法关闭oozie则kill掉。
- Mysql配置如果没有生效的话,默认使用derby数据库
- 在本地修改完成的job配置,必须重新上传到HDFS。
- Linux用户名和Hadoop的用户名不一致。
- 时区