MapReduce是一个分布式运算程序的编程框架,核心是将用户编写的业务逻辑代码和自带默认组件整合成一个完整的分布式运算程序,并运行在一个Hadoop集群上,高容错,适合PB级以上的海量数据的离线处理。
MapReduce概述
MapReduce核心思想
)分布式的运算程序往往需要分成至少2个阶段。
2)第一个阶段的MapTask并发实例,完全并行运行,互不相干。
3)第二个阶段的ReduceTask并发实例互不相干,但是他们的数据依赖于上一个阶段的所有MapTask并发实例的输出。
4)MapReduce编程模型只能包含一个Map阶段和一个Reduce阶段,如果用户的业务逻辑非常复杂,那就只能多个MapReduce程序,串行运行。
总结:分析WordCount数据流走向深入理解MapReduce核心思想。
MapReduce进程
一个完整的MapReduce程序在分布式运行有三类实例进程:
1)MrAPPMaster:负责整个程序的过程调度及状态协调。
2)MapTask:负责Map阶段的整个数据处理过程。
3)ReduceTask:负责Reduce阶段的整个数据处理过程。
用户编写的程序分为三个问题:Mapper,Reduce,Driver。
Mapper阶段
- 用户自定义的Mapper要继承自己的类。
- Mapper输入形式是KV形式,(KV的类型可自定义)。
- Mapper的业务逻辑可以写如Map()中。
- Mapper输出形式是KV形式,(KV的类型可自定义)。
- map()方法(MapTask进程),对每一个
调用一次。
Reduce阶段
- 用户自定义的Reducer要继承自己的父类。
- Reducer的输入类型是对应Mapper的输出类型,也是KV.
- Reducer的业务逻辑写入到reduce()方法中。
- ReduceTask进程对每一组相同K的
组调用一次reduce()方法。
Driver阶段
- 相当于YARN集群的客户端,用于提交整个程序到YARN集群中,提交的是封装了Mapreduce程序相关的运行参数的job对象。
WordCount案例实操
需求:在给定的文本文件中统计输出每一个单词出现的总次数
需求分析:
环境准备:
(1)创建maven工程
(2)在pom.xml文件中添加如下依赖
<dependencies> <dependency> <groupId>junitgroupId> <artifactId>junitartifactId> <version>RELEASEversion> dependency> <dependency> <groupId>org.apache.logging.log4jgroupId> <artifactId>log4j-coreartifactId> <version>2.8.2version> dependency> <dependency> <groupId>org.apache.hadoopgroupId> <artifactId>hadoop-commonartifactId> <version>2.7.2version> dependency> <dependency> <groupId>org.apache.hadoopgroupId> <artifactId>hadoop-clientartifactId> <version>2.7.2version> dependency> <dependency> <groupId>org.apache.hadoopgroupId> <artifactId>hadoop-hdfsartifactId> <version>2.7.2version> dependency> dependencies>
(3)在项目的src/main/resources目录下,新建一个文件,命名为“log4j.properties”,在文件中填入。
log4j.rootLogger=INFO, stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - %m%n
log4j.appender.logfile=org.apache.log4j.FileAppender
log4j.appender.logfile.File=target/spring.log
log4j.appender.logfile.layout=org.apache.log4j.PatternLayout
log4j.appender.logfile.layout.ConversionPattern=%d %p [%c] - %m%n
4.编写程序
(1)编写Mapper类
package com.atguigu.mapreduce; 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; public class WordcountMapper extends Mapper{ 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); } } }
(2)编写Reducer类
package com.atguigu.mapreduce.wordcount; import java.io.IOException; import org.apache.hadoop.io.IntWritable; import org.apache.hadoop.io.Text; import org.apache.hadoop.mapreduce.Reducer; public class WordcountReducer extends Reducer{ int sum; IntWritable v = new IntWritable(); @Override protected void reduce(Text key, Iterable values,Context context) throws IOException, InterruptedException { // 1 累加求和 sum = 0; for (IntWritable count : values) { sum += count.get(); } // 2 输出 v.set(sum); context.write(key,v); } }
(3)编写Driver驱动类
package com.atguigu.mapreduce.wordcount; 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 { // 1 获取配置信息以及封装任务 Configuration configuration = new Configuration(); Job job = Job.getInstance(configuration); // 2 设置jar加载路径 job.setJarByClass(WordcountDriver.class); // 3 设置map和reduce类 job.setMapperClass(WordcountMapper.class); job.setReducerClass(WordcountReducer.class); // 4 设置map输出 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); System.exit(result ? 0 : 1); } }
Hadoop序列化
序列化描述
序列化就是将内存中的对象,转化为字节序列,以便于持久化和网络传输。
反序列化就是将字节序列或者磁盘持久化数据转化为内存中的对象。
为什么不用JAVA的序列化:
Java序列化是重量级的序列化框架,一个对象被序列化后,会携带额外的信息,不便于网络传输 。
Hadoop序列化特点:
MapRedcuce框架原理
InputFormat数据输入
切片与MapTask并行度决定机制
1.问题引出
MapTask的并行度决定Map阶段的任务处理并发度,进而影响到整个Job的处理速度。
思考:1G的数据,启动8个MapTask,可以提高集群的并发处理能力。那么1K的数据,也启动8个MapTask,会提高集群性能吗?MapTask并行任务是否越多越好呢?哪些因素影响了MapTask并行度?
2.MapTask并行度决定机制
数据块:Block是HDFS上物理上把数据分成一块一块得。
数据切片:数据切片只是在逻辑上对输入进行分片,并不会在磁盘上将其切分成片进行存储。
数据切片与MapTask并行度决定机制