MapReduce技术引入
大数据时代的数据分析任务比传统的数据分析任务要复杂,因为往往涉及的数据量巨大,比如要分析汇总某个大型零售商在全国的销售数据,查看某个搜索引擎的特定词条的访问日志… … 通常来讲,我们的笔记本电脑可以同时干很多事儿,比如听音乐,编辑Word文档,下载电影,这些都可以同时进行,为什么呢?因为这些程序任务处理的数据量规模小。而对于大规模的数据处理任务来说,就不是一台电脑同时做许多任务了,而是许多电脑同时做一件任务的逻辑关系。假如你写了一个程序,然后让你的电脑来跑一个比较大的数据量(例如把百度百科上所有的词条分析一遍…),那么你的电脑需要很长很长的时间来做这件事…大多数情况下,数据还没跑完,你的电脑就被累死了(死机…)。那么怎么办?就有人考虑到了用许多台电脑来同时完成这个任务。这就引入了并行计算的概念。
许多电脑同时做一件复杂的任务,涉及很多问题:比如,这个任务首先要分解成许多子任务,然后这些小任务要在这些电脑上面去分配,然后这些电脑完成了任务之后反馈的结果还要汇总,同时还要考虑如果这些电脑的故障异常等问题怎么去解决…MapReduce就是这样的一个编程模型,一个复杂的任务按照这个抽象的模型去实现,就可以有效进行并行计算。
MapReduce的定义
什么是MapReduce呢?引用官方的解释:
Hadoop MapReduce is a software framework for easily writing applications which process vast amounts of data (multi-terabyte data-sets) in-parallel on large clusters (thousands of nodes) of commodity hardware in a reliable, fault-tolerant manner.
这段话的大概意思就是说MapReduce是一个可以运行在分布式集群计算框架,可以并行处理大量的数据。MapReduce是一个编程模型,一个处理和生成超大数据集的算法模型的相关实现。简单的一句话解释MapReduce就是“任务的分解与结果的汇总”。mapreduce成功的最大因素是它简单的编程模型。程序员只要按照这个框架的要求,设计map和reduce函数,剩下的工作,如分布式存储、节点调度、负载均衡、节点通讯、容错处理和故障恢复都由mapreduce框架(比如hadoop)自动完成,设计的程序有很高的扩展性。
MapReduce的原理
Hadoop将输入数据划分成等长的小数据块,称为分片(split);一个合理的分片大小趋向于HDFS的一个block块的大小,默认是128M;在存有输入数据的节点上运行map任务可以获得最佳性能(即计算去找数据),这就是所谓的本地优化。
首先我们来看下面这一张图:
假设给定的输入文档内容包含如下四行
- Hello Java
- Hello C
- Hello Java
- Hello C++
第一步:split:将上述文档中每一行的内容转换为key-value对
0-Hello Java
1- Hello C
2- Hello Java
3-Hello C++
注意:上述中的0-1-2-3实际是每条记录的偏移量,这里为了方便用0-1-2-3表示
map task中map模块从inputSplit中拿到数据,进行map映射,映射就是讲拆分之后的内容转换成新的key-value对,即:
- (Hello,1)
- (Java,1)
- (Helllo,1)
- (Java,1)
- (Hello,1)
- (C,1)
- (Hello,1)
- (C++,1)
map过程还会对文件中的每一行记录打标签,打标签的目的就是为了让这一条记录将来被相应的reduce task处理,对应数据走到图中第5步。所谓打标签就是分区,分区是由HashPatitioner来做的,分区方法是首先求出每一行记录HashCode,然后将HashCode对reduce task数取模,根据取模结果进行分区,reduce task数是程序员自己设定的。
第二步:
将map中的数据写入缓冲区内存(buffer in memory),进入buffer之后的每一条记录都由三个部分组成:
1、分区号
2、key值
3、value值
这个缓冲区内存的大小是100M,同时这100M又分为80M和20M,当nap源源不断地往buffer中写入数据,一旦写入到80M时,就会将这80M内存封锁,然后对80M的数据进行combiner和排序,combiner就是将相同分区的数据放到一块,经过combiner和排序后分区内数据是有序的。那剩下的20M内存有什么用呢?就是当封锁主80M的内存就行分区排序的时候,map模块继续输出数据到buffer中的数据就会都存储在这20M里面。经过combiner后的数据:
- (Hello,1)
- (Hello,1)
- (Helllo,1)
- (Hello,1)
- (Java,1)
- (Java,1)
- (C,1)
- (C++,1)
第三步
排序完成之后就开始往磁盘中溢写数据,每进行一次溢写就产生一个磁盘小文件,这些小文件是有序且是分好区的。
第四步:merge on disk
上述merger on disk过程可以用下图表示:
这一步就是将磁盘中的小文件根据分区合成一个大文件,并根据key值排序,合成完毕之后就会进行第五步。
第五步
此时进入到reduce过程,reduce会根据分区拉取相应的数据到磁盘中。
第六步
将拉取到的数据读入buffer中,再次根据key进行排序,这个过程和第二步差不多,只不过不用再打标签分区了。
第七步
将所有的buffer中的数据写入reduce task的reduce模块中,并根据key值排序进行,然后分组。分组后数据:
- (Hello,1,1,1,1}
- {Java,1,1}
- {C,1}
- {C++,1}
第八步
Reduce(缩减)并将结果输出。Reduce后数据:
- (Hello,4)
- (Java,2)
- (C,1)
- (C++,1)
总结
上述过程中234步就是一个数据shuttle write过程,567步是shuttle read过程