原理解析
一·YARN调优
1. yarn相关参数解析
1).RM的内存资源配置, 配置的是资源调度相关
RM1:yarn.scheduler.minimum-allocation-mb 分配给AM单个容器可申请的最小内存
RM2:yarn.scheduler.maximum-allocation-mb 分配给AM单个容器可申请的最大内存
注:
- 最小值可以计算一个节点最大Container数量
- 一旦设置,不可动态改变
2).NM的内存资源配置,配置的是硬件资源相关
NM1:yarn.nodemanager.resource.memory-mb 节点最大可用内存
NM2:yarn.nodemanager.vmem-pmem-ratio 虚拟内存率,默认2.1
注:
- RM1、RM2的值均不能大于NM1的值
- NM1可以计算节点最大最大Container数量,max(Container)=NM1/RM1
- 一旦设置,不可动态改变
3).AM内存配置相关参数,配置的是任务相关
AM1:mapreduce.map.memory.mb 分配给map Container的内存大小
AM2:mapreduce.reduce.memory.mb 分配给reduce Container的内存大小
- 这两个值应该在RM1和RM2这两个值之间
- AM2的值最好为AM1的两倍
- 这两个值可以在启动时改变
AM3:mapreduce.map.java.opts 运行map任务的jvm参数,如-Xmx,-Xms等选项
AM4:mapreduce.reduce.java.opts 运行reduce任务的jvm参数,如-Xmx,-Xms等选项
注: - 这两个值应该在AM1和AM2之间
4).RM的CPU资源配置, 配置的是资源调度相关
yarn.scheduler.minimum-allocation-vcores:最小可申请CPU数,默认是1
yarn.scheduler.maximum-allocation-vcores:最大可申请CPU数,默认是4
2.关于Container
(1)Container是YARN中资源的抽象,它封装了某个节点上一定量的资源(CPU和内存两类资源)。它跟Linux Container没有任何关系,仅仅是YARN提出的一个概念(从实现上看,可看做一个可序列化/反序列化的Java类)。
(2)Container由ApplicationMaster向ResourceManager申请的,由ResouceManager中的资源调度器异步分配给ApplicationMaster;
(3)Container的运行是由ApplicationMaster向资源所在的NodeManager发起的,Container运行时需提供内部执行的任务命令(可以使任何命令,比如java、Python、C++进程启动命令均可)以及该命令执行所需的环境变量和外部资源(比如词典文件、可执行文件、jar包等)。
另外,一个应用程序所需的Container分为两大类,如下:
(1) 运行ApplicationMaster的Container:这是由ResourceManager(向内部的资源调度器)申请和启动的,用户提交应用程序时,可指定唯一的ApplicationMaster所需的资源;
(2)运行各类任务的Container:这是由ApplicationMaster向ResourceManager申请的,并由ApplicationMaster与NodeManager通信以启动之。
以上两类Container可能在任意节点上,它们的位置通常而言是随机的,即ApplicationMaster可能与它管理的任务运行在一个节点上。
Container是YARN中最重要的概念之一,懂得该概念对于理解YARN的资源模型至关重要,望大家好好理解。
注意:map/reduce task是运行在Container之中的,所以上面提到的mapreduce.map(reduce).memory.mb大小都大于mapreduce.map(reduce).java.opts值的大小。
二·HDFS
三·MapReduce
代码实操
一·scala实现MapReduce的wordcount
import org.apache.hadoop.conf.{Configuration, Configured}
import org.apache.hadoop.fs.Path
import org.apache.hadoop.io.{IntWritable, LongWritable, Text}
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat
import org.apache.hadoop.mapreduce.{Job, Mapper, Reducer}
import org.apache.hadoop.util.Tool
class MRmap extends Mapper[LongWritable, Text, Text, IntWritable]{
override def map(key: LongWritable, value: Text, context: Mapper[LongWritable, Text, Text, IntWritable]#Context): Unit = {
val words = value.toString
val arr = words.split(",")
for (x <- arr) {
context.write(new Text(x), new IntWritable(1))
}
}
}
class MRreduce extends Reducer[Text, IntWritable, Text, IntWritable] {
def reduce(key: Text, values: Iterable[IntWritable], context: Reducer[Text, IntWritable, Text, IntWritable]#Context): Unit = {
//统计个数
var cnt:Int=0
for (x :IntWritable <- values){
cnt +=x.get()
}
context.write(key,new IntWritable(cnt))
}
}
object MR extends Configured with Tool{
override def run(strings: Array[String]): Int = {
val configuration = new Configuration()
//configuration.set("fs.defaultFS","hdfs://work01:8020")
val job = Job.getInstance(configuration)
job.setJarByClass(this.getClass)
job.setJobName("wordcount")
//map.reduce.combiner
job.setMapperClass(classOf[MRmap])
job.setReducerClass(classOf[MRreduce])
job.setCombinerClass(classOf[MRreduce])
job.setMapOutputKeyClass(classOf[Text])
job.setOutputValueClass(classOf[IntWritable])
//输入 输出
FileInputFormat.addInputPath(job,new Path("C:\\Users\\yxiong02\\Desktop\\data\\13320-5419-tags.csv"))
FileOutputFormat.setOutputPath(job,new Path("C:\\Users\\yxiong02\\Desktop\\data\\output"))
val bool:Boolean = job.waitForCompletion(true)
if (bool) 0 else 1
}
def main(args: Array[String]): Unit = {
run(Array())
}
}
二·修改文件输出名
写一个类继承TextOutputFormat,重写setOutputName方法,然后在driver类里指定一个输出类就ok了
//指定输出名的输出类
class MyOut extends TextOutputFormat {
protected static void setOutputName(JobContext job, String name) {
job.getConfiguration().set(BASE_OUTPUT_NAME, name);
}
}
//在driver类加一句
MyOut.setOutputName(job, strs);
//把strs修改为你需要的名字就好了
三·指定reduce输出
写一个分区类继承Partitioner<Text,Text>,重写getPartitoner方法
class XyyPatitioner extends Partitioner<Text,Text> {
public int getPartition(Text key, Text value, int num) {
if(value.toString().contains("chengdu")){
return 1;
}else if(value.toString().contains("hangzhou")){
return 2;
}else if(value.toString().contains("nanjing")){
return 3;
}else if(value.toString().contains("zhengzhou")){
return 4;
}else {
return 0;
}
}
}
//driver类加两行
job.setPartitionerClass(XyyPatitioner.class);
job.setNumReduceTasks(num);//设置reduce个数
getPartition()方法有三个形参,源码中key、value分别指的是Mapper任务的输出,numReduceTasks指的是设置的Reducer任务数量,默认值是1
这里只是做个笔记,顺便骗一骗阅读量,哈哈哈哈,原谅我的厚颜无耻。大佬们有什么交流的可以随意留言。
(未完待续)