avatar

目录
Oozie-任务调度

Oozie简介

​ 一个基于工作流引擎的开源框架,由 Cloudera 公司贡献给 Apache,提供对 Hadoop MapReduce、Pig Jobs 的任务调度与协调。Oozie 需要部署到 Java Servlet 容器中运行。主要用于定时调度任务,多任务可以按照执行的逻辑顺序调度。

Oozie 的功能模块介绍

模块

1) Workflow

顺序执行流程节点,支持 fork(分支多个节点),join(合并多个节点为一个)

2) Coordinator

定时触发 workflow

3) Bundle Job

绑定多个 Coordinator

常用节点

1) 控制流节点(Control Flow Nodes)

控制流节点一般都是定义在工作流开始或者结束的位置,比如 start,end,kill 等。以及提供工 作流的执行路径机制,如 decision,fork,join 等。

2) 动作节点(Action Nodes)

负责执行具体动作的节点,比如:拷贝文件,执行某个 Shell 脚本等等。

Oozie的部署

修改 Hadoop 配置

core-site.xml

xml
1
2
3
4
5
6
7
8
9
10
<!-- Oozie Server 的 Hostname --> 
<property>
<name>hadoop.proxyuser.machine.hosts</name>
<value>*</value>
</property>
<!-- 允许被 Oozie 代理的用户组 -->
<property>
<name>hadoop.proxyuser.machine.groups</name>
<value>*</value>
</property>

mapred-site.xml

xml
1
2
3
4
5
6
7
8
9
10
11
12
<!-- 历史服务器-->

<!-- 配置 MapReduce JobHistory Server 地址 ,默认端口 10020 -->
<property>
<name>mapreduce.jobhistory.address</name>
<value>mxxcentos7:10020</value>
</property>
<!-- 配置 MapReduce JobHistory Server web ui 地址, 默认端口 19888 -->
<property>
<name>mapreduce.jobhistory.webapp.address</name>
<value>mxxcentos7:19888</value>
</property>

yarn-site.xml

xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<!-- 日志聚集功能 -->
<property>
<name>yarn.log-aggregation-enable</name>
<value>true</value>
</property>

<!-- 日志保留时间7天 -->
<property>
<name>yarn.log-aggregation.retain-seconds</name>
<value>604800</value>
</property>

<!-- 任务历史服务 -->
<property>
<name>yarn.log.server.url</name>
<value>http://mxxcentos7:19888/jobhistory/logs/</value>
</property>

启动

Code
1
2
3
./start-dfs.sh
./start-yarn.sh
./mr-jobhistory-daemon.sh start historyserver

部署 Oozie

