转载自董的博客
1、 概述
传统的MapReduce框架(见博文:传统MapReduce框架)把一个作业的执行过程分为两个阶段:map和reduce,在map阶段,每个map task读取一个block,并调用map()函数进行处理,然后将结果写到本地磁盘(注意,不是HDFS)上;在reduce阶段,每个reduce task远程的从map task所在节点上读取数据,调用reduce()函数进行数据处理,并将最终结果写到HDFS。从以上过程可以看出,map阶段和reduce阶段的结果均要写磁盘,这虽然会降低系统性能,但可以提高可靠性。正是由于这个原因,传统的MapReduce不能显式地支持迭代编程,如果用户硬要在传统MapReduce上运行迭代式作业,性能将非常低。为此,不少改进型的MapReduce出现了,它们能很好地支持迭代式开发。本文组织结构如下:下一节将介绍几个常见的迭代式作业并分析它们的特点;第3节介绍迭代式MapReduce框架需要解决的几个难题;第4节介绍现在比较有名的迭代式MapReduce框架;第5节介绍迭代式MapReduce框架仍未解决的问题;最后一节给出了一些迭代式MapReduce框架的资料。
2、 迭代式作业
在数据挖掘,信息检索等领域,有很多算法需要多次迭代,本节介绍两个常见的作业,一个是PageRank,另一个是SSSP(Single Source Shortest Path)。PageRank是一个非常有名的网页重要性衡量因素,它是一个多次迭代的过程,如下图所示,每次迭代,PageRank由两个作业MR1和MR2完成,这样迭代多次,直到相邻的两次迭代中PR之差小于某一个阈值。
单源最短路径问题实际上也是多次迭代的过程,主要思想是:设G=(V,E)是一个带权有向图,R是G的邻接矩阵。整个算法始终把图中顶点集合V分成两组,第一组为已求出最短路径的顶点集合(用S表示,初始时S中只有一个源点,在每次迭代中求得一条最短路径 , 并将该路径的另一顶点加入到集合S中,直到全部顶点都加入到S中,算法就结束了),第二组为其余未确定最短路径的顶点集合(用U表示)。在每次迭代中,从U中选择一个当前路径最短的顶点,转存到S中,直到U为空。
更多迭代式作业以及在Hadoop上的实现方法,请参见Apache开源项目Mahout 以及它的论坛。
3、 技术难点
从PageRank和SSSP的整个计算过程可以看出:
(1) 输入数据由动态数据和静态数据两部分组成。对于PageRank, L属于静态数据,而R属于动态数据;对于SSSP,R属于静态数据,S和U属于动态数据。传输动态数据是不可避免的,而静态数据可以采用某种策略避免重复传输。怎样避免传输静态数据?
(2) 每次迭代,如果所有task重复重新创建,代价将非常高。怎样重用task以提高效率(task pool)?
(3) 每次迭代,数据怎么样存储?如果总是写磁盘,代价将非常高。
(4) 何时迭代终止,怎样改变编程模型,允许用户指定合适终止迭代.
4、 迭代式MapReduce框架
现在出现了不少迭代式MapReduce框架,比较有名的是Twister和Haloop(Ha,loop)。下面分别给予介绍。
Twister是由一个印度人开发的,其架构如下:
在Twister中,大文件不会自动被切割成一个一个block,因而用户需提前把文件分成一个一个小文件,以供每个task处理。在map阶段,经过map()处理完的结果被放在分布式内存中,然后通过一个broker network(NaradaBroking系统)将数据push给各个reduce task(Twister假设内存足够大,中间数据可以全部放在内存中);在reduce阶段,所有reduce task产生的结果通过一个combine操作进行归并,此时,用户可以进行条件判定, 确定迭代是否结束。combine后的数据直接被送给map task,开始新一轮的迭代。为了提高容错性,Twister每隔一段时间会将map task和reduce task产生的结果写到磁盘上,这样,一旦某个task失败,它可以从最近的备份中获取输入,重新计算。
为了避免每次迭代重新创建task,Twister维护了一个task pool,每次需要task时直接从pool中取。在Twister中,所有消息和数据都是通过broker network传递的,该broker network是一个独立的模块,目前支持NaradaBroking和ActiveMQ。
总体上说,Twister还是一个研究性项目,它的一些设计策略决定了它不太可能在实际中应用,如数据全部放在分布式内存中;没有分布式文件系统,只提供了一个tool进行文件存取和访问;计算模型抽象程度不够,支持的应用类型不够多。
Haloop是在Hadoop基础上扩展而来的,其架构如下:
Haloop进行的改进有:
(1) 提供了一套新的编程接口,以方便用户进行迭代式程序开发。
(2) master node(jobtracker)包含一个循环控制模块,它不断的启动map-reduce计算直到满足迭代终止条件。
(3) 设计了新的Task scheduler,以便更好的利用data locality特性。
(4) 数据在各个task tracker会被缓存(cache)和建索引(index)。
下面介绍技术创新点:
(1) HaLoop 将所有迭代式任务抽象为:,其中R0是初始输入,L是每次迭代不变的数据,Ri是第i次迭代产生的结果。主要编程接口是:
SetFixedPointThreshold:设置两次迭代的终止条件,即距离差是否达到某一个阈值
setMaxNumOfIterations:设置迭代次数
setIterationInput:设置变化的输入数据
AddInvariantTable:设置不变的输入数据
(2) Loop-aware 任务调度。Haloop在第一次迭代时会将不变的输入数据保存到该计算节点上,以后每次调度task,尽量放在固定的那些节点上(locality)。这样,每次迭代,不变的数据就不必重复传输了。
(3) Cache和Index。Map task的输入与输出,Reduce task的输出都会被建索引和缓存,以加快数据处理速度。其中,缓存是指数据被写到本次磁盘,以供下一轮循环迭代时直接使用。
总体上说,Haloop比Twister抽象度更高,支持更多的计算,同时,由于是在Hadoop基础上修改上,因而继承了Hadoop的很多优点。
5、 总结
目前在迭代式MapReduce研究方面,还处于发展阶段。Twister和Haloop的模型抽象度不够高,支持的计算有限。
6、 参考资料
(1) Twister主页:http://www.iterativemapreduce.org/
(2) Twister论文:Twister: A Runtime for Iterative MapReduce
(http://www.iterativemapreduce.org/hpdc-camera-ready-submission.pdf)
(3) Haloop主页:http://code.google.com/p/haloop/
(4) Haloop论文:HaLoop: Efficient Iterative Data Processing on Large Clusters(http://www.ics.uci.edu/~yingyib/papers/HaLoop_camera_ready.pdf)