MapReduce
- mapreduce: 是一个分布式运算编程框架,是用户开发“基于Hadoop的数据分析应用”的核心框架
- 核心功能: 自带默认组件,用户编写的业务逻辑代码,整合成一个完整的分布式运算程序,并发运行在Hadoop集群上
为什么需要MapReduce
- 海量数据单机处理,硬件资源受限,所以无法胜任(硬盘读写速度、CPU处理速度等)
- 单机版阔成分布式版,增加程序复杂度和开发难度
- 为了提高开发效率,将分布式程序中的公共功能封装成框架,让开发人员可以将精力集中于业务逻辑。
MapReduce程序演示
- wordcount程序
- 开启HDFS和YARN
- 将元数据上传到HDFS
- 运行命令:hadoop jar hadoop-mapreduce-examples-2.6.5.jar wordcount 输入路径 输出路径
MapReduce 示例编写及编程规范
编码规范
Mapper
- 1.继承Mapper类
- 2.输入数据是<key,value>对形式(kv的类型可以自定义)
- 3.输出数据是<key,value>对形式(kv的类型可以自定义)
- 4.业务逻辑是写在map()方法中
- 5.MapTask进程对每一个<k,v>调用一次map()方法
Reduce
- 1.继承Reduce类
- 2.输入数据类型对应Mapper的输出数据类型,也是<key,value>对形式
- 3.输出数据是<key,value>对形式(kv的类型可以自定义)
- 4.业务逻辑是写在reduce()方法中
- 5.MapTask进程对每一组相同的k的<k,v>调用一次reduce()方法
Driver
(提交运行MR程序的客户端),配置程序的运行信息,提交job对象
WordCount 示例程序编写
WordCount 的业务逻辑:
MapTask阶段
- 处理每个数据分块的单词统计分析,思路是将每一行文本拆分成一个个的单词,每遇到一个单词则把其转换成一个 key-value 对,比如单词 hello,就转换成<’hello’,1>发送给 ReduceTask 去汇总。
ReduceTask阶段
- 将接收 MapTask 的结果,按照 key 对 value 做汇总计数
- 流程图
WordCount 程序编写:
Map端: 将每一行文本拆分为一个个单词,每遇到一个单词则把其转换成一个key-value对
Reduce端: 接收Map端的结果,按照key对value做汇总计数
Job端: 程序的主入口,相当于YARN集群的客户端
MapReduce 程序运行模式
本地运行模式:
集群运行模式:
//创建配置信息类
Configuration conf=new Configuration();
conf.set("fs.defaultFS","hdfs://master:9000");
conf.set("mapreduce.framework.name","yarn");
conf.set("yarn.resourcemanage.hostname","master");
System.setProperty("HADOOP_USER_NAME","theone");
//新建一个Job任务
Job job=Job.getInstance(conf);
//指定jar包的路径
job.setJarByClass(WordCountDemo.class);
//指定Mapper类和Reducer类
job.setMapperClass(WordCountMapper.class);
//指定combiner
job.setCombinerClass(WordCountReducer.class);
job.setReducerClass(WordCountReducer.class);
//指定maptask的key-value对的输出类型
//job.setMapOutputKeyClass(Text.class);
//job.setMapOutputValueClass(IntWritable.class);
//指定reducetask的key-value对的输出类型
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(IntWritable.class);
//指定mr程序输入输出数据路径
Path inpath=new Path("/mr/wordcount/input");
Path outpath=new Path("/mr/wordcount/output");
//获取fs对象
FileSystem fs = FileSystem.get(conf);
if (fs.exists(outpath)){
//存在则删除输出路径
fs.delete(outpath,true);
}
FileInputFormat.setInputPaths(job, inpath);
FileOutputFormat.setOutputPath(job, outpath);
//提交任务job,等待mr程序运行完成打印反馈信息
boolean waitForCompletion = job.waitForCompletion(true);
// 退出程序
System.exit(waitForCompletion?0:1);
MapReduce 三大组件(一):Combiner
- 什么是Combiner?
什么是Combiner?
- 作用: 在MapTask之后给MapTask的结果进行局部汇总,以减轻ReduceTask的计算负载,减少网络传输
- 实现: 本地key的聚合,对map输出的key排序,value进行迭代,有本地Reduce之称
数据格式的转换:
map:(k1,v1)–>list(k2,v2)
combiner:(k2,list(v2))–>list(k3,v3)
reduce:(k3,list(v3))–>list(k4,v4)
- 具体实现步骤:
(1)自定义一个Combiner继承Reducer,重写reduce方法
(2)在job中设置:job.setCombinerClass(xxx.class) - 具体代码实现
和reduce端的代码一致,在job中设置Cominer类
注意事项
- (1)运行位置
Combiner是在每一个MapTask所在的节点运行
recuder是接收全局所有Mapper的输出结果 - (2)Combiner 的输出 KV 跟 Reducer 的输入 KV 类型相对应
- (3)Combiner 使用的原则是:有或没有都不能影响业务逻辑,都不能影响最终结果。
- (4)适用场景:汇总统计;不适用场景:求平均数。适用于Reduce的输入key/value与输出key/value类型完全一致情况
MapReduce 程序的核心运行机制
1-结构
- MRAppMaster(MapReduce Application Master)负责整个程序的过程调度及状态协调
- YarnChild
MapTask:负责Map阶段的整个数据处理流程,阶段并发任务
ReduceTask:负责Reduce阶段的整个数据处理流程,阶段汇总任务
MapTask和ReduceTask不在同一个Yarnchild进程中
2-MR程序的运行流程
- (1)一个 MR 程序启动的时候,最先启动的是 MRAppMaster, MRAppMaster 启动后根据本次 job 的描述信息,计算出需要的 MapTask 实例数量,然后向集群申请机器启动相应数量的 MapTask 进程;
- (2)MapTask 进程启动之后,根据给定的数据切片(哪个文件的哪个偏移量范围)范围进行数据处理,主体流程为:
1,利用客户指定的 InputFormat 来获取 RecordReader 读取数据,形成输入 KV 对
2,将输入 KV 对传递给客户定义的 map()方法,做逻辑运算,并将 map()方法输出的 KV 对收集到缓存
3,将缓存中的 KV 对按照 K 分区排序后不断溢写到磁盘文件- (3)MRAppMaster 监控到所有 MapTask 进程任务完成之后(真实情况是,某些 MapTask 进程处理完成后,就会开始启动 ReduceTask 去已完成的 MapTask 处 fetch 数据),会根据客户指定的参数启动相应数量的 ReduceTask 进程,并告知 ReduceTask 进程要处理的数据范围(数据分区);
- (4)ReduceTask 进程启动之后,根据 MRAppMaster 告知的待处理数据所在位置,从若干台 MapTask 运行所在机器上获取到若干个 MapTask 输出结果文件,并在本地进行重新归并排序,然后按照相同 key 的 KV 为一个组,调用客户定义的 reduce() 方法进行逻辑运算,并收集运算输出的结果 KV,然后调用客户指定的 OutputFormat 将结果数据输出到外部存储。
MapTask 并行度决定机制
- 问题场景
MapTask 并行度决定 Map 阶段的任务处理并发度,进而影响到整个 Job 的处理速度。那么, MapTask 并行实例是否越多越好呢?其并行度又是如何决定呢? - 一个 Job 的 Map 阶段并行度由客户端在提交 Job 时决定, 客户端对 Map 阶段并行度的规划的基本逻辑为:
将待处理数据执行逻辑切片(即按照一个特定切片大小,将待处理数据划分成逻辑上的多个 split),然后每一个 split 分配一个 MapTask 并行实例处理
FileInputFormat 切片机制
-
默认切片机制
1.简单地按照文件的内容长度进行切片
2.切片大小,默认等于 block 大小
3.切片时不考虑数据集整体,而是逐个针对每一个文件单独切片 -
切片大小参数配置
切片大小计算公式:long splitSize = computeSplitSize(Math.max(minSize, Math.min(maxSize, blockSize)))
主要参数:
blocksize: 默认是 128M,可通过 dfs.blocksize 修改
minSize: 默认是 1,可通过 mapreduce.input.fileinputformat.split.minsize 修改
maxsize: 默认是 Long.MaxValue,可通过mapreduce.input.fileinputformat.split.maxsize 修改
ReduceTask 并行度决定机制
- ReduceTask 数量可以直接手动设置
job.setNumReduceTasks(4);
如果数据分布不均匀,就有可能在 reduce 阶段产生数据倾斜。 - 注意:ReduceTask 数量并不是任意设置,还要考虑业务逻辑需求,有些情况下,需要计算全局汇总结果,就只能有 1 个 ReduceTask。