Hadoop的C++扩展了解(2)

来源:互联网 发布:思迅天店 知乎 编辑:程序博客网 时间:2024/06/05 08:34
 

Hadoop是一个软件平台,是Apache开源组织的一个分布式计算开源框架,可以让你很容易地开发和运行处理海量数据的应用。Hadoop框架中最核心的设计就是:MapReduceHDFS,也可以说是Hadoop是基于分布式文件系统(HDFS)的MapReduce的实现。

 

分布式文件系统(HDFS

HDFS采用master/slave架构。一个HDFS集群是由一个Namenode和一定数目的Datanodes组成。Namenode是一个中心服务器,负责管理文件系统的名字空间(namespace)以及客户端对文件的访问。集群中的Datanode一般是一个节点一个,负责管理它所在节点上的存储。HDFS暴露了文件系统的名字空间,用户能够以文件的形式在上面存储数据。从内部看,一个文件其实被分成一个或多个数据块,这些块存储在一组Datanode上。Namenode执行文件系统的名字空间操作,比如打开、关闭、重命名文件或目录。它也负责确定数据块到具体Datanode节点的映射。Datanode负责处理文件系统客户端的读写请求。在Namenode的统一调度下进行数据块的创建、删除和复制。

 

MapReduce

MapReduce任务是用来处理键/值对的。该框架将转换每个输入的记录成一个键/值对,每对数据会被输入给Map作业。Map任务的输出是一套键/值对,原则上,输入是一个键/值对,但是,输出可以是多个键/值对。然后,它对Map输出键/值对分组和排序。然后,对排序的每个键值对调用一次Reduce方法,它的输出是一个键值和一套关联的数据值。Reduce方法可以输出任意数量的键/值对,这将被写入工作输出目录下的输出文件。如果Reduce输出键值保持和Reduce输入键值一致,最终的输出仍然保持排序。

 

该框架提供了两个处理过程来管理MapReduce作业:

TaskTracker在集群中的计算节点上管理和执行各个MapReduce作业。 

JobTracker接受作业提交,提供作业的监测和控制,管理任务,以及分配作业到TaskTracker节点上。

一般来说,每个集群有一个JobTracker进程,集群中的每个节点有一个或多个TaskTracker进程。JobTracker是一个关键模块,它出现问题会引起系统的瘫痪,如果一个TaskTracker出现问题,JobTracker会调度其他TaskTracker进程重试。

下面是一个用GoogleMapReduce的介绍的RapReduce原理:

了解MapReduce模型的人应该知道,Map函数的输出是一系列的Key/Value对(pair),这些Key/Value对是给Reduce函数使用的。但是在这里可以发现,Map函数的输入参数也是KeyValue。但其实,输入的Key/Value和输出的Key/Value不是同一组东西。对于一个Map函数调用,输入的是一个Key/Value对,而输出呢,是一组Key/Value对。举例来说,如果要统计一篇文章中所有单词的数目,那么输入的Key可能就是行数,输入的Value就是该行的内容。对于一次Map调用,就是要统计出一行中各个单词出现的次数,所以输出的Key是单词,Value是这个单词的出现次数。
Map
函数的输入之所以也用Key/Value的形式,可能是因为一般来说一个任务并不是用一次MapReduce就能够完成,而是需要用到多次MapReduce调用,下一个Map调用的输入很有可能就是上一个Reduce的输出结果(Key/Value对)。


系统流程



结合上面的图,这里描述了当一个用户程序执行MapReduce调用后,系统的流程:
1.
首先,用户程序中的MapReduceLibrary会将输入的文件(就是要处理的文件)切分成大小为16M——64M之间的M份(就是图中的split 0split 1...),一般来说,这M份数据是放在了cluster的多台机器上。然后在整个cluster的机器上启动程序的多份拷贝,如图所示(1)。

2. 其中的一份程序拷贝是master,其余的拷贝是workersmaster会将任务分配给workers。任务包括了Mmap的任务和R reduce的任务,master会找到空闲的worker然后将map或者reduce的任务分配给它。(M的值取决于input files被切分的块数;R值则是根据map中所能hash出的key的数量。)如图所示(2)。

3. 当一个worker被分配到map任务,那么它就会处理M份中的一份splitInputData中的数据也是Key/Value形式的很多 pairs(这个在前面中提到了),Map任务的worker会将这些pairs一个一个传递给Map函数,Map函数产生的很多新的Key/Value 对会被缓存在内存中。

4. 周期性的,buffer中缓存的那些pairs会写入到本地disk中。如图所示(3)(4)。由于有Rreduce任务,所以disk中的pair 会按照一定规则分为R个区,每个区的数据都特定的给某一个reduceWorker。在图中的每个Map Worker所对应的Intermediatefiles其实被分成了R个区(很有可能就是R个文件)。这些区的位置会被传递到master上,它会负责将这些位置交给reduce workers。可以看到,master在这里起到了一个承上启下的作用,Map函数和Reduce函数之间的连接是由master完成的。

5. Reduce Workermaster获取了这些区的位置,然后将这些Key/Value对从mapWorker处通过RPC读取。注意,Reduce Worker只读那些对应于自己的区的数据。如图所示(5)。读取完数据后需要对于这些Key/Value对按照Key进行排序,如果需要,可能还采取外排的方式(externalsort)。之所以需要排序是因为对于一个Key,会有很多组不同的pair,通过排序可以将它们聚合在一起。

6. reduceWorker迭代整个被排序后的Key/Value数据,将每个独一无二的key和它所对应的value序列(之所以是序列,是因为对于一个 key可能有很多个Key/Value,每个项中的value都不同,它们已经通过排序聚合在了一起)送入Reduce函数中。Reduce函数对于这样的输入产生的结果往往是0或者1个值(比如将所有Value相加,和就是最后的结果)。Reduce函数对于Reduce函数的结果会被添加到最终的 output file里(每次reduce Worker都会产生一个输出文件,最终一共有R个文件,因为一共有Rreduce的任务)。如图所示(6)。

7. 当所有的mapreduce任务结束后,master会唤醒用户的程序。这时候,用户的MapReduce调用返回。

还需要提及的是,当整个流程顺利完成以后,最终得到的其实是R个文件。如果想要最终的结果,应该将这R个文件合并。但一般来说,都是将这R个文件作为另一个MapReduce任务的输入。