shell
1
2
3
4
5
6
7
8
9
10
11
12
# 解压 Oozie
tar -zxvf /media/psf/centos_share/oozie-4.1.0-cdh5.16.1.tar.gz
# 在 oozie 根目录下解压 oozie-hadooplibs
tar -zxvf oozie-hadooplibs-4.1.0-cdh5.16.1.tar.gz -C ../
# 在 Oozie 目录下创建 libext 目录
mkdir libext/
# 将 hadooplibs 里面的 jar 包,拷贝到 libext 目录下:
cp hadooplibs/hadooplib-2.6.0-cdh5.16.1.oozie-4.1.0-cdh5.16.1/* ./libext/
# 拷贝 Mysql 驱动包到 libext 目录下(Oozie元数据信息用mysql保存):
cp /media/psf/centos_share/mysql-connector-java-5.1.39-bin.jar ./libext/
# 将 ext-2.2.zip 拷贝到 libext/目录下(ext 是一个 js 框架,用于展示 oozie 前端页面:)
cp /media/psf/centos_share/ext-2.2.zip ./libext/

修改Oozie配置

oozie-site.xml 复制oozie-default.xml,加入以下字段

(不复制也行?oozie-default.xml就是默认值?)

xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<!-- jdbc的配置 -->
<property>
<name>oozie.service.JPAService.jdbc.driver</name>
<value>com.mysql.jdbc.Driver</value>
</property>

<property>
<name>oozie.service.JPAService.jdbc.url</name>
<value>jdbc:mysql://mxxcentos7:3306/oozie</value>
</property>

<property>
<name>oozie.service.JPAService.jdbc.username</name>
<value>root</value>
</property>

<property>
<name>oozie.service.JPAService.jdbc.password</name>
<value>123456</value>
</property>

<!-- hadoop的配置 -->

<property>
<name>oozie.service.HadoopAccessorService.hadoop.configurations</name>
<value>*=/home/machine/apps/hadoop-2.6.0-cdh5.16.1/etc/hadoop</value>
</property>

在 Mysql 中创建 Oozie 的数据库

初始化 Oozie

cdh5.16.1貌似有很多很多问题….

上传 Oozie 目录下的 yarn.tar.gz 文件到 HDFS

(yarn.tar.gz 文件会自行解压)

shell
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 
bin/oozie-setup.sh sharelib create -fs hdfs://mxxcentos7:9000 -locallib oozie-sharelib-4.1.0-cdh5.16.1.tar.gz

# 找不到或无法加载主类 org.apache.oozie.tools.OozieSharelibCLI
oozie-tools-4.1.0.jar扔到libext下
# java.lang.ClassNotFoundException: org.apache.oozie.cli.CLIParser
cp ./lib/oozie-client-4.1.0-cdh5.16.1.jar ./libext/
# Caused by: java.lang.ClassNotFoundException: org.apache.oozie.service.Services
cp ./oozie-core/oozie-core-4.1.0-cdh5.16.1.jar ./libext/
# java.lang.ClassNotFoundException: org.apache.log4j.rolling.RollingFileAppender
cp /media/psf/centos_share/apache-log4j-extras-1.2.17.jar ./libext/

# 再次运行
bin/oozie-setup.sh sharelib create -fs hdfs://mxxcentos7:9000 -locallib oozie-sharelib-4.1.0-cdh5.16.1.tar.gz

# 终于成功了!!!

创建 oozie.sql 文件

sh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 
bin/ooziedb.sh create -sqlfile oozie.sql -run
# Caused by: java.lang.ClassNotFoundException: org.apache.openjpa.jdbc.meta.MappingTool
cp /media/psf/centos_share/openjpa-jdbc-3.0.0.jar ./libext/
# Caused by: java.lang.ClassNotFoundException: org.apache.openjpa.meta.MetaDataModes
cp /media/psf/centos_share/openjpa-3.0.0.jar ./libext/
# Caused by: java.lang.ClassNotFoundException: javax.transaction.Synchronization
cp /media/psf/centos_share/geronimo-jta_1.1_spec-1.1.1.jar ./libext/
# java.lang.NoClassDefFoundError: javax/persistence/spi/PersistenceUnitInfo
cp /media/psf/centos_share/geronimo-jpa_2.1_spec-1.0-alpha-1.jar ./libext/
# Caused by: java.lang.ClassNotFoundException: serp.bytecode.BCClassLoader
cp /media/psf/centos_share/serp-1.15.1.jar ./libext/
# Caused by: java.lang.ClassNotFoundException: org.json.simple.JSONObject
cp /media/psf/centos_share/json-simple-1.1.jar ./libext/
# Caused by: java.lang.ClassNotFoundException: org.jdom.Content
cp /media/psf/centos_share/jdom-1.1.3.jar ./libext/

打包项目,生成 war 包

shell
1
2
3
4
5
6
7
8
9
10
bin/oozie-setup.sh prepare-war
# unzip: 未找到命令
sudo yum install unzip
# File/Dir does no exist: /home/machine/apps/oozie-4.1.0-cdh5.16.1/oozie-server/conf/ssl/server.xml
# 下载了其他版本里的 oozie-server...
cp -r /media/psf/centos_share/oozie-server/ ./
# zip: 未找到命令
sudo yum install zip

# 成功!!!

启动与关闭

shell
1
2
3
4
5
bin/oozied.sh start
# jps ,出现一个“Bootstrap”。这是oozie的进程
http://mxxcentos7:11000

bin/oozied.sh stop

Oozie的使用

案例一: Oozie 调度 shell 脚本

目标:使用 Oozie 调度 Shell 脚本

shell
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
# 解压官方案例模板
tar -zxvf oozie-examples.tar.gz

# 创建工作目录
mkdir oozie-apps/

# 拷贝任务模板到 oozie-apps/目录
cp -r examples/apps/shell/ oozie-apps

# 编写脚本 p1.sh
#!/bin/bash
/sbin/date > /home/machine/p1.log

# 修改 job.properties 和 workflow.xml 文件
# job.properties
nameNode=hdfs://mxxcentos7:9000
jobTracker=mxxcentos7:8032
queueName=default
examplesRoot=oozie-apps

oozie.wf.application.path=${nameNode}/user/${user.name}/${examplesRoot}/shell
EXEC=p1.sh

# workflow.xml
<exec>${EXEC}</exec>
<!-- <argument>my_output=Hello Oozie</argument> -->
<file>/user/machine/oozie-apps/shell/${EXEC}#${EXEC}</file>
<capture-output/>

<ok to="end"/>

# 删掉check-output节点


# 上传任务配置
hadoop fs -put oozie-apps/ /user/machine

# 执行任务
bin/oozie job -oozie http://mxxcentos7:11000/oozie -config oozie-apps/shell/job.properties -run

# 再次刷新11000页面,发现有一个任务正在执行,过了一会儿执行失败了
点开查看失败原因:
# UnsupportedOperationException: Accessing local file system is not allowed
# https://stackoverflow.com/questions/54945345/oozie-s3-as-job-folder
rm org/apache/hadoop/fs/RawLocalFileSystem.class
# I solved this by deleting RawLocalFilesystem.class from oozie WEB-INF/classes and restarted oozie.
# 解决!


# Main class [org.apache.oozie.action.hadoop.ShellMain], exit code [1]
查看yarn-ui, 看到historyserver的日志,报错如下:
# ./p1.sh:行2: /sbin/date: 没有那个文件或目录
原因是p1.sh写错了,将/sbin/date 改为 date

#!/bin/bash
date > /home/machine/p1.log

# 重新上传一下
hadoop fs -rm -r /user/machine/oozie-apps/shell/p1.sh
hadoop fs -put ./oozie-apps/shell/p1.sh /user/machine/oozie-apps/shell/
# 重新提交任务
bin/oozie job -oozie http://mxxcentos7:11000/oozie -config oozie-apps/shell/job.properties -run

# Oozie查看,成功执行!!
cat /home/machine/p1.log
# 2019年 10月 16日 星期三 15:14:10 CST

# 总结
整个任务调度是yarn, 他会随机选一个NM执行任务(可以在yarn-ui上找到),然后在该NM上输出p1.log
能指定p1.log输出的节点吗?修改p1.sh脚本,直接登录到那个节点去执行
yarn historyserver可以查错

# 杀死某个任务
bin/oozie job -oozie http://hadoop101:11000/oozie -kill 0000004-170425105153692-oozie-z-W

案例二: Oozie 逻辑调度执行多个 Job

目标:使用 Oozie 执行多个 Job 调度,先执行p1.sh,成功后再执行p2.sh

shell
1
2
3
4
5
6
7
# 编写脚本p2.sh
#!/bin/bash
date > /home/machine/p2.log

# 修改job.properties
EXEC1=p1.sh
EXEC2=p2.sh

修改workflow.xml

xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
<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/machine/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/machine/oozie-apps/shell/${EXEC2}#${EXEC2}</file>
<capture-output/>
</shell>
<ok to="end"/>
<error to="fail"/>
</action>

重新上传,执行

shell
1
2
3
4
5
6
7
8
9
10
hadoop fs -rm -r /user/machine/oozie-apps/shell/*
hadoop fs -put ./oozie-apps/shell/* /user/machine/oozie-apps/shell/
bin/oozie job -oozie http://mxxcentos7:11000/oozie -config oozie-apps/shell/job.properties -run

# job dag可以看到流程图
# yarn-ui上提交了两个任务
cat /home/machine/p1.log
2019年 10月 16日 星期三 16:11:07 CST
cat /home/machine/p2.log
2019年 10月 16日 星期三 16:11:28 CST

案例三: Oozie 调度 MapReduce 任务

1)找到一个可以运行的 mapreduce 任务的 jar 包(可以用官方的,也可以是自己写的)
2)拷贝官方模板到 oozie-apps

shell
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 测试一下 wordcount 在 yarn 中的运行
touch wordcount.txt
hadoop oozie spark
hive hbase

hadoop fs -put wordcount.txt /
yarn jar $HADOOP_HOME/share/hadoop/mapreduce/hadoop-mapreduce-examples-2.6.0-cdh5.16.1.jar wordcount /wordcount.txt /out
# history-Configuration能查到当前jar包所有配置
mapred.mapper.new-api true
mapreduce.job.map.class org.apache.hadoop.examples.WordCount$TokenizerMapper
# 以上配置对应workflow.xml的配置

# 拷贝官方模板到 oozie-apps
cp -r ./examples/apps/map-reduce/ ./oozie-apps/

# 修改job.properties
nameNode=hdfs://mxxcentos7:9000
jobTracker=mxxcentos7:8032
queueName=default
examplesRoot=oozie-apps

oozie.wf.application.path=${nameNode}/user/${user.name}/${examplesRoot}/map-reduce/workflow.xml
outputDir=map-reduce

修改workflow.xml (修改configuration节点里的内容)

xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
<workflow-app xmlns="uri:oozie:workflow:0.2" name="map-reduce-wf">
<start to="mr-node"/>
<action name="mr-node">
<map-reduce>
<job-tracker>${jobTracker}</job-tracker>
<name-node>${nameNode}</name-node>
<prepare>
<!-- 是否提前删除输出路径 -->
<delete path="${nameNode}/user/${wf:user()}/${examplesRoot}/output-data/${outputDir}"/>
</prepare>
<configuration>
<property>
<name>mapred.job.queue.name</name>
<value>${queueName}</value>
</property>

<!-- 调度mr任务时,使用新的api -->
<property>
<name>mapred.mapper.new-api</name>
<value>true</value>
</property>
<property>
<name>mapred.reducer.new-api</name>
<value>true</value>
</property>

<!-- 指定job的key/value输出类型 -->
<property>
<name>mapreduce.job.output.key.class</name>
<value>org.apache.hadoop.io.Text</value>
</property>
<property>
<name>mapreduce.job.output.value.class</name>
<value>org.apache.hadoop.io.IntWritable</value>
</property>

<!-- 指定输入/输出路径 -->
<property>
<name>mapred.input.dir</name>
<value>/wordcount.txt</value>
</property>
<property>
<name>mapred.output.dir</name>
<value>/output/</value>
</property>

<!-- 指定Map类/Reduce类 -->
<property>
<name>mapreduce.job.map.class</name>
<value>org.apache.hadoop.examples.WordCount$TokenizerMapper</value>
</property>
<property>
<name>mapreduce.job.reduce.class</name>
<value>org.apache.hadoop.examples.WordCount$IntSumReducer</value>
</property>

<property>
<name>mapred.map.tasks</name>
<value>1</value>
</property>

</configuration>
</map-reduce>
<ok to="end"/>
<error to="fail"/>
</action>
<kill name="fail">
<message>Map/Reduce failed, error message[${wf:errorMessage(wf:lastErrorNode())}]</message>
</kill>
<end name="end"/>
</workflow-app>

继续

shell
1
2
3
4
5
6
7
8
9
10
11
12
13
# 拷贝待执行的 jar 包到 map-reduce 的 lib 目录下
rm -rf ./oozie-apps/map-reduce/lib/*
cp $HADOOP_HOME/share/hadoop/mapreduce/hadoop-mapreduce-examples-2.6.0-cdh5.16.1.jar ./oozie-apps/map-reduce/lib/

# 上传配置好的 app 文件夹到 HDFS
hadoop fs -put ./oozie-apps/map-reduce/ /user/machine/oozie-apps/

# 执行任务
bin/oozie job -oozie http://mxxcentos7:11000/oozie -config oozie-apps/map-reduce/job.properties -run

# 成功!!

核心:要拿到workflow.xml的配置属性

案例四: Oozie 定时任务/循环任务

目标:Coordinator 周期性调度任务

每5分钟进行p3.sh

修改时区

shell
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 保证时区是+0800
date -R
Wed, 16 Oct 2019 17:21:08 +0800

# 配置 oozie-site.xml 文件
<!-- 修改时区 -->
<property>
<name>oozie.processing.timezone</name>
<value>GMT+0800</value>
</property>

# 修改 js 框架中的关于时间设置的代码
# /oozie-server/webapps/oozie/oozie-console.js
function getTimeZone() {
Ext.state.Manager.setProvider(new Ext.state.CookieProvider());
return Ext.state.Manager.get("TimezoneId","GMT+0800");
}

# 重启 oozie 服务,并重启浏览器(一定要注意清除缓存)
bin/oozied.sh stop
bin/oozied.sh start

# 成功!!

拷贝官方模板配置定时任务

Code
1
cp -r examples/apps/cron/ ./oozie-apps/

修改模板 job.properties 和 coordinator.xml 以及 workflow.xml

job.properties

properties
1
2
3
4
5
6
7
8
9
10
11
12
nameNode=hdfs://mxxcentos7:9000
jobTracker=mxxcentos7:8032
queueName=default
examplesRoot=oozie-apps

oozie.coord.application.path=${nameNode}/user/${user.name}/${examplesRoot}/cron
# start:必须设置为未来时间,否则任务失败
start=2019-10-16T18:20Z
end=2019-10-16T18:50Z
workflowAppUri=${nameNode}/user/${user.name}/${examplesRoot}/cron

EXEC3=p3.sh

coordinator.xml

xml
1
2
3
4
5
6
<!--
修改的地方:
timezone="GMT+0800"
frequency="${coord:minutes(5)}" 最少就是5min
-->
...

workflow.xml

xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<workflow-app xmlns="uri:oozie:workflow:0.5" name="one-op-wf">
<start to="p3-shell-node"/>
<action name="p3-shell-node">
<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>${EXEC3}</exec>
<file>/user/machine/oozie-apps/cron/${EXEC3}#${EXEC3}</file>
<!-- <argument>my_output=Hello Oozie</argument>-->
<capture-output/>
</shell>
<ok to="end"/>
<error to="fail"/>
</action>
<kill name="fail">
<message>Shell action failed, errormessage[${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>

p3.sh

shell
1
2
3
vi ./oozie-apps/cron/p3.sh
#!/bin/bash
date > /home/machine/p3.log

上传/执行

Code
1
2
hadoop fs -put ./oozie-apps/cron/ /user/machine/oozie-apps/
bin/oozie job -oozie http://mxxcentos7:11000/oozie -config oozie-apps/cron/job.properties -run

常见问题总结

Code
1
2
3
4
5
6
7
如果 bin/oozied.sh stop 无法关闭,则可以使用 kill -9 [pid],之后 oozie-server/temp/xxx.pid 文 件一定要删除。

Oozie 重新打包时,一定要注意先关闭进程,删除对应文件夹下面的 pid 文件。

JobHistoryServer 必须开启

在本地修改完成的 job 配置,必须重新上传到 HDFS。
文章作者: Machine
文章链接: https://machine4869.gitee.io/2019/10/11/20191011151653804/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 哑舍
打赏
  • 微信
    微信
  • 支付宝
    支付宝

评论