重点介绍oozie调度中 MapReduce 、Spark、Hive workflow的构建以及构建过程中遇到的问题
1 MapReduce Action
oozie调度mapreduce任务,其实是针对mapreduce任务的map和reduce阶段分别起了一个map和reduce的任务,
去分别调度map和reduce阶段,而不会去从mapreduce任务的main 函数执行,因此需要将main函数中设置的所有配置都要设置在 workflow中的configuration中。
(1)设置workflow中的configuration
<configuration>
<property>
<name>mapred.reducer.new-api</name> //让oozie支持Hadoop新的MapReduce api
<value>true</value>
</property>
<property>
<name>mapred.mapper.new-api</name> //让oozie支持Hadoop新的MapReduce api
<value>true</value>
</property>
<property>
<name>mapreduce.job.queuename</name> //设置任务队列的队列名
<value>${queue_name}</value>
</property>
<property>
<name>mapreduce.job.reduces</name> //设置MapReduce任务的 reduce个数
<value>50</value>
</property>
<property>
//设置任务的数据输入路径,对应 FileInputFormat.setInputPaths(job, new Path(args[0]));
name 的值对应 Hadoop中配置参数 public static final String INPUT_DIR =
"mapreduce.input.fileinputformat.inputdir"; (通过代码跟进setInputPaths()可以找到这个参数)
<name>mapreduce.input.fileinputformat.inputdir</name>
<value>${input_data_l2}</value>
</property>
<property>
//设置任务的数据输出路径,对应 FileOutputFormat.setOutputPath(job, new Path(args[1]));
name 的值对应 Hadoop中配置参数 public static final String OUTDIR = "mapreduce.output.fileoutputformat.outputdir"; (通过代码跟进setOutputPath()可以找到这个参数)
<name>mapreduce.output.fileoutputformat.outputdir</name>
<value>${output_data_l2}</value>
</property>
<property>
//设置任务中 map的类型以及page名,形式:page名$map类名,对应 job.setMapperClass(JsonAvroConverterMapper.class);
<name>mapreduce.job.map.class</name>
<value>com.milky.pkl.mijia.mapreduce.JsonAvroConverter$JsonAvroConverterMapper</value>
</property>
<property>
//设置任务中 reduce的类型以及page名,形式:page名$reduce类名,对应 job.setReducerClass(JsonAvroConverterReducer.class);
<name>mapreduce.job.reduce.class</name>
<value>com.milky.pkl.mijia.mapreduce.JsonAvroConverter$JsonAvroConverterReducer</value>
</property>
<property>
//设置任务中 输入数据的数据格式类型,对应:job.setInputFormatClass(TextInputFormat.class);
name的值 对应Hadoop中配置参数 public static final String INPUT_FORMAT_CLASS_ATTR = "mapreduce.job.inputformat.class"; (通过代码跟进setInputFormatClass()可以找到这个参数)
key的值对应 TextInputFormat 所在的包名,在当前类 中的 import中可以找到
<name>mapreduce.job.inputformat.class</name>
<value>org.apache.hadoop.mapreduce.lib.input.TextInputFormat</value>
</property>
<property>
//设置任务中 输入数据的数据格式类型,对应:job.setOutputFormatClass(AvroKeyOutputFormat.class);
name的值 对应Hadoop中配置参数 public static final String OUTPUT_FORMAT_CLASS_ATTR = "mapreduce.job.outputformat.class"; (通过代码跟进setOutputFormatClass()可以找到这个参数)
key的值对应 AvroKeyOutputFormat 所在的包名,在当前类 中的 import中可以找到
<name>mapreduce.job.outputformat.class</name>
<value>org.apache.avro.mapreduce.AvroKeyOutputFormat</value>
</property>
<property>
//设置任务中 map阶段输出数据 key的类型的class,对应 job.setMapOutputKeyClass(AvroKeyOutputFormat.class);
name的值 对应Hadoop中配置参数 public static final String MAP_OUTPUT_KEY_CLASS = "mapreduce.map.output.key.class";(通过代码跟进setMapOutputKeyClass()可以找到这个参数)
key的值对应 public static class JsonAvroConverterMapper
extends Mapper<LongWritable/*输入Key的类型*/, Text/*输入value的类型*/, AvroKey<MijiaResult>/*输出key的类型*/, NullWritable/*输出value的类型*/> {} 中 AvroKey 所在的包名,在当前类 中的 import中可以找到
<name>mapreduce.map.output.key.class</name>
<value>org.apache.avro.mapred.AvroKey</value>
</property>
<property>
// 设置任务中 map阶段输出数据value类型的class,类同 上述 ,不再多说
<name>mapreduce.map.output.value.class</name>
<value>org.apache.hadoop.io.NullWritable</value>
</property>
/* 普通的mapreduce任务设置以上内容已可满足,若是main函数中还有其他的job任务的配置,根据上述的方法继续配置*/
/*下面是 avrojob中的额外配置,main函数中有两行:
第一行: AvroJob.setOutputKeySchema(job, MijiaResult.getClassSchema());
其中setOutputKeySchema函数实现为:
public static void setOutputKeySchema(Job job, Schema schema) {
job.setOutputKeyClass(AvroKey.class);
job.getConfiguration().set(CONF_OUTPUT_KEY_SCHEMA, schema.toString());
}
第二行: AvroJob.setMapOutputKeySchema(job, MijiaResult.getClassSchema());
其中setMapOutputKeySchema函数的实现为:
public static void setMapOutputKeySchema(Job job, Schema schema) {
job.setMapOutputKeyClass(AvroKey.class);
job.setGroupingComparatorClass(AvroKeyComparator.class);
job.setSortComparatorClass(AvroKeyComparator.class);
AvroSerialization.setKeyWriterSchema(job.getConfiguration(), schema);
AvroSerialization.setKeyReaderSchema(job.getConfiguration(), schema);
AvroSerialization.addToConfiguration(job.getConfiguration());
}
这需要根据上面两个函数的实现继续配置!!!
*/
<property>
<name>mapreduce.job.output.key.class</name>
<value>org.apache.avro.mapred.AvroKey</value>
</property>
<property>
<name>avro.schema.output.key</name>
<value>${schema}</value>
</property>
<property>
<name>mapreduce.job.output.group.comparator.class</name>
<value>org.apache.avro.hadoop.io.AvroKeyComparator</value>
</property>
<property>
<name>mapreduce.job.output.key.comparator.class</name>
<value>org.apache.avro.hadoop.io.AvroKeyComparator</value>
</property>
<property>
<name>avro.serialization.key.writer.schema</name>
<value>${schema}</value>
</property>
<property>
<name>avro.serialization.key.reader.schema</name>
<value>${schema}</value>
</property>
<property>
<name>io.serializations</name>
<value>org.apache.hadoop.io.serializer.WritableSerialization, org.apache.hadoop.io.serializer.avro.AvroSpecificSerialization, org.apache.hadoop.io.serializer.avro.AvroReflectSerialization,org.apache.avro.hadoop.io.AvroSerialization</value>
</property>
</configuration>
(2)遇到的问题:
avro-mapred.jar 包与hive中有些jar冲突问题,避免avro-mapred.jar 与hive的一些jar放到一起
2 Spark Action
oozie调度spark任务,只会启动一个map任务,来执行spark任务,
(1)oozie4.2.0 只支持sparkaction0.1,最新版本是支持sparkaction0.2
(2)workflow 设置action时,要标明sparkaction的版本,例如: <spark xmlns="uri:oozie:spark-action:0.1"></spark>
(3)即使有spark任务没提交到spark上运行,有可能产生oozie调度的成功
(4)基本路径不能忽略hdfs://op2:8020/,不设置将默认在本地找(默认的事file://)
(5) sparkhistory中找不到oozie调spark的任务记录;需要在spark-opts标签中显示的设置,例如:
--conf spark.yarn.historyServer.address=http://172.23.7.11:18080 --conf spark.eventLog.dir=hdfs://op2/user/spark/log --conf spark.eventLog.enabled=true
(6)运行方式: master为 yarn-cluster,mode 不用设置或将其设置成cluster;yarn-client的模式会出现永久区 OOM,原因不详
(7)配置设置: 将runtime时需要的 file:// 协议的文件,用 spark的--files参数将所需要的文件带到各个节点上
(8) 队列设置: mapreduce.job.queuename 只设置了oozie起 的一个map的队列,而spark任务的队列需要在spark-opts 中的 --queue 设置队列的名字,若不设置 spark任务会在 root.default队列上执行
(9) 像 --driver-java-option 这样的参数传递多个参数时,多个参数之前不能用空格,需要 用转义过的制表符的(注意是xml的转义)
workflow的例子:
<workflow-app name="PKL_MIJIA_M6_WF" xmlns="uri:oozie:workflow:0.4">
<start to="Mijia_rcm"/>
<action name="Mijia_rcm" retry-max="${retry_max}" retry-interval="${retry_interval}">
<spark xmlns="uri:oozie:spark-action:0.1">
<job-tracker>${job_tracker}</job-tracker>
<name-node>${name_node}</name-node>
<prepare>
<delete path="${output_data_l1}"/>
</prepare>
<configuration>
<property>
<name>mapreduce.job.queuename</name>
<value>${queue_name}</value>
</property>
</configuration>
<master>yarn-cluster</master>
<name>mijia.spark.M6</name>
<class>com.milky.pkl.mijia.Mijia</class>
<jar>${oozie_app_path}workflow/lib/mijia.jar</jar>
<spark-opts>${spark_opts}</spark-opts>
<arg>--input</arg>
<arg>${pkl_mijia_datas_input}</arg>
<arg>--output</arg>
<arg>${output_data_l1}</arg>
<arg>--output-format</arg>
<arg>avro</arg>
<arg>--config-path</arg>
<arg>${configs_path}</arg>
</spark>
<ok to="end"/>
<error to="fail"/>
</action>
<kill name="fail">
<message>Job failed, error message[${wf:errorMessage(wf:lastErrorNode())}]</message>
</kill>
<end name="end"/>
</workflow-app>
3 Hive Action
(1) 参数传递方式
<param>_0_date=${_0_date}</param>其中param标签传递的参数 最终为转化为 --hivevar 的这种传参方式,若是hive脚本中 有hiveconf
传参方式,请将脚本中的hiveconf 全部换成hivevar传参,因为是 oozie调度hive ,oozie向hive脚本传递参数只能是 hivevar方式
(2)设置hive配置
<job-xml>${oozie_app_path}/workflow/conf/hive-site.xml</job-xml>,通过job-xml标签将hive-site.xml加载进来,
若是不加载hive-site.xml,会报出异常。
workflow的例子:
<workflow-app name="PKL_FINAL_WF" xmlns="uri:oozie:workflow:0.4">
<start to="pkl_final"/>
<action name="pkl_final" retry-max="${retry_max}" retry-interval="${retry_interval}">
<hive xmlns="uri:oozie:hive-action:0.2">
<job-tracker>${job_tracker}</job-tracker>
<name-node>${hive_name_node}</name-node>
<job-xml>${oozie_app_path}/workflow/conf/hive-site.xml</job-xml>
<configuration>
<property>
<name>mapreduce.job.queuename</name>
<value>${queue_name}</value>
</property>
</configuration>
<script>${oozie_app_path}/workflow/script/kk_final.sql</script>
<param>date1=${date1}</param>
<param>date2=${date1}</param>
</hive>
<ok to="end"/>
<error to="fail"/>
</action>
<kill name="fail">
<message>Job failed, error message[${wf:errorMessage(wf:lastErrorNode())}]</message>
</kill>
<end name="end"/>
</workflow-app>
4 需要注意和建议
(1) workflow目录下的lib文件夹下的所有 jar包是默认全部加载,即使你在workflow中指定其他目录下的 jar包,
lib下的所有jar包也有加载,在出现jar包冲突时需要考虑这一点。
(2)一个workflow中出现多个 action,且configuration中的配置有很多相同的配置的时候,建议将多个action中的配置写在global标签中