Hadoop--MapReduce详解(Map、Shuffle、Reduce)


1、MapReduce概述

1.1 MapReduce是什么

MapReduce是一个分布式运算程序的编程框架,是用户开发“基于Hadoop的数据分析应用”的核心框架。

MapReduce是hadoop的核心组件之一,hadoop要实现分布式需要包括两部分,一部分是分布式文件系统 HDFS,一部分是分布式计算框架 MapReduce。MapReduce核心功能是将用户编写的业务逻辑代码和自带默认组件整合成一个完整的分布式运算程序,并发运行在一个Hadoop集群上

1.2 MapReduce核心思想和简单过程

MapReduce计算框架用来处理海量数据,而一台计算机不可能计算如此大量的数据,一台不行那就使用多台一起处理数据。“ 分而治之 ”是MapReduce的核心思想。

MapReduce有两个过程:

  1. map阶段
    Map负责把一个任务分解成多个任务进行处理。任务分配等会增加程序的复杂性,但人多力量大,效率也会有明显地提高。

  2. reduce阶段
    Reduce负责对map阶段的结果进行汇总输出。

下面这个例子就很好的体现了MapReduce的思想

果园里有1000颗果树,现在要计算一共有多少个果子。

  1. 如果一个人算,就算这个人算的再快也一定要算好久,也有很大的可能 算着算着不想算罢工了 或者 超负荷去医院了;
  2. 但1000个人算的话,分配到每人身上的任务就只剩下一棵树了,虽然需要额外花点时间安排哪些人算哪些树和资源,但1000人同时开始,效率得到了极大的提高,最后将这1000个人所算的数进行汇总得到总果子数。

注:后面还将具体介绍MapReduce工作过程。

1.3 MapReduce的优缺点

优点

  1. MapReduce易于编程
    只需要实现一些简单接口,就可以完成一个分布式程序,这个分布式程序可以分布到大量廉价的PC机器上运行。也就是说你写一个分布式程序,就跟写一个简单的串行程序是一模一样的。

  2. 良好的扩展性(hadoop的特点)
    当你的计算资源不能满足的时候,你可以通过简单的增加机器(nodemanager)来扩展它的计算能力

  3. 高容错性
    MapReduce设计的初衷就是使程序能够部署在廉价的PC机器上,这就要求它具有很高的容错性,比如其中一台机器挂了,它可以把上面的计算任务转移到另外一个节点上运行,不至于整个任务运行失败。

  4. 适合PB级以上海量数据的离线处理
    可以实现上千台服务器集群并发工作,提供数据处理能力

缺点

  1. 不擅长实时计算
    MapReduce无法像MySQL一样,在毫秒或者秒级内返回结果

  2. 不擅长流式计算
    流式计算的输入数据是动态的,而MapReduce的输入数据集是静态的,不能动态变化。这是因为MapReduce自身的设计特点决定了数据源必须是静态的

  3. 不擅长DAG有向图计算
    多个应用程序之间存在依赖关系,后一个应用程序的输入为前一个程序的输出。在这种情况下,每个MapReduce作业的输出结果都会写入到磁盘,会造成大量的磁盘IO,导致性能非常低下


2、MapReduce工作机制

2.1 MapReduce常用数据序列化类型

首先,先介绍MR的常用数据序列化类型,也为了方便后面的理解。
在这里插入图片描述
MR中,以 键值对(K-V) 的形式表示每个数据,而 K 和 V 的数据类型需要根据实即情况而定。框架把作业的输入(InPut)看成是一组<key,value>键值对,同样也产生一组<key,value>键值对作为作业的输出(PutOut),这两组键值对有可能是不同的。

Map和Reduce都要设置 输入 和 输出 数据类型;且Map的输出作为Reduce的输入 进行汇总,所以Map输出和Reduce输入必须一样。

程序的InPut就是Map的输入,程序的OutPut就是Reduce的输出。
在这里插入图片描述

2.2 MapReduce简单过程图示

这里是一个WordCount的例子,结合下面的一些概念和该图一起理解。
在这里插入图片描述

2.2.1 MapReduce进程

