本文是董西成《Hadoop技术内幕》一书的读书总结。
MapReduce应用广泛的原因之一就是其易用性,提供了一个高度抽象化而变得非常简单的编程模型,它是在总结大量应用的共同特点的基础上抽象出来的分布式计算框架,在其编程模型中,任务可以被分解成相互独立的子问题。MapReduce编程模型给出了分布式编程方法的5个步骤:
- 迭代,遍历输入数据,将其解析成key/value对;
- 将输入key/value对映射map成另外一些key/value对;
- 根据key对中间结果进行分组(grouping);
- 以组为单位对数据进行归约;
- 迭代,将最终产生的key/value对保存到输出文件中。
下面就简要总结一下编程模型中用到的主要组件以及在其中的作用:
1. InputFormat
主要用于描述输入数据的格式,提供数据切分功能,按照某种方式将输入数据且分成若干个split,确定map task的个数,以及为Mapper提供输入数据,给定某个split,让其解析成一个个key/value对。
InputFormat中的getSplits方法主要完成数据切分的功能,会尝试着将输入数据且分成numSplits个进行存储。InputSplit中只记录了分片的元数据信息,比如起始位置、长度以及所在的节点列表。
在Hadoop中对象的序列化主要用在进程间通信以及数据的永久存储。Client端会调用Job中的InputFormat中的getSplits函数,当作业提交到JobTracker端对作业初始化时,可以直接读取该文件,解析出所有InputSplit,并创建对应的MapTask。
而重要的方法就是getRecordReader,其返回一个RecordReader,将输入的InputSplit解析成若干个key/value对。MapReduce框架在Map Task执行过程中,不断地调用RecordReader对象中的方法,获取key/value对交给map函数处理,伪代码如下:
K1 key = input.createKey(); V1 value = input.createValue(); while(input.next(key, value)){ //invoke map() } input.close();
对于FileInputFormat,这是一个采用统一的方法对各种输入文件进行切分的InputFormat,也是比如TextInputFormat, KeyValueInputFormat等类的基类。其中最重要的是getSplits函数,最核心的两个算法就是文件切分算法以及host选择算法。
文件切分算法主要用于确定InputSplit的个数以及每个InputSplit对应的数据段。
在InputSplit切分方案完成后,就需要确定每个InputSplit的元数据信息: <file, start, length, host>,表示InputSplit所在文件,起始位置,长度以及所在的host节点列表,其中host节点列表是最难确定的。
host列表选择策略直接影响到运行过程中的任务本地性。Hadoop中HDFS文件是以block为单位存储的,一个大文件对应的block可能会遍布整个集群,InputSplit的划分算法可能导致一个InputSplit对应的多个block位于不同的节点上。
hadoop将数据本地性分成三个等级:node locality, rack locality和data center locality。在进行任务调度时,会依次考虑3个节点的locality,优先让空闲资源处理本节点的数据,其次同一个机架上的数据,最差是处理其他机架上的数据。
虽然InputSplit对应的block可能位于多个节点上,但考虑到任务调度的效率,通常不会将所有节点到InputSplit的host列表中,而是选择数据总量最大的前几个节点,作为任务调度时判断任务是否具有本地性的主要凭据。对于FileInputFormat设计了一个简单有效的启发式算法:按照rack包含的数据量对rack进行排序,在rack内部按照每个node包含的数据量对node排序,取前N个node的host作为InputSplit的host列表(N为block的副本数,默认为3)。
当InputSplit的尺寸大于block的尺寸时,MapTask不能实现完全的数据本地性,总有一部分数据需要从远程节点中获取,因此当使用基于FileInputFormat实现InputFormat时,为了提高Map Task的数据本地性,应该尽量使得InputSplit大小与block大小相同。(虽然理论上是这么说,但是这会导致过多的MapTask,使得任务初始时占用的资源很大)。
2. OutputFormat
OutputFormat主要用于描述输出数据的格式,能够将用户提供的key/value对写入特定格式的文件中。其中与InputFormat类似,OutputFormat接口中有一个重要的方法就是getRecordWriter,返回的RecordWriter接收一个key/value对,并将之写入文件。Task执行过程中,MapReduce框架会将map或reduce函数产生的结果传入write方法:
public void map(Text key, Text value, OutputCollector<Text, Text> output, Reporter reporter) throws IOException{ output.collect(newKey, newValue); }
hadoop中所有基于文件的OutputFormat都是从FileOutputFormat中派生的,事实上这也是最常用的OutputFormat。总结发现,FileOutputFormat实现的主要功能有两点:
- 为防止用户配置的输出目录数据被意外覆盖,实现checkOutputSpecs接口,在输出目录存在时抛出异常;
- 处理side-effect file。hadoop可能会在一个作业执行过程中加入一些推测式任务,因此,hadoop中reduce端执行的任务并不会真正写入到输出目录,而是会为每一个Task的数据建立一个side-effect file,将产生的数据临时写入该文件,待Task完成后,再移动到最终输出目录。
默认情况下,当作业成功完成后,会在最终结果目录下生成空文件_SUCCESS,该文件主要为高层应用提供作业运行完成的标识(比如oozie工作流就可以根据这个判断任务是否执行成功)。
3. Mapper和Reducer
Mapper的过程主要包括初始化、Map操作执行和清理三个部分。Reducer过程与Mapper过程基本类似。
- 初始化,Mapper中的configure方法允许通过JobConf参数对Mapper进行初始化工作;
- Map操作,通过前面介绍的InputFormat中的RecordReader从InputSplit获取一个key/value对,交给实际的map函数进行处理;
- 通过继承Closable接口,获得close方法,实现对Mapper的清理。
对于一个MapReduce应用,不一定非要存在Mapper,MapReduce框架提供了比Mapper更加通用的接口:org.apache.hadoop.mapred.MapRunnable,可以直接实现该接口定制自己的key/value处理逻辑(相对于MapReduce阶段中固定的map阶段,可以跳过Map阶段,比如Hadoop Pipes中的将数据发送给其他进程处理)。
MapRunner是其固定实现,直接调用用户job中设置的Mapper Class,此外,hadoop中还提供了一个多线程的MapRunnable实现,用于非CPU类型的作业提供吞吐率。
4. Partitioner
Partitoner的作用是对Mapper产生的中间结果进行分片,将同一分组的数据交给一个Reducer来处理,直接影响这Reducer阶段的负载均衡。其中最重要的方法就是getPartition,包含三个参数,key,value,以及Reducer的个数numPartions。
MapReduce提供两个Partitioner实现,HashPartitoner和TotalOrderPartitioner。HashPartitioner是默认实现,基于哈希值进行分片(曾在一篇文章中讲了一次Partition的开发和测试过程:http://brandnewuser.iteye.com/blog/2122852);TotalOrderPartitoner提供了一种基于区间分片的方法,通常用在数据的全排序中。例如归并排序,如果Map Task进行局部排序后Reducer端进行全局排序,那么Reducer端只能设置成1个,这会成为性能瓶颈,为了提高全局排序的性能和扩展性,并保证一个区间中的所有数据都大于前一个区间的数据,就会用到TotalOrderPartitioner。
本文主要参考《Hadoop技术内幕-MapReduce架构设计》(董西成著)一书。
相关推荐
Hadoop MapReduce 编程实战 ...通过了解 MapReduce 编程基础、MapReduce 项目实践、MapReduce 编程模型、Deduplication、MAC 地址统计和计数器的使用,我们可以更好地掌握 Hadoop MapReduce 的编程技术。
实验项目“MapReduce 编程”旨在让学生深入理解并熟练运用MapReduce编程模型,这是大数据处理领域中的核心技术之一。实验内容涵盖了从启动全分布模式的Hadoop集群到编写、运行和分析MapReduce应用程序的全过程。 ...
1. **掌握基本的MapReduce编程方法**:理解MapReduce的基本原理和编程流程,学会如何使用Java编写MapReduce程序。 2. **实现统计HDFS系统中多个文本文件中的单词出现频率**:通过实际操作,体验MapReduce在处理大...
本文针对上述问题,提出了一种新的离群数据挖掘方法,其核心思想是利用MapReduce编程模型,结合上下文信息来提高挖掘结果的可理解性和可解释性。 首先,文章提出的相关子空间法(Correlation Subspace Method)是一...
它简化了大数据处理的编程模型,使得开发者可以专注于业务逻辑,而不用关心底层的分布式细节。 【应用实例】 大数据技术在众多领域都有实际应用,例如: 1. **流感预测**:Google利用大数据分析用户的搜索行为,...
在大数据处理领域,MapReduce 是一种非常流行的编程模型,用于并行处理海量数据集。该模型由 Google 首次提出,并被广泛应用于搜索引擎、推荐系统等场景。MapReduce 的核心思想是将一个大任务分解成许多小任务来并行...
【MapReduce初级编程实践】是大数据处理中的一项基础任务,主要应用于大规模数据集的并行计算。在这个实验中,我们关注的是如何利用MapReduce来实现文件的合并与去重操作。MapReduce是一种分布式计算模型,由Google...
MapReduce 是一种编程模型,用于大规模数据集(大于 1TB)的并行计算。它的基本思想是将大任务分解为小任务(映射阶段),然后在多台机器上并行处理这些小任务,最后再将结果合并(化简阶段)。在这个案例中,我们...
在这个具体的案例中,我们关注的是如何利用MapReduce编程来分析新浪微博的数据,以实现更有效的广告和内容推荐。 首先,我们需要理解微博数据的结构。微博内容通常包含用户ID、时间戳、微博文本、可能的标签和其他...
为了解决这些问题,后来出现了如Spark、Flink等更现代的计算框架,它们在保持可扩展性和容错性的同时,提供了更高的计算性能和更灵活的编程模型。 总之,MapReduce是一种强大的工具,它改变了大数据处理的方式,让...
总结,通过Hadoop MapReduce实现MatrixMultiply是将大规模矩阵运算分布式化的过程,它利用了并行计算的能力处理大量数据,有效地解决了单机环境下无法处理的大规模矩阵乘法问题。理解并掌握这一技术对于在大数据背景...
1. MapReduce设计模式:涉及MapReduce编程模型的多种使用场景和应用,旨在为开发者提供各种数据处理问题的解决方案。 2. MapReduce和Hadoop:介绍了MapReduce的历史及其与Hadoop的关系。Hadoop是一个开源框架,支持...
它将复杂的分布式系统操作抽象成简单的编程模型,使开发人员能够专注于编写Map和Reduce函数,从而实现大规模数据处理。 MapReduce的核心思想是“分而治之”(Divide and Conquer)。在处理海量数据时,首先将数据分解...
Google MapReduce中文版详细描述了MapReduce编程模型的工作原理和实现细节,同时也介绍了一些实际案例和编程技巧。文档强调了MapReduce在运行时处理的几个关键方面:如何分割输入数据、在计算机集群上调度任务、处理...
### hadoop MapReduce编程教程知识点概述 #### 一、MapReduce基本概念 - **MapReduce**:这是一种分布式计算模型,由Google提出,并被Apache Hadoop所实现。它主要用于大规模数据集(多TB甚至PB级别)的并行处理,...
在本段落中,我们集中讨论了与MapReduce设计模式相关...这本书为读者提供了深入理解和应用MapReduce编程模型的知识框架,对于希望利用Hadoop和MapReduce模型进行数据处理的专业人士来说,它是一本不可或缺的参考资料。