一、基础概念
Maapreduce是一个分布式运算程序的编程框架,是用户开发“基于hadoop的数据分析应用”的核心框架;
Mapreduce核心功能是将用户编写的业务逻辑代码和自带默认组件整合成一个完整的分布式运算程序,并发运行在一个hadoop集群上;
(一)、为什么使用MAPREDUCE
1、海量数据在单机上处理因为硬件资源限制,无法胜任
2、一旦将单机版程序扩展到集群来分布式运行,将极大增加程序的复杂度和开发难度
3、引入mapreduce框架后,开发人员可以将绝大部分工作集中在业务逻辑的开发上,而将分布式计算中的复杂性交由框架来处理
(二)、MAPREDUCE框架结构及核心运行机制
1、框架结构
(1)、MRAppMaster:负责整个程序的过程调度及状态协调
(2)、mapTask:负责map阶段的整个数据处理流程
(3)、ReduceTask:负责reduce阶段的整个数据处理流程
2、流程
(1)、一个mr程序启动的时候,最先启动的是MRAppMaster,MRAppMaster启动后根据本次job的描述信息,计算出需要的maptask实例数量,然后向集群申请机器启动相应数量的maptask进程
(2)、maptask进程启动之后,根据给定的数据切片范围进行数据处理,主体流程为:
1
2
3
4
5 1a) 利用客户指定的inputformat来获取RecordReader读取数据,形成输入KV对
2b) 将输入KV对传递给客户定义的map()方法,做逻辑运算,并将map()方法输出的KV对收集到缓存
3c) 将缓存中的KV对按照K分区排序后不断溢写到磁盘文件
4
5
(3)、MRAppMaster监控到所有maptask进程任务完成之后,会根据客户指定的参数启动相应数量的reducetask进程,并告知reducetask进程要处理的数据范围(数据分区)
(4)、Reducetask进程启动之后,根据MRAppMaster告知的待处理数据所在位置,从若干台maptask运行所在机器上获取到若干个maptask输出结果文件,并在本地进行重新归并排序,然后按照相同key的KV为一个组,调用客户定义的reduce()方法进行逻辑运算,并收集运算输出的结果KV,然后调用客户指定的outputformat将结果数据输出到外部存储
(三)、MapTask并行度决定机制
maptask的并行度决定map阶段的任务处理并发度,进而影响到整个job的处理速度
1、mapTask并行度的决定机制
一个job的map阶段并行度由客户端在提交job时决定 而客户端对map阶段并行度的规划的基本逻辑为:
1
2
3 1将待处理数据执行逻辑切片(即按照一个特定切片大小,将待处理数据划分成逻辑上的多个split),然后每一个split分配一个mapTask并行实例处理</font></br>
2
3
这段逻辑及形成的切片规划描述文件,由FileInputFormat实现类的getSplits()方法完成
2、FileInputFormat切片机制
(1)、切片定义在InputFormat类中的getSplit()方
(2)、FileInputFormat中默认的切片机制
1
2
3
4
5 1a) 简单地按照文件的内容长度进行切片
2b) 切片大小,默认等于block大小
3c) 切片时不考虑数据集整体,而是逐个针对每一个文件单独切片
4
5
(3)、FileInputFormat中切片的大小的参数配置
通过分析源码,在FileInputFormat中,计算切片大小的逻辑:Math.max(minSize, Math.min(maxSize, blockSize)); 切片主要由这几个值来运算决定
1
2
3
4
5
6
7 1minsize:默认值:1
2 配置参数: mapreduce.input.fileinputformat.split.minsize
3maxsize:默认值:Long.MAXValue
4 配置参数:mapreduce.input.fileinputformat.split.maxsize
5blocksize
6
7
因此,默认情况下,切片大小=blocksize
1
2
3
4
5
6
7
8
9
10
11 1maxsize(切片最大值):
2参数如果调得比blocksize小,则会让切片变小,而且就等于配置的这个参数的值
3minsize (切片最小值):
4参数调的比blockSize大,则可以让切片变得比blocksize还大
5
6选择并发数的影响因素:
71、运算节点的硬件配置
82、运算任务的类型:CPU密集型还是IO密集型
93、运算任务的数据量
10
11
reducetask的并行度影响整个job的执行并发度和执行效率,但与maptask的并发数由切片数决定不同,Reducetask数量的决定是可以直接手动设置:
1
2
3
4 1//默认值是1,手动设置为4
2job.setNumReduceTasks(4);
3
4
如果数据分布不均匀,就有可能在reduce阶段产生数据倾斜
1
2
3
4 1注意: reducetask数量并不是任意设置,还要考虑业务逻辑需求,有些情况下,需要计算全局汇总结果,就只能有1个reducetask
2尽量不要运行太多的reduce task。对大多数job来说,最好rduce的个数最多和集群中的reduce持平,或者比集群的 reduce slots小。这个对于小集群而言,尤其重要。
3
4
二、MAPREDUCE 编程规范及示例
(一)、编程规范
1
2
3
4
5
6
7
8
9
10
11
12 1(1)用户编写的程序分成三个部分:Mapper,Reducer,Driver(提交运行mr程序的客户端)
2(2)Mapper的输入数据是KV对的形式(KV的类型可自定义)
3(3)Mapper的输出数据是KV对的形式(KV的类型可自定义)
4(4)Mapper中的业务逻辑写在map()方法中
5(5)map()方法(maptask进程)对每一个<K,V>调用一次
6(6)Reducer的输入数据类型对应Mapper的输出数据类型,也是KV
7(7)Reducer的业务逻辑写在reduce()方法中
8(8)Reducetask进程对每一组相同k的<k,v>组调用一次reduce()方法
9(9)用户自定义的Mapper和Reducer都要继承各自的父类
10(10)整个程序需要一个Drvier来进行提交,提交的是一个描述了各种必要信息的job对象
11
12
(二)、wordcount程序展示
(1)定义一个mapper:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 1public class WordCountMapper extends Mapper<LongWritable, Text, Text, IntWritable>{
2 //map方法的生命周期: 框架每传一行数据就被调用一次
3 //key : 这一行的起始点在文件中的偏移量
4 //value: 这一行的内容
5 @Override
6 protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
7 //拿到一行数据转换为string
8 String line = value.toString();
9 //将这一行切分出各个单词
10 String[] words = line.split(" ");
11 //遍历数组,输出<单词,1>
12 for(String word:words){
13 context.write(new Text(word), new IntWritable(1));
14 }
15 }
16}
17
18
(2)定义一个reducer类
1
2
3
4
5
6
7
8
9
10
11
12
13 1@Override
2 protected void reduce(Text key, Iterable<IntWritable> values, Context context) throws IOException, InterruptedException {
3 //定义一个计数器
4 int count = 0;
5 //遍历这一组kv的所有v,累加到count中
6 for(IntWritable value:values){
7 count += value.get();
8 }
9 context.write(key, new IntWritable(count));
10 }
11}
12
13
(3)定义一个主类,用来描述job并提交job
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 1public class WordCountRunner {
2 //把业务逻辑相关的信息(哪个是mapper,哪个是reducer,要处理的数据在哪里,输出的结果放哪里……)描述成一个job对象
3 //把这个描述好的job提交给集群去运行
4 public static void main(String[] args) throws Exception {
5 Configuration conf = new Configuration();
6 Job wcjob = Job.getInstance(conf);
7 //指定我这个job所在的jar包
8// wcjob.setJar("/home/hadoop/wordcount.jar");
9 wcjob.setJarByClass(WordCountRunner.class);
10
11 wcjob.setMapperClass(WordCountMapper.class);
12 wcjob.setReducerClass(WordCountReducer.class);
13 //设置我们的业务逻辑Mapper类的输出key和value的数据类型
14 wcjob.setMapOutputKeyClass(Text.class);
15 wcjob.setMapOutputValueClass(IntWritable.class);
16 //设置我们的业务逻辑Reducer类的输出key和value的数据类型
17 wcjob.setOutputKeyClass(Text.class);
18 wcjob.setOutputValueClass(IntWritable.class);
19
20 //指定要处理的数据所在的位置
21 FileInputFormat.setInputPaths(wcjob, "hdfs://hdp-server01:9000/wordcount/data/big.txt");
22 //指定处理完成之后的结果所保存的位置
23 FileOutputFormat.setOutputPath(wcjob, new Path("hdfs://hdp-server01:9000/wordcount/output/"));
24
25 //向yarn集群提交这个job
26 boolean res = wcjob.waitForCompletion(true);
27 System.exit(res?0:1);
28 }
29
30
(三)、运行模式
1、本地运行模式
(1)mapreduce程序是被提交给LocalJobRunner在本地以单进程的形式运行
(2)而处理的数据及输出结果可以在本地文件系统,也可以在hdfs上
(3)怎样实现本地运行?写一个程序,不要带集群的配置文件(本质是你的mr程序的conf中是否有mapreduce.framework.name=local以及yarn.resourcemanager.hostname参数)
(4)本地模式非常便于进行业务逻辑的debug
2、集群运行模式
(1)将mapreduce程序提交给yarn集群resourcemanager,分发到很多的节点上并发执行
(2)处理的数据和输出结果应该位于hdfs文件系统
(3)提交集群的实现步骤:
1
2
3
4
5
6
7 1A、将程序打成JAR包,然后在集群的任意一个节点上用hadoop命令启动
2 $ hadoop jar wordcount.jar cn.itcast.bigdata.mrsimple.WordCountDriver inputpath outputpath
3B、直接在linux的eclipse中运行main方法
4(项目中要带参数:mapreduce.framework.name=yarn以及yarn的两个基本配置)
5C、如果要在windows的eclipse中提交job给集群,则要修改YarnRunner类
6
7
(四) MAPREDUCE中的Combiner
(1)combiner是MR程序中Mapper和Reducer之外的一种组件
(2)combiner组件的父类就是Reducer
(3)combiner和reducer的区别在于运行的位置:Combiner是在每一个maptask所在的节点运行,Reducer是接收全局所有Mapper的输出结果;
(4)combiner的意义就是对每一个maptask的输出进行局部汇总,以减小网络传输量
1
2
3
4
5 1具体实现步骤:
21、 自定义一个combiner继承Reducer,重写reduce方法
32、 在job中设置: job.setCombinerClass(CustomCombiner.class)
4
5
(5)combiner能够应用的前提是不能影响最终的业务逻辑 而且,combiner的输出kv应该跟reducer的输入kv类型要对应起来
(五)、mapreduce的shuffle机制
1、概述:
mapreduce中,map阶段处理的数据如何传递给reduce阶段,是mapreduce框架中最关键的一个流程,这个流程就叫shuffle;
将maptask输出的处理结果数据,分发给reducetask,并在分发的过程中,对数据按key进行了分区和排序;
2、主要流程
shuffle是MR处理流程中的一个过程,它的每一个处理步骤是分散在各个map task和reduce task节点上完成的,整体来看,分为3个操作:
1
2
3
4
5 11、分区partition
22、Sort根据key排序
33、Combiner进行局部value的合并
4
5
3、详细流程
1、maptask收集我们的map()方法输出的kv对,放到内存缓冲区中
2、从内存缓冲区不断溢出本地磁盘文件,可能会溢出多个文件
3、多个溢出文件会被合并成大的溢出文
4、在溢出过程中,及合并的过程中,都要调用partitoner进行分组和针对key进行排序
5、reducetask根据自己的分区号,去各个maptask机器上取相应的结果分区数据
6、reducetask会取到同一个分区的来自不同maptask的结果文件,reducetask会将这些文件再进行合并(归并排序)
7、合并成大文件后,shuffle的过程也就结束了,后面进入reducetask的逻辑运算过程(从文件中取出一个一个的键值对group,调用用户自定义的reduce()方法)
Shuffle中的缓冲区大小会影响到mapreduce程序的执行效率,原则上说,缓冲区越大,磁盘io的次数越少,执行速度就越快
缓冲区的大小可以通过参数调整, 参数:io.sort.mb 默认100M
(六)、YARN
1、概述
Yarn是一个资源调度平台,负责为运算程序提供服务器运算资源,相当于一个分布式的操作系统平台,而mapreduce等运算程序则相当于运行于操作系统之上的应用程序
2、概念
1、yarn并不清楚用户提交的程序的运行机制
2、yarn只提供运算资源的调度(用户程序向yarn申请资源,yarn就负责分配资源)
3、yarn中的主管角色叫ResourceManager
4、yarn中具体提供运算资源的角色叫NodeManager
5、这样一来,yarn其实就与运行的用户程序完全解耦,就意味着yarn上可以运行各种类型的分布式运算程序(mapreduce只是其中的一种),比如mapreduce、storm程序,spark程序,tez ……
6、所以,spark、storm等运算框架都可以整合在yarn上运行,只要他们各自的框架中有符合yarn规范的资源请求机制即可
7、Yarn就成为一个通用的资源调度平台,从此,企业中以前存在的各种运算集群都可以整合在一个物理集群上,提高资源利用率,方便数据共享