一个完整的MapReduce程序在分布式运行时有三类实例进程:

  1. Mr AppMaster:负责整个程序的过程调度及状态协调。
  2. MapTask:负责Map阶段的整个数据处理流程。
  3. ReduceTask:负责Reduce阶段的整个数据处理流程。

由上图可知,这个程序有3个MapTask 和 2个ReduceTask

2.2.2 数据切片与MapTask并行度

MapTask个数(并行度)等于切片数

  1. 一个Job的Map阶段并行度由客户端在提交Job时的切片数决定
  2. 每一个split切片分配一个MapTask并行实例处理
  3. 默认情况下,切片大小=BlockSize(老版本是64M,新版本是128M)
  4. 切片时不考虑数据集整体,而是逐个针对每一个文件单独切片

由上图可知,该程序一共有两个文件。第一个文件是200M,所以被切分成了两个切片;第二个文件是100M(小于128M),单独为一个切片。

2.2.3 分区机制与ReduceTask并行度

ReduceTask个数(并行度)默认等于ReduceTask的进程数

当自己设定分区数时
job.setNumReduceTasks(n):设置分区数
getPartition:自定义所取分区数

  1. 分区机制
    如果ReduceTask的数量 > getPartition的结果数,则会多产生几个空的输出文件part-r-000xxx;
    如果1 < ReduceTask的数量 < getPartition的结果数,则有一部分分区数据无处安放,报错;
    如果ReduceTask的数量=1,则不管MapTask端输出多少个分区文件,最终结果都交给这一个ReduceTask,最终只产生一个结果文件part-r-00000;
    分区号必须从零开始,逐一累加。
  2. 案例分析
    例如:假设自定义分区数为5,
    job.setNumReduceTasks(6);大于5,程序正常运行,多产生几个空的输出文件
    job.setNumReduceTasks(2);报错;
    job.setNumReduceTasks(1),正常运行,最终只产生一个输出文件;

由上图可知,该程序自定义分区,将把结果按单词首位(a-p)、(q-z)输出到两个文件中,ReduceTask个数默认为2。

2.2.4 排序

排序概述

  1. 排序是MapReduce框架中最重要的操作之一
  2. MapTask和ReduceTask均会对数据按照key进行排序。该操作是Hadoop的默认行为。任何应用程序中的数据均会被排序,而不是逻辑上是否需要。
  3. 默认排序是按照字典顺序排序,且实现该排序的方法是快速排序。

排序分类

  1. 部分排序:MapReduce根据输入记录的键对数据集排序,保障输出的每个文件内部有序。
  2. 全排序:最终输出结果只有一个文件,且文件内部有序。
  3. 辅助排序(GroupingComparator):在Reduce端对key进行分组
  4. 二次排序:在自定义排序过程中,如果compareTo中的判断条件为两个即为二次排序
2.2.5 MapReduce过程描述
  1. MapReduce运算程序一般需要分成2个阶段:Map阶段和Reduce阶段;
  2. Map阶段的并发MapTask,完全并行运行,互不相干;
  3. Reduce阶段的并发ReduceTask,完全互不相干,但是他们的数据依赖于上一个阶段的所有MapTask并发实例的输出;
  4. MapReduce编程模型只能包含一个Map阶段和一个Reduce阶段,如果用户的业务逻辑非常复杂,那就只能多个MapReduce程序,串行运行。

注:MapTask如何工作、ReduceTask如何工作等若干问题细节下面会继续介绍

2.3 MapReduce工作机制

MapReduce详细工作流程
在这里插入图片描述
在这里插入图片描述

2.3.1 MapTask工作机制

过程详解

