英语原文共 13 页,剩余内容已隐藏,支付完成后下载完整资料
MapReduce: Simplified Data Processing on Large Clusters
MapReduce:面向大型集群的简化数据处理
摘要
MapReduce既是一种编程模型,也是一种与之关联的、用于处理和产生大数据集的实现。用户要特化一个map程序去处理key/value对,并产生中间key/value对的集合,以及一个reduce程序去合并有着相同key的所有中间key/value对。本文指出,许多实际的任务都可以用这种模型来表示。
用这种函数式风格写出的程序自动就拥有了在一个大的PC机集群上并行执行的能力。运行时系统会负责细节:切分输入数据,在一组机器上调度执行程序,处理机器错误,以及管理所需的机器间通信。这允许不具备任何并行和分布式系统经验的程序员也能轻松地利用一个大型分布式系统的资源。
我们的MapReduce实现运行在一个大型PC机集群上,且具有很好的扩展性:一个典型的MapReduce计算要在数千台机器上处理若干TB的数据。程序员可以很轻松的使用这一系统:目前已经实现的MapReduce程序数以百计,每天有上千个MapReduce作业运行在Google的集群上。
1 介绍
在过去的5年中,作者以及许多其他Google员工实现了数百个特定用途的计算过程,其中包括了处理大量的原始数据(抓取文档、网络请求日志等等),计算许多种类的衍生数据(倒排索引、网络文档图结构的多种表示、单台主机抓取页面数量的概要、指定日期频次最高的请求集合等等)。大多数这样的计算过程在概念上都很直接。但输入数据量通常都很大,因此计算过程需要分布到数百或数千台机器上进行,才能保证过程在一个合理时间内结束。而为了处理计算并行化、数据分发和错误处理等问题而引入大量复杂的代码则令原本简单的计算过程变的晦涩难懂。
作为对这种复杂性的回应,我们设计了一种新的抽象,允许我们表达出原本简单的计算过程,且将涉及并行、容错性、数据分发和负载均衡的凌乱细节隐藏在一个函数库中。我们的抽象受到了Lisp等函数式语言中的map和reduce原语的启发。我们意识到我们大多数的计算都包含了在每个输入的逻辑“记录”上应用map操作,从而计算出一组中间key/value对的集合,然后再向共享同一个key的所有中间value应用reduce操作,从而适当地合并衍生数据。我们对用户定义的map和reduce操作的使用允许我们轻松地将大型计算并行化,以及将再执行作为容错性的主要机制。
本项工作的主要贡献是一个简单但功能强大的接口,允许自动实现并行化和大范围的分布计算,和一个与此接口结合的实现,能在普通PC机集群上达到很高的性能。
第2部分描述了基本的编程模型并给出了几个例子。第3部分描述了针对我们基于集群的计算环境而裁剪的MapReduce接口的一个实现。第4部分描述了我们觉得非常有用的一些编程模型的技巧。第5部分针对多种不同的任务,对我们的实现进行了性能测量。第6部分探索了在Google中MapReduce的应用,包括了我们在将其作为生产索引系统的重写基础的经验。第7部分讨论了相关的和未来要做的工作。
2 编程模型
计算过程就是输入一组key/value对,再生成输出一组key/value对。MapReduce库的使用者用两个函数来表示这个过程:map和reduce。
map由使用者编写,使用一个输入key/value对,生成一组中间key/value对。MapReduce库将有着相同中间key I的中间value都组合在一起,再传给reduce函数。
reduce也由使用者编写,它接受一个中间key I和一组与I对应的value。它将这些value合并为一个可能更小的value集合。通常每个reduce调用只产生0或1个输出value。中间value是通过一个迭代器提供给reduce函数的。这允许我们操作那些因为大到找不到连续存放的内存而使用链表的value集合。
2.1 示例
考虑一个问题:统计一个很大的文档集合中每个单词出现的次数。使用者能写出与下面的伪代码相似的代码:
map(String key,String value):
// key: 文档名
// value: 文档内容
for each word w in value:
EmitIntermediate(w,'1');
reduce(Stringkey, Iterator values):
// key: 一个单词
// value: 计数值列表
int result = 0;
for each v in values:
result = ParseInt(v);
Emit(AsString(result));
map函数将每个单词与出现次数一同输出(本例中简单的输出“1”)。reduce函数将针对某个特定词输出的次数都合并相加。
另外,使用者要写代码填充一个符合MapReduce规格的对象,内容包括输入和输出文件的名字,以及可选的调节参数。之后使用者调用MapReduce函数,将指定的对象传进去。用户代码会与MapReduce库(C 实现)链接到一起。附录A包括了这个例子的全部程序文本。
2.2 类型
尽管前面的伪代码写成了用字符串进行输入输出,但从概念上讲用户提供的map和reduce函数是关联着类型的:
map |
(k1, v1) |
→ list(k2, v2) |
reduce |
(k2, list(v2)) |
→ list(v2) |
也就是说,输入的key和value与输出的key和value的域不同。进一步说,中间的key和value与输出的key和value的域相同。
我们的C 实现使用字符串与用户定义的函数交互,而将字符串与相应类型的转换留给用户代码完成。
2.3 更多例子
这里例举了一些有趣的程序,它们都可以很轻松的用MapReduce模型表达。
分布式Grep:map函数在匹配到给定的pattern时输出一行。reduce函数只是将给定的中间数据复制到输出上。
URL访问频次统计:map函数处理网页请求的日志,对每个URL输出〈URL, 1〉。reduce函数将相同URL的所有值相加并输出〈URL, 总次数〉对。
倒转Web链接图:map函数在source页面中针对每个指向target的链接都输出一个〈target, source〉对。reduce函数将与某个给定的target相关联的所有source链接合并为一个列表,并输出〈target, list(source)〉对。
每个主机的关键词向量:关键词向量是对出现在一个文档或一组文档中的最重要的单词的概要,其形式为〈单词, 频率〉对。map函数针对每个输入文档(其主机名可从文档URL中提取到)输出一个〈主机名, 关键词向量〉对。给定主机的所有文档的关键词向量都被传递给reduce函数。reduce函数将这些关键词向量相加,去掉其中频率最低的关键词,然后输出最终的〈主机名, 关键词向量〉对。
倒排索引:map函数解析每个文档,并输出一系列〈单词, 文档ID〉对。reduce函数接受给定单词的所有中间对,将它们按文档ID排序,再输出〈单词, list(文档ID)〉对。所有输出对的集合组成了一个简单的倒排索引。用户可以很轻松的扩展这个过程来跟踪单词的位置。
分布式排序:map函数从每条记录中提取出key,并输出〈key, 记录〉对。reduce函数不改变这些中间对,直接输出。这个过程依赖于4.1节介绍的划分机制和4.2节介绍的排序性质。
3 实现
许多不同的MapReduce的实现都是可行的。选择哪一个要取决于环境。例如,一种实现可能适合于小型的共享内存机器,一种实现可能适合于大型的NUMA多处理器机器,而另一种则适合于更大型的联网机器集。
本部分描述的实现主要面向Google内部广泛使用的计算环境:大型的商用PC机集群,互相之间用交换式以太网连接。我们的环境是:
- 主要使用的机器为双核X86处理器,运行Linux系统,每台机器的内存从2GB到4GB不等。
- 使用的都是商用网络硬件设备——在机器层面上通常从100Mbps到1Gbps不等,但平均起来要比总带宽的一半少很多。
- 集群中拥有数百或数千台机器,因此机器错误经常出现。
- 每台机器都使用廉价的IDE硬盘来提供存储功能。我们使用一种内部开发的分布式文件系统来管理这些磁盘上的数据。这个文件系统通过复制的方法在不可靠的硬件之上提供了实用性与可靠性。
- 用户向一个调度系统提交作业。每个作业包括了一个任务集,会由调度器调度到集群内可用的一组机器上。
3.1 执行过程概述
通过自动将输入数据切分为M块,map调用分布在多台机器上进行。输入划分可以在不同的机器上并行执行。reduce调用是通过一个划分函数(例如hash(key) mod R)将中间key空间划分为R块来分布运行。划分的块数R和划分函数都由用户指定。
图1展示了我们的实现中MapReduce操作的整体流程。当用户程序调用MapReduce函数时,会发生下面一系列动作(图1中的标号与下面列表顺序相同):
- 用户程序中的MapReduce库首先将输入文件切分为M块,每块的大小从16MB到64MB(用户可通过一个可选参数控制此大小)。然后MapReduce库会在一个集群的若干台机器上启动程序的多个副本。
- 程序的各个副本中有一个是特殊的——主节点,其它的则是工作节点。主节点将M个map任务和R个reduce任务分配给空闲的工作节点,每个节点一项任务。
- 被分配map任务的工作节点读取对应的输入区块内容。它从输入数据中解析出key/value对,然后将每个对传递给用户定义的map函数。由map函数产生的中间key/value对都缓存在内存中。
- 缓存的数据对会被周期性的由划分函数分成R块,并写入本地磁盘中。这些缓存对在本地磁盘中的位置会被传回给主节点,主节点负责将这些位置再传给reduce工作节点。
- 当一个reduce工作节点得到了主节点的这些位置通知后,它使用RPC调用去读map工作节点的本地磁盘中的缓存数据。当reduce工作节点读取完了所有的中间数据,它会将这些数据按中间key排序,这样相同key的数据就被排列在一起了。同一个reduce任务经常会分到有着不同key的数据,因此这个排序很有必要。如果中间数据数量过多,不能全部载入内存,则会使用外部排序。
- reduce工作节点遍历排序好的中间数据,并将遇到的每个中间key和与它关联的一组中间value传递给用户的reduce函数。reduce函数的输出会写到由reduce划分过程划分出来的最终输出文件的末尾。
- 当所有的map和reduce任务都完成后,主节点唤醒用户程序。此时,用户程序中的MapReduce调用返回到用户代码中。
成功完成后,MapReduce执行的输出都在R个输出文件中(每个reduce任务产生一个,文件名由用户指定)。通常用户不需要合并这R个输出文件——他们经常会把这些文件当作另一个MapReduce调用的输入,或是用于另一个可以处理分成多个文件输入的分布式应用。
3.2 主节点数据结构
主节点维持多种数据结构。它会存储每个map和reduce任务的状态(空闲、处理中、完成),和每台工作机器的ID(对应非空闲的任务)。
主节点是将map任务产生的中间文件的位置传递给reduce任务的通道。因此,主节点要存储每个已完成的map任务产生的R个中间文件的位置和大小。位置和大小信息的更新情况会在map任务完成时接收到。这些信息会被逐步发送到正在处理中的reduce任务节点处。
3.3 容错性
既然MapReduce库是为了帮助使用成百上千台机器处理数量非常大的数据的,它就必须能够优雅地承受机器错误。
工作节点错误
主节点周期性的ping每个工作节点。如果工作
全文共15658字,剩余内容已隐藏,支付完成后下载完整资料
资料编号:[10640],资料为PDF文档或Word文档,PDF文档可免费转换为Word
以上是毕业论文外文翻译,课题毕业论文、任务书、文献综述、开题报告、程序设计、图纸设计等资料可联系客服协助查找。