本篇文章中,笔者记录了自己对于MapReduce的肤浅理解,参考资料主要包括《大数据Hadoop 3.X分布式处理实战》和网络视频课程。下文介绍了MapReduce的基本概念、运行逻辑以及在 wordCount 代码示例。
一、MapReduce概述
1.概述
google为解决其搜索引擎中的大规模网页数据的并行化处理问题,设计了MapReduce,在发明MapReduce之后首先用其重新改写了搜索引擎中web文档索引处理系统。
MapReduce是面向大数据并行处理的计算模型、框架和平台。实现了基于集群的高性能并行计算平台;是一个并行计算和运行软件框架;是一个并行程序设计模型和方法。
2.MR实现的主要功能
- 数据划分和计算任务调度
数据划分:系统自动将一个作业(job)待处理的数据划分为很多个数据块,每个数据块为一个计算任务,即task,并自动调度计算节点来处理相应的数据块。
计算调度:作业和任务的调度功能主要负责分配和调度这些计算节点,同时监控节点的执行状态、map节点计算的同步控制。 - 代码、数据互相定位
代码向数据迁移:尽量实现本地化数据处理,减少通信延迟。 - 系统优化
一是中间数据进入reduce节点之前会进行一定的合并处理;二是map输出的中间数据需要进行一定策略的进行划分处理,以保证相关性数据发送到同一个reducer节点;三是一些计算优化处理,对于执行最慢的任务实行多备份执行、选最快完成者作为结果。 - 出错检测和恢复
由于低端商用服务器构成的大规模计算集群的节点硬件(内存、磁盘和主机)损坏和软件损坏是常态,因此MapReduce需要检测并隔离出错节点,调配新的节点接管出错节点的计算任务。
此外,系统还要维护数据存储的可靠性,用多备份冗余存储机制提高数据的可靠性,并及时检出和恢复出错的数据。
3. MR的运行框架和数据处理流程
-
MAP阶段:负责数据的过滤和分发,将原始数据转化为键值对。
-
REDUCE阶段:负责数据合并,将相同key值的value进行处理在输出新的键值对作为最终结果。mapper<keyIn, valueIn, keyOut, valueOut>
mapper<keyIn, valueIn, keyOut, valueOut>
reducer<keyIn, valueIn, keyOut, valueOut>
- SHUFFLE阶段:map阶段计算输出的数据如何传递给reduce就是shuffle来完成的,shuffle 的核心机制包括数据分区、排序和缓存。
map和reduce的操作需要rd自己开发相应的map类和reduce类,但是shuffle是系统自动实现的。
二、MR-wordCount 编码
1. 内在的序列化数据格式
在海量数据进行传输时,需要对数据进行序列化,但相比之下java本身提供的对象序列化机制比较复杂,因此Hadoop提供了一些自己的数据类型,这些数据类型实现了WritableComparable接口,使用这些类型定义的数据可以被序列化进行网络传输和文件存储以及进行大小比较。
参考:Hadoop序列化
下面介绍wordCount的代码实现:
2. wordCountMapper
mapper阶段的代码:
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Mapper;
import java.io.IOException;
/**
* keyIn 行的偏移量
* valueIn 行的内容
* keyOut 单词
* valueOut 单词数量
* hadoop序列化机制的数据类型:精简信息,提高整体传输的速度。
*/
public class wordCountMapper extends Mapper<LongWritable, Text, Text, IntWritable> {
@Override
protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
String[] words = value.toString().split(" ");
for (String word:words){
context.write(new Text(word),new IntWritable(1));
}
}
}
3. wordCountReducer
reduce阶段的代码:
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Reducer;
import java.io.IOException;
public class wordCountReducer extends Reducer<Text, IntWritable,Text, IntWritable> {
@Override
protected void reduce(Text key, Iterable<IntWritable> values, Context context) throws IOException, InterruptedException {
int a =0;
for (IntWritable value:values){
a= value.get() + a ;
}
context.write(key,new IntWritable(a));
}
}
4. wordCountJobSubmitter
任务提交的代码:
【提交任务的类需要指明作业的包、类、kv对的数据类型、读文件和写文件的目录和任务提交到集群中的指令。】
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
import javax.xml.soap.Text;
import java.io.IOException;
public class wordCountJobSubmitter {
public static void main(String[] args) throws IOException, ClassNotFoundException, InterruptedException {
Configuration configuration = new Configuration();
Job job = Job.getInstance(configuration);
// 指明当前job所在的jar包,否则运行过程中maptask和reducetask无法找到提交的job所在的类
job.setJarByClass(wordCountJobSubmitter.class);
// 指明 mapper 和 reducer 的类
job.setMapOutputValueClass(wordCountMapper.class);
job.setReducerClass(wordCountReducer.class);
// 指明kv数据类型
job.setMapOutputKeyClass(Text.class);
job.setMapOutputValueClass(IntWritable.class);
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(IntWritable.class);
// 指明 读文件和写文件的路径
FileInputFormat.setInputPaths(job,"test");
FileOutputFormat.setOutputPath(job,new Path("123test"));
// 将任务提交到hadoop集群中
job.waitForCompletion(true);
}
}
感谢阅读,如有错误,欢迎指正和探讨!