(1)Read阶段:MapTask通过用户编写的RecordReader,从输入InputSplit中解析出一个个key/value。
(2)Map阶段:该节点主要是将解析出的key/value交给用户编写map()函数处理,并产生一系列新的key/value。
(3)Collect收集阶段:在用户编写map()函数中,当数据处理完成后,一般会调用OutputCollector.collect()输出结果。在该函数内部,它会将生成的key/value分区(调用Partitioner),并写入一个环形内存缓冲区中。
(4)Spill阶段:即“溢写”,当环形缓冲区满后,MapReduce会将数据写到本地磁盘上,生成一个临时文件。在写入之前,先要对数据进行分区划分和一次本地排序

  • 分区划分。通过调用Partitioner的getPartition()方法就能知道该输出要送往哪个Reducer。默认的Partitioner使用Hash算法来分区,即通过key.hashCode() mode R来计算,R为Reducer的个数。getPartition返回Partition事实上是个整数,例如有10个Reducer,则返回0-9的整数,每个Reducer会对应到一个Partition。map输出的键值对,与partition一起存在缓冲中。

  • 对每部分分区的数据,使用快速排序算法(QuickSort)对key排序。并在必要时对数据进行合并(Combiner)、压缩(Compress

  • )等操作。
    在这里插入图片描述
    最终写入磁盘的是一个文件内部分区、区内部有序的临时文件
    在这里插入图片描述

(5)合并Spill文件阶段:当所有数据处理完后,MapTask会将所有临时文件合并成一个大文件,并保存到文件output/file.out中,同时生成相应的索引文件output/file.out.index。

  • 在进行文件合并过程中,MapTask以分区为单位进行合并。对于某个分区,它将采用多轮递归合并的方式。每轮合并io.sort.factor(默认10)个文件,并将产生的文件重新加入待合并列表中,对文件排序后,重复以上过程,直到最终得到一个大文件。

  • 让每个MapTask最终只生成一个数据文件,可避免同时打开大量文件和同时读取大量小文件产生的随机读取带来的开销。

最终每个MapTask只产生了一个文件
在这里插入图片描述

2.3.2 ReduceTask工作机制

过程详解
(1)Copy阶段:ReduceTask从各个MapTask上远程拷贝一片数据,并针对某一片数据,如果其大小超过一定阈值,则写到磁盘上,否则直接放到内存中。
(2)Merge阶段:在远程拷贝数据的同时,ReduceTask启动了两个后台线程对内存和磁盘上的文件进行合并,以防止内存使用过多或磁盘上文件过多。
(3)Sort阶段:按照MapReduce语义,用户编写reduce()函数输入数据是按key进行聚集的一组数据。为了将key相同的数据聚在一起,Hadoop采用了基于排序的策略。由于各个MapTask已经实现对自己的处理结果进行了局部排序,因此,ReduceTask只需对所有数据进行一次归并排序即可,再以key进行分组。
(4)Reduce阶段:reduce()函数将计算结果写到HDFS上。

2.3.3 Shuffle工作机制

Map方法之后,Reduce方法之前的数据处理过程称之为Shuffle

实际上包括了前面所说的 Map阶段的数据溢写、分区、排序、合并;Reduce阶段的Copy、Merge、Sort。都已基本介绍。

这里再来简单介绍下shuffle中的两个可选优化

1、Combiner
本质:提前进行聚合,让MapTask分担ReduceTask的工作。

先讨论下面这个问题

  • 如果我们有60亿个数据,Mapper会生成60亿个键值对在网络间进行传输,但如果我们只是对数据求和,那么很明显的Mapper只需要输出它所知道的和即可。这样做不仅可以减轻网络压力,同样也可以大幅度提高程序效率。

Combiner目的:减少传输到Reduce中的数据量。为了削减Mapper的输出从而减少网络带宽和Reducer之上的负载。

对于Combiner有几点需要说明的是:

  • combine的输入和reduce的完全一致,输出和map的完全一致

  • 与combine与reducer不同的是,combiner没有默认的实现,需要显式的设置在conf中才有作用。combine是在每一个MapTask所在的节点运行;Reducer是接收全局所有Mapper的输出结果;

  • 并不是所有的job都适用combiner,只有操作满足结合律的才可设置combiner。combine操作类似于:opt(opt(1, 2, 3), opt(4, 5, 6))。如果opt为求和、求最大值的话,可以使用,但是如果是求中值的话,不适用。

  • 一般来说,combiner和reducer它们俩进行同样的操作。
    在这里插入图片描述

2、Compress
在进行网络传输前将数据压缩(如:ReuceCopyu数据前),接收数据后再进行解压,可以大大减少了磁盘IO以及网络IO;将Reduce数据的结果进行压缩,也能够很好的节省空间。

