一、什么是MapReduce
MapReduce是一个分布式运算程序的编程框架(模型),其核心功能是将用户编写的业务逻辑代码和自带的默认组件整合成一个完整的分布式运算程序,并发的运行在一个hadoop集群上
二、为什么需要MapReduce
- 海量数据因为硬件资源限制,无法在单机上处理
- 将单机版程序扩展到集群来分布式运行,极大增加程序的复杂度和开发难度
- 引入MR之后,开发人员可以专注于业务逻辑代码的开发,分布式计算中的复杂性交给MR框架处理
三、MapReduce编程规范
- MR程序的业务编码分为两个大类:
一部分配置程序的运行信息
一部分编写该MR程序的业务逻辑,并且业务逻辑的map阶段和reduce阶段分别继承Mapper类和Reducer类 - MR程序具体规范编写
(1)用户编写的程序分为三部分:Mapper,Reducer,Driver(提交运行MR程序的客户端)
(2)Mapper的输入数据是KV对 (键值对)的形式(KV类型可以自定义)
(3)Mapper的输出数据是KV对的形式(KV类型可以自定义)
(4)Mapper中的业务逻辑编写在map()方法中
(5)map()方法(maptask进程)对每个<K,V>调用一次
(6)Reucer的数据数据类型应该对应Mapper的输出数据类型,也是KV对的形式
(7)Reducer的业务逻辑写在reduce()方法中
(8)reducetask进程对每一组相同K的<K,V>组调用一次reduce()方法
(9)用户自定义的Mapper和Reducer都要继承各自的父类
(10)整个程序需要一个Rriver来进行提交,提交的是一个描述了各种必要信息的job对象
四、运行模式
集群运行模式:
- 将MapReduce程序提交给Yarn集群,分发到很多的节点上并发执行
- 处理的数据和输出结果应该位于HDFS文件系统
- 提交集群的实现步骤:将程序打成jar包,之后在集群的任一节点上用hadoop jar命令启动
- 例wordcount函数:
hadoop jar /software/hadoop/share/hadoop/mapreduce/hadoop-mapreduce-examples-2.7.4.jar(jar包全路径)
wordcount (函数名)/wc.txt(HDFS上的文件输入路径) /wcout0302(HDFS上的文件输出路径)- 例pi函数:
hadoop jar /software/hadoop/share/hadoop/mapreduce/hadoop-mapreduce-examples-2.7.4.jar
pi 5(Map数量) 5(Reduce数量)
五、Shuffle阶段的组件
- partition分区组件
继承partitioner类,将结果存储在不同的文件中 - sort组件与序列化
序列化(Serialization):结构化对象转化为字节流
反序列化(Deserialization):把字节流转化为结构化对象
进程间传递对象或持久化对象的时候,需要序列化对象成字节流,反之从接收或者从磁盘中读取数据时要将字节流转化为对象,需要进行反序列化
Hadoop嫌弃Java的序列化框架(Serializable)不够精简高效(对象被序列化后会附带各种校验信息,header,继承体系等),开发了自己的一套序列化机制(Writable)
java | hadoop |
---|---|
byte | ByteWritable |
short | ShortWritable |
int | IntWritable |
long | LongWritable |
float | FloatWritable |
double | DoubleWritable |
String | Text |
null | NullWritable |
Writable有个子接口WritableComparable,该接口不仅可以实现序列化,还可以对key进行比较
- combiner局部合并组件
(1)什么是combiner:
combiner组件作用在maptask之后给maptask的结果进行局部汇总,以减轻reducetask的计算负载,减少网络传输
(2)如何使用combiner:
Combiner和Reducer一样,编写一个类继承Reducer,reduce()方法中写具体的combiner逻辑,之后在job中设置combiner组件:job.setCombinerClass(MyCombiner.class) - group分组组件
group组件是shuffle组件当中reduce端的一个功能组件,主要作用决定哪些数据作为一组
六、Shuffle原理详解
- MapReduce中,map阶段处理的数据通过一个流程传给reduce阶段,这个流程就叫shuffle(数据汇洗)。shuffle分为map shuffle和reduce shuffle。
MapShuffle:
因为频繁的磁盘I/O操作会严重的降低效率,所以map()方法处理后的数据优先存储到map节点的“环形内存缓冲区”,在spill(溢写)之前进行partition(分区),也就是对于每个键值对来说,都增加了一个partition属性值,(默认retuen (key.hashCode() & Integer.MAX_VALUE)% numPartition )然后连同键值对一起序列化成字节数组写入到缓冲区(缓冲区采用的就是字节数组,默认大小为100M)。
当写入的数据量达到预先设置的阙值(spill percent,默认0.8)后便会启动溢写出线程将缓冲区中的那部分数据溢写(spill)到磁盘的临时文件中,并在写入前把相同key的数据进行排序(sort)和合并(combine,可选操作,combiner可以使map的结果更紧凑,减少写磁盘的数据,同时直接将combine后的数据传给reduce,减少网络传输开销)
溢出写过程按轮询方式将缓冲区中的内容写到磁盘中。当整个map任务完成溢出写后,会对磁盘中这个map任务产生的所有临时文件(spill文件)通过归并排序算法进行归并(merge)操作生成最终的正式输出文件
ReduceShuffle:
reduce task从每个map task的结果文件中拉取对应分区的数据。因为数据在map阶段已经是分好区了,并且会有一个额外的索引文件(环形缓冲区中的一部分内存用来存入数据索引)记录每个分区的起始偏移量。所以reduce task取数的时候直接根据偏移量去拉取对应数据
reduce task拉取到所有数据后会将拉取到的所有数据再次进行合并,排序,按照自定义的reducer()的逻辑代码去处理。
MR代码以及测试数据
链接: https://pan.baidu.com/s/1vLWeAGqq1Y-TDukt0kwXgQ
提取码: i5gx