MR支持的压缩编码
在这里插入图片描述

注意:采用压缩技术减少了磁盘IO,但同时增加了CPU运算负担。所以,压缩特性运用得当能提高性能,但运用不当也可能降低性能。

压缩基本原则:

  • 运算密集型的job,少用压缩
  • IO密集型的job,多用压缩

3、MapReduce编码规范

用户编写的程序分成三个部分:Mapper、Reducer和Driver。

  1. Mapper阶段
    (1)用户自定义的Mapper要继承自己的父类
    (2) Mapper的输入数据是KV对的形式(KV的类型可自定义)
    (3) Mapper中的业务逻辑写在map()方法中
    (4) Mappen的输出数据是KV对的形式(KV的类型可自定义)
    (5) map()方法(MapTask进程)对每一个<K,V>调用一次

  2. Reducer阶段
    (1)用户自定义的Reducer要继承自己的父类
    (2) Reducer的输入数据类型对应Mapper的输出数据类型,也是KV
    (3) Reducer的业务逻辑写在reduce()方法中
    (4) ReduceTask进程对每一组相同k的<k,v>组调用一次reduce()方法
    (5) Reducer的输出数据类型也是KV

  3. Driver阶段
    相当于YARN集群的客户端,用于提交我们整个程序到YARN集群,提交的是封装了MapReduce程序相关运行参数的job对象


4、简单示例----WordCount

根据编码规范,要实现自定义Mapper、Reducer、Driver三个类

Mapper类

import java.io.IOException;

import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Mapper;

/*
 KEYIN      输入数据的key             表示每行数据的偏移量
 VALUEIN    输入数据的value			 表示每行数据
 KEYOUT		输出数据的key            表示每个输出数据的key
 VALUEOUT   输出数据的value          表示每个输出数据的key
 
 1、继承Mapper类
 2、指定以上四个参数类型
 
 */

public class WordcountMapper extends Mapper<LongWritable, Text, Text, IntWritable>{
	
	//输出的key  value
	Text k = new Text();
	IntWritable v = new IntWritable(1);
	
	@Override
	protected void map(LongWritable key, Text value, Context context)
			throws IOException, InterruptedException {
		
		//1. 读取每一行
		String line = value.toString();
		
		//2. 切割单词
		String[] words = line.split(" ");
		
		//3. 循环写出
		for (String word : words) {
			k.set(word);
			context.write(k, v); 
		}
	}
}

Reducer类

import java.io.IOException;

import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Reducer;
/*
 KEYIN      输入数据的key             
 VALUEIN    输入数据的value			 
 KEYOUT		输出数据的key            
 VALUEOUT   输出数据的value          
 
 1、继承Reducer类
 2、指定以上四个参数类型
 
 */
public class WordcountReducer extends Reducer<Text, IntWritable, Text, IntWritable>{
	
	IntWritable v = new IntWritable();
	int sum;
	
	  @Override
	protected void reduce(Text key, Iterable<IntWritable> values,
			Context context) throws IOException, InterruptedException {
		  
		  //you,1
		  //you,1
		  
		  sum = 0;
		  
		  //1. 累加求和
		  for (IntWritable value : values) {
			sum += value.get();
		  }
		  
		  //2. 写出
		  v.set(sum);
		  context.write(key, v);
	
		  //you,2
		  
	}

}

Driver

import java.io.IOException;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;

public class WordcountDriver {

	public static void main(String[] args) throws IOException, ClassNotFoundException, InterruptedException {

		args = new String[] { "D:\\Z-Test\\input\\InPutWordCount", "D:\\Z-Test\\output\\OutPutWordCount" };

		Configuration conf = new Configuration();

		// 1 获取配置信息以及封装任务job对象
		Job job = Job.getInstance(conf);

		// 2 设置jar加载路径
		job.setJarByClass(WordcountDriver.class);

		// 3 关联map和reduce类
		job.setMapperClass(WordcountMapper.class);
		job.setReducerClass(WordcountReducer.class);

		// 4 设置map输出kv类型
		job.setMapOutputKeyClass(Text.class);
		job.setMapOutputValueClass(IntWritable.class);

		// 5 设置最终输出kv类型
		job.setOutputKeyClass(Text.class);
		job.setOutputValueClass(IntWritable.class);

		// 6 设置输入和输出路径
		FileInputFormat.setInputPaths(job, new Path(args[0]));
		FileOutputFormat.setOutputPath(job, new Path(args[1]));

		// 7 提交
		boolean result = job.waitForCompletion(true); // 为true 打印运行信息
		System.exit(result ? 0 : 1);
	}

}

InPutWordCount文件中有两个.txt文件
在这里插入图片描述
在这里插入图片描述
运行结果
在这里插入图片描述
由于没有进行自定义分区,这里默认只有一个分区,也就只有一个part-r-000000文件
在这里插入图片描述
统计成功
在这里插入图片描述

  • 7
    点赞
  • 46
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: amples-2.7.1.jar wordcount /input /output 这是一个Hadoop命令,用于运行一个名为wordcount的MapReduce作业。hadoop-mapreduce-examples-2.7.1.jar是Hadoop MapReduce示例程序的JAR文件,包含了许多常见的MapReduce作业示例。/input是输入数据的路径,/output是输出结果的路径。 ### 回答2: hadoop jar hadoop-mapreduce-ex是一个Hadoop MapReduce应用程序,它是Hadoop的一个组件,用于处理大规模数据集。Hadoop MapReduce是一个开源的计算框架,通过分布式计算处理海量数据,具有高可靠性、高扩展性和高效性等特点。 hadoop-mapreduce-ex是一个扩展程序包,它提供了更多的MapReduce应用程序。该程序包包括了很多实用的工具和例子,可以帮助用户更快地实现MapReduce任务,提高了处理大数据的效率和质量。 在使用hadoop jar hadoop-mapreduce-ex时,需要使用hadoop jar命令。此命令的作用是将MapReduce程序打包成一个JAR文件,并提交给Hadoop集群进行处理。具体来说,hadoop jar命令有以下功能: 1. 提交MapReduce任务:使用该命令可以将作业提交到Hadoop集群中,启动MapReduce任务; 2. 配置MapReduce作业:通过命令行参数可以配置MapReduce作业的参数; 3. 监控MapReduce作业:通过该命令可以查看MapReduce作业的状态和进度; 4. 执行本地MapReduce任务:通过该命令可以在本地测试MapReduce程序的正确性和性能。 总之,hadoop jar hadoop-mapreduce-ex是一个非常有用的工具,它帮助用户更好地利用Hadoop MapReduce框架,处理并分析大数据集,提高业务效率和质量。 ### 回答3: Hadoop Jar Hadoop-MapReduce-Ex是Hadoop中的一个MapReduce拓展工具包,可以帮助用户更加方便地进行分布式计算任务。 Hadoop是一个开源的、由Apache开发的分布式计算框架,其最大的特点是能够在大规模的集群中高效地处理海量数据。而MapReduce作为Hadoop中的计算模式,可以将大数据集分解成独立小块,进行并行处理。 在Hadoop Jar Hadoop-MapReduce-Ex中,包含了许多有用的工具包和API,包括: 1. MapReduce算法库:提供了常见的MapReduce算法实现,例如排序、过滤、连接等,用户可以通过简单的配置和调用API方便地进行分布式计算任务。 2. 自定义InputFormat和OutputFormat:这个工具包提供了自定义输入和输出格式的API,用户可以将原始数据转换为Hadoop可处理的格式,或者将MapReduce结果转换为用户需要的格式。 3. MapReduce作业执行框架:这个框架提供了对MapReduce作业进行管理和监控的功能,用户可以方便地查看作业执行情况、调整作业配置等。 4. 分布式缓存:这个工具包提供了分布式缓存的API,可以将需要共享的数据存入缓存中,便于后续作业的调用和共享。 综上,Hadoop Jar Hadoop-MapReduce-Ex是一个非常有用的工具包,可以帮助用户快速实现分布式计算任务,提高计算效率和数据处理能力。但需要注意的是,使用该工具包需要有一定的编程经验和Hadoop的相关知识。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值