《MapReduce: Simplified Data Processing on Large Cluster 》翻译

Abstract程序员

MapReduce是一种编程模型和一种用来处理和产生大数据集的相关实现。用户定义map函数来处理key/value键值对来产生一系列的中间的key/value键值对。还要定义一个reduce函数用来合并有着相同中间key值的中间value。许多现实世界中的任务均可以用这种模型来表达,就像下文所展现的那样。web

用这个风格编写的程序能够自动并行地在集群上工做。运行时系统会自动处理例如切割输入数据,在机器之间调度程序的执行,处理机器故障以及管理必要的机器间通讯等细节问题。这可让那些对于并行分布式系统没有任何经验的程序员也能很简单地利用起一个大的分布式系统的资源。算法

咱们的MapReduce的实现运行在一个由大的商业机构成的集群当中而且是高度可扩展的:一个典型的MapReduce计算要在上千台机器中处理TB数量级的数据。程序员会以为这个系统很是好用:已经有成千上万的MapReduce程序被实现出来而且天天有上千个MapReduce任务运行在Google的集群上。数据库

1 Introduction编程

在过去五年中,做者和许多Google的其余人已经实现了成百上千个用于特殊目的的计算程序用于处理大量的raw data,各类各样的derived data。许多这种计算程序在概念上都是很是直接的。然而输入的数据量每每很大,而且计算须要分布在成百上千台机器中为了在一个可接受的时间内完成任务。可是除了简单的计算模型之外,咱们须要大量复杂的代码用来处理例如如何并行化计算、分发数据、处理故障等等问题。api

为了解决这样的复杂性,咱们设计了一种新的抽象,它让咱们只须要表示出咱们想要执行的计算模型,而将背后复杂的并行化,容错,数据分发,负载平衡等等技术的实现细节隐藏在了库中。咱们这种新的抽象是受Lisp以及其余一些函数式编程语言中的map和reduce原语影响而来的。咱们意识到许多的计算都须要对于输入中的每一个逻辑“记录”进行map操做,为了计算一系列的中间键值对。而后还须要对全部共享同一个key的value进行reduce操做,从而可以对派生的数据进行适当的组合。咱们这种让用户自定义map和reduce操做的编程模型可以让咱们简单地对大量数据实现并行化,而且使用从新执行做为主要的容错机制。缓存

咱们这项工做的主要共享是提供了一个简单而且强大的接口可以让咱们实现自动的并行化而且分布处理大规模的计算,同时该接口的实现能在大型的商用PC集群上得到很是高的性能。网络

Section 2描述了基本的编程模型以及一些简单的例子。Section 3描述了为咱们的基于集群的计算环境量身定作的MapReduce接口。Section 4描述了一些咱们认为有用的对于编程模型的改进。Section 5是对咱们的实如今不一样任务下的性能测试。Section 6 包含了MapReduce在Google内的使用状况,包括咱们以它为基础重写咱们的产品索引系统的经验。Section 7讨论了相关的工做以及将来的发展。数据结构

2 Programming Model负载均衡

计算模型以一系列的键值对做为输入并产生一系列的键值对做为输出。MapReduce库的用户以“Map”和"Reduce"两个函数来表达计算。

Map,是由用户编写的,获取一个输入对,而且产生一系列中间的键值对。MapReduce库将那些具备相同的中间键I的中间值汇集在一块儿,而后将它们传递给Reduce函数。

Reduce函数一样是由用户编写的,接收一个中间键I和该键对应的一系列的中间值。Reduce函数经过将这些值合并来组成一个更小的值的集合。一般每一个Reduce函数只产生0个或1个输出值。Reduce函数通常经过一个迭代器来获取中间值,从而在中间值的数目远远大于内存容量时,咱们也可以处理。

 2.1 Example

下面来考虑这样一个问题:统计大量文档中每个单词出现的次数。对此,用户须要编写相似于以下的伪代码:

  map(String key, String value):

    // key: document name

    // value: document contents

    for each word w in value:

      EmitIntermediate(w, "1");

  reduce(String key, Iterator values):

    // key: a word

    // values: a list of counts

    int result = 0;

    for each v in values:

      result += ParseInt(v);

    Emit(AsString(result));

Map函数为在每个单词出现的时候,为它加上一个计数(在这个简单的例子中就是加1)。Reduce函数对每一个单词的全部计数进行叠加。

另外,用户须要用输入输出文件的名字,以及一个可选的tuning parameter去填充一个叫mapreduce specification 的对象。以后,用户调用MapReduce函数,将定义的上述对象传递进去。用户的代码将和MapReduce库相连(由C++实现)。Appendix A中有这个例子全部的代码文档。

2.2 Types

虽然在上述的伪代码中输入输出都是字符串类型的,但事实上,用户提供的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 More Example

接下来是一些可以简单地用MapReduce计算模型进行表达的例子

Distributed Grep:Map函数获取匹配提供的模式的行,Reduce函数只是简单地将这些中间数据拷贝到输出

Count of URL Access Frequency:Map函数处理web请求的日志,而且输出<URL, 1>。Reduce函数将拥有相同URL的value相加,获得<URL, total count>对

Reverse Web-Link Graph:Map函数输出<target, source>对,其中source所在的page都有连向target这个URL的连接。Reduce函数将给定target的全部的source URL链接起来,输出<target, list(source)>对

Term-Vector per Host:一个term vector表示一系列<word, frequency>的键值对,word表示一篇或者一系列文章中出现的比较重要的单词,frequency表示它们出现的次数。Map函数对于每篇输入的文章输出<hostname, term vector>键值对(其中hostname是从文章所在的URL中抽取出来的)Reduce函数获取给定host的term vectors。它将这些term vectors累加起来,丢弃非频繁出现的term,并产生一个最终的<hostname, term vector>对。

Inverted Index:Map函数对每篇文章进行处理,并输出一系列的<word, document ID>对。Reduce函数接收给定word的全部键值对,对相应的document ID进行排序而且输出<word, list<document ID>>对。全部输出对的集合构成了一个简单的倒排索引。用了MapReduce模型,对单词位置的追踪就变得很是简单了。

Distributed Sort:Map函数从每一个record中抽取出key,产生<key, record>键值对。Reduce函数只是简单地将全部对输出。这个计算模型依赖于Section 4.1中描述的划分技巧以及Section 4.2中描述的排序特性。

3 Implementation

对于MapReduce的接口,各类各样不一样的实现都是可能的。全部正确的实现都是基于应用环境的。好比,一种实现可能适合于小的共享内存的机器,另外一种可能适合于大型的NUMA多处理器机器,甚至有的是为更大的互联的机器集群设计的。

本节中描述的实现基于的是Google中最经常使用的计算环境:一个由大量商用PC机经过交换以太网互联的集群。在咱们的环境中:

(1)、机器一般都是x86的双核处理器,其上运行Linux,每台机器拥有2-4G的内存

(2)、商用网络硬件---一般是100 M/s或者1 G/s,可是综合起来要小于平均带宽

(3)、一个集群由成千上万台机器组成,所以机器故障是常有的事

(4)、存储由便宜的IDE磁盘提供,它们都与独立的机器直接相连。一个内部研发的文件系统用于管理全部存储于这些硬盘上的文件。该文件系统经过Replication在不可靠的硬件上提供了可用性和可靠性

(5)、用户提交jobs给调度系统。每一个job由一系列的task组成,而且由调度器分配到集群中一系列可用的机器上

3.1 Execution Overview

经过将输入数据自动分割成M份,Map函数得以在多台机器上分布式执行。每个输入块都能并行地在不一样的机器上执行。经过划分函数(例如,hash(key) mod R)将中间键划分为R份,Reduce函数也能被分布式地调用。其中划分的数目R和划分函数都是由用户指定的。

上图1展现了在咱们的实现中MapReduce所有的流程。当用户程序调用MapReduce函数时,接下来的动做将按序发生(图1中标记的数字与下面的数字是一一对应的):

(1)、用户程序中的MapReduce库首先将输入文件划分为M片,每片大小通常在16M到64M之间(由用户经过一个可选的参数指定)。以后,它在集群的不少台机器上都启动了相同的程序拷贝。

(2)其中有一个拷贝程序是特别的----master。剩下的都是worker,它们接收master分配的任务。其中有M个Map任务和R个Reduce任务要分配。master挑选一个空闲的worker而且给它分配一个map任务或者reduce任务。

(3)、被分配到Map任务的worker会去读取相应的输入块的内容。它从输入文件中解析出键值对而且将每一个键值对传送给用户定义的Map函数。而由Map函数产生的中间键值对缓存在内存中。

(4)、被缓存的键值对会阶段性地写回本地磁盘,而且被划分函数分割成R份。这些缓存对在磁盘上的位置会被回传给master,master再负责将这些位置转发给Reduce worker。

(5)、当Reduce worker从master那里接收到这些位置信息时,它会使用远程过程调用从Map worker的本地磁盘中获取缓存的数据。当Reduce worker读入所有的中间数据以后,它会根据中间键对它们进行排序,这样全部具备相同键的键值对就都汇集在一块儿了。排序是必须的,由于会有许多不一样的键被映射到同一个reduce task中。若是中间数据的数量太大,以致于不可以装入内存的话,还须要另外的排序。

(6)、Reduce worker遍历已经排完序的中间数据。每当遇到一个新的中间键,它会将key和相应的中间值传递给用户定义的Reduce函数。Reduce函数的输出会被添加到这个Reduce部分的输出文件中。

(7)、当全部的Map tasks和Reduce tasks都已经完成的时候,master将唤醒用户程序。到此为止,用户代码中的MapReduce调用返回。

当成功执行完以后,MapReduce的执行结果被存放在R个输出文件中(每一个Reduce task对应一个,文件名由用户指定)。一般用户并不须要将R个输出文件归并成一个。由于它们一般将这些文件做为另外一个MapReduce调用的输入,或者将它们用于另一个可以以多个文件做为输入的分布式应用。

3.2 Master Data Structures

 在master中保存了许多的数据结构。对于每一个Map task和Reduce task,master都保存了它们的状态(idle,in-progress或者是completed)以及worker所在机器的标识(对于非idle状态的tasks而言)。

master至关因而一个管道,经过它Map task所产生的中间文件被传递给了Reduce task。所以,对于每个已经完成的Map task,master会存储由它产生的R个中间文件的位置和大小。当Map task完成的时候,master就会收到位置和大小的更新信息。而这些信息接下来就会逐渐被推送处处于in-progress状态的Reduce task中。

3.3 Fault Tolerance

由于MapReduce库的设计初衷是用成千上万的机器去处理大量的数据,因此它就必须能用优雅的方式对机器故障进行处理。

Worker Failure

master会周期性地ping每个worker。若是通过了一个特定的时间还未从某一个worker上得到响应,那么master会将worker标记为failed。全部由该worker完成的Map task都被回退为idle状态,所以可以被从新调度到其余的worker上。一样的,全部failed worker正在执行的Map task或者Reduce task也会被回退为idle状态,而且被从新调度。

发生故障的机器上已经完成的Map task须要从新执行的缘由是,它们的输入是保存在本地磁盘的,所以发生故障以后就不能获取了。而已经完成的Reduce task并不须要被从新执行,由于它们的输出是存放在全局的文件系统中的。

当一个Map task开始由worker A执行,后来又由worker B执行(由于A故障了)。全部执行Reduce task的worker都会收到这个从新执行的通知。那些还未从worker A中读取数据的Reduce task将会从worker B中读取数据。

MapReduce对于大面积的机器故障是很是具备弹性的。例如,在一次MapReduce操做中,网络维护形成了集群中八十台机器在几分钟的时间内处于不可达的状态。MapReduce的master只是简单地将不可达的worker机器上的工做从新执行了一遍,接着再继续往下执行,最终完成了MapReduce的操做。

Master Failure

对于master,咱们能够简单地对上文所述的master数据结构作周期性的快照。若是一个master task死了,咱们能够很快地根据最新的快照来从新启动一个master task。可是,由于咱们只有一个master,所以故障的几率比较低。因此,在咱们的实现中若是master出现了故障就只是简单地中止MapReduce操做。用户能够检测到这种状况,而且若是他们须要的话能够从新开始一次MapReduce操做。

Semantics in the Presence of Failures

若是用户提供的Map和Reduce操做是关于输入值的肯定性函数,那么咱们分布式的实现将会产生一样的输出,在整个程序通过没有出现故障的顺序执行以后。

 咱们依赖Map task和Reduce task原子性地提交输出来实现上述特性。每个正在执行的task都会将它的输出写到一个私有的临时文件中。一个Reduce task产生一个这样的文件,而一个Map task产生R个这样的文件(每一个Reduce work一个)。当一个Map task完成的时候,worker就会给master发送一个信息,,其中包含了R个临时文件的名字。若是master收到了一个来自于已经完成了的Map task的完成信息,那么它就将它自动忽略。不然,将R个文件的名称记录到一个master数据结构中。

当一个Reduce task完成的时候,Reduce worker会自动将临时输出文件命名为最终输出文件。若是同一个Reduce task在多台机器上运行,那么多个重命名操做产生的最终输出文件名将会产生冲突。对此,咱们依赖底层文件系统提供的原子重命名操做来保证最终文件系统中的数据来自一个Reduce task。

大多数的Map和Reduce操做都是肯定性的,事实上,咱们的语义等同于顺序执行。所以这让程序员很是容易地可以解释他们程序的行为。当Map和Reduce操做是非肯定性的时候,咱们提供较弱,但仍然合理的语义。在非肯定性的操做中,对于一个特定的Reduce task R1的输出是和非肯定性程序顺序执行产生R1产生的输出是相同的。然而,对于另外一个Reduce task R2,它的输出对应于非肯定性程序另外一个顺序执行的结果。

下面考虑Map task M和Reduce task R1和R2。让e(Ri)表示Ri的执行结果。更弱的语义意味着,e(R1)可能从M的一次执行结果中读取输入,而e(R2)可能从M的另外一次执行中读取输入。

3.4 Locality

网络带宽在咱们的计算环境中是相对稀缺的资源。咱们经过将输入数据存储在集群中每台机器的本地磁盘的方法来节省带宽。GFS将输入文件切分红64MB大小的块,而且将每一个块的多份拷贝(一般为3份)存储在不一样的机器上。MapReduce的master获取全部输入文件的位置信息,而后将Map task调度到有相应输入文件副本的机器上。当发生故障时,再将Map task调度到邻近的具备该task输入文件副本的机器(即在同一台交换机内具备相同数据的机器)。当在一个集群的大量机器上作MapReduce操做时,大多数的输入数据都是从本地读取的,而不用消耗带宽。

3.5 Task Granularity

如上所述,咱们将Map操做分红M份,Reduce操做分红R份。在理想的状况下,M和R的值应该要比集群中worker machine的数量多得多。让一个worker同时进行许多不一样的task有利于提升动态的负载均衡,同时在一个worker故障的时候能尽快恢复。许多已经完成的Map task也能尽快地传播到其余全部的worker machine上。

在咱们的实现中,M和R的大小是有一个实用范围的。由于咱们的master须要作O(M+R)个调度决定,而且还要在内存中保存O(M*R)个状态。(可是内存使用的常数仍是比较小的,O(M*R)个Map task/Reduce task 状态对,每一个的大小大概在一个字节)

另外,R一般受限于用户,由于每一个Reduce task的输出都分散在不一样的输出文件中。事实上,咱们会选择M,所以每一个输入文件大概16MB到64MB的输入文件(所以上文所述的局部性优化会达到最优)。而咱们会让R成为worker machine数量的一个较小的倍数。所以,咱们一般在进行MapReduce操做时,将M设为200000,R设为5000,使用2000个worker machine。

3.6 Backup Tasks

“straggler”(落伍的士兵)的存在是拖慢整个MapReduce操做的一般的缘由之一。所谓的"straggler"是指一台机器用了过长的时间去完成整个计算任务中最后几个Map或者Reduce task。Straggler出现的缘由有不少。好比一台机器上硬盘坏了,它就会经历大量的可纠正错误,从而让它的性能从30MB/s降低到1MB/s。集群的调度系统可能将其余task调度到该机器上,致使它执行MapReduce代码的速度变慢不少,由于CPU,内存,本地磁盘,网络带宽的竞争加重。咱们最近遇到的一个问题是一台机器的初始化代码有点问题,它会致使处理器的缓存被禁用,在这些受影响的机器上进行的计算速度会降低到原来的百分之一。

对此,咱们有一个通用的机制用来缓解straggler的问题。当MapReduce操做接近结束的时候,master会将那些还在执行的task的备份进行调度执行。不管是原来的仍是备份执行完成,该task都被标记为已完成。咱们经过调整将该操做致使的计算资源消耗仅仅提升了几个百分点。可是在完成大型的MapReduce操做时,却让整个执行时间降低了好多。例如,Section 5.3中所描述的排序算法在备份机制关闭的状况下,须要多消耗44%的时间。

4 Refinement

虽然对于大多数需求由Map和Reduce函数提供的功能已经足够了,可是咱们仍是发现了一些有用的扩展。对它们的描述以下。

4.1 Partitioning Function

MapReduce用户决定他们的Reduce task或者输出文件的数目R。经过一个划分函数,根据中间键值将各个task的数据进行划分。默认的划分函数是经过哈希(好比,hash(key) mod R)。这一般会产生很是好的较为均衡的划分。可是在其余一些状况下,经过键值的其余函数来划分要更好一些。例如,有的时候输出键值是一些URL,咱们但愿同一个host的内容能放在同一个输出文件中。为了支持这种状况,MapReduce库的用户能够提供一个特殊的划分函数。例如,使用“hash(Hostname(urlKey)) mod R”做为划分函数,从而让全部来自于同一个host的URL的内容都输出到同一个输出文件。

4.2 Ordering Guarantees

咱们确保在一个给定的划分中,中间的键值对都按照键值的升序进行处理。这样的处理顺序确保了每个划分产生一个排好序的输出文件。这样的话,若是输出文件格式须要支持根据key进行有效的随机查找会比较方便。同时,输出的用户也会以为已经排好序的数据使用起来特别方便。

4.3 Combiner Function

在有些状况下,每一个Map task都会产生大量的中间键的重复而用户指定的Reduce函数是交互和关联的。Section 2.1中的单词统计就是一个很好的例子。由于单词的出现频率服从于Zipf分布,每一个Map Task都会产生成百上千个<the, 1>这样的记录。全部这些记录都会经过网络被送到一个Reduce task中,而且由Reduce函数加在一块儿去产生一个数。咱们容许用户使用了可选的Cominer函数,用于在网络传输以前部分地进行归并操做。

Combiner函数在每一个执行Map task的机器上执行。一般Combiner和Reduce函数使用的是相同的代码。Reduce函数和Combiner函数惟一的不一样是MapReduce库如何处理函数的输出。Reduce函数的输出写到最终的输出文件中。而Combiner函数的输出会被写到一个最终将被送给Reduce task的中间文件中。

部分的合并操做能极大地加速某类特定的MapReduce操做。Appendix A包含了一个使用Combiner的例子。

4.4 Input and Output Types

MapReduce库提供了对读入数据文件多种的格式支持。例如,"text"格式的输入将每一行做为键值对:key是文件内的偏移,value是该行的内容。另一种比较经常使用的格式存储一系列按照键进行排序的键值对。每个输出格式的实现都知道如何将本身进行合理的划分从而能让不一样的Map task进行处理(例如,text模式就知道将区域划分到以行为边界)。用户能够经过简单地定义一个reader接口来提供一个新的输入类型的实现。事实上,大多数用户只使用了预约义输入类型的很小一部分。

reader并不必定要从文件中读取数据。例如,咱们能够很容易地定义一个从数据库,或者内存中映射的数据结构中读取记录的reader。

同理,咱们也支持产生不一样格式的输出数据,用户也能编写新的输出数据格式。

4.5 Side-effects

在有些状况下,MapReduce的用户会很容易发现Map或者Reduce操做会产生一些辅助文件做为额外的输出文件。咱们依赖应用的编写者去保证这些反作用是原子和幂等的。通常来讲,应用会写到一个临时文件中,而且在它彻底产生以后,经过一个原子操做将它重命名。

对于一个单一的task产生的多个输出文件,咱们不提供原子性的两相提交支持。所以,产生多个输出文件而且有跨文件一致性要求的task须要是肯定性的。可是这样的限制在实践过程当中并非什么问题。

4.5 Skipping Bad Records

有时候,若是用户的代码中有bug的话,会致使Map或者Reduce操做在某些记录上崩溃。这些bug会致使MapReduce操做的正常完成。对于这种状况,一般就是去修bug。不过有时候这是不可行的,也许bug是第三方库形成的,而咱们并不能获得它的源代码。并且,有时候咱们容许忽略掉一些记录,例如在对一个大数据集作分析的时候。所以咱们提供了一种可选的执行模式,当MapReduce库检测到一些记录会形成崩溃时,就会主动跳过它们,从而保证正常地运行。

每个worker进程都安装了一个signal handler用于捕捉段错误和bug。在调用用户的Map和Reduce操做以前,MapReduce库会将参数的序号保存在一个全局变量中。若是用户代码产生了一个信号,signal handler就会传输一个参数含有序号的"last gasp"UDP包给MapReduce的master。当master在一个特定的记录中发现了不知一次的错误,这表示在下一次执行相应的Map或者Reduce操做的时候一个将它跳过。

4.7 Local Execution

Map或者Reduce函数的调试问题是很是tricky的。由于实际的计算发生在分布式的系统中,一般由成百上千台机器组成,而且工做的分配由master动态执行。为了帮助调试,分析,以及小规模的测试,咱们开发了另一个MapReduce库的实现,它可以在本地机器上顺序执行一个MapReduce操做的全部工做。它的控制交给用户,所以计算能够被限定到制定的Map task中执行。用户利用指定的flag启动程序,而后就能很是简单地使用任何它们以为有用的调试或者测试工具了。

4.8 Status Information

master运行了一个内置的HTTP server而且暴露了一系列供人类使用的状态页。状态页会显示程序的计算过程,例如已经完成了多少个task,还有多少个task正在执行,输入的字节数,中间数据的字节数,输出的字节数,以及处理速度等等。该页还包含了指向各个task的标准错误和标准输出连接。用户能够利用这些数据来判断计算会持续多长时间,以及计算是否须要添加更多的资源。这些页面还能用来发现何时处理速度比预期地降低好多。

另外,顶层的状态页显示了那些worker出错了,以及在它们出错时正在执行哪些Map和Reduce task。这些信息在诊断用户代码出现的bug时是很是有用的。

4.9 Counter

MapReduce库提供了一个叫counter的设施用于统计各类不一样事件出现的次数。例如,用户可能想要统计已经处理过的单词的数目或者德国文件的索引数量。

为了使用这一特性,用户代码建立一个命名的counter对象,而且在Map以及Reduce函数中对counter进行增长。例如:

Counter* uppercase;

uppercase = GetCounter("uppercase")

map(String name, String contents):

  for each word w in contents:

    if(IsCapitalized(w)):

      uppercase->Increment();

    EmitIntermediate(w, "1");

每一个worker机器上counter的值会按期传给master(捎带在给master的ping回复中)。master未来自成功执行的Map和Reduce task的counter值汇集起来。而后在MapReduce操做完成以后返回给用户代码。当前的counter值也会显示在master的状态页上,因此用户能从实时观看计算的进行。在汇集counter的值的时候,master会消除Map或者Reduce task的重复执行形成的重复计算。(重复执行可能由backup tasks或者由于错误从新执行的task引发)。

有些counter的值是由MapReduce库自动维护的,例如已经处理的输入键值对数目以及已经产生的输出键值对数目。

用户发现counter特性对于检查MapReduce操做的执行是很是有用的。例如,在有些MapReduce操做中,用户代码想要确保产生的输出对的数目和已经处理的输入对的数目是刚好相等的,或者处理的德语文件的数目占总处理文件数目的比重在一个可容忍的范围内。

5 Performance

 在这个section中,咱们经过运行在一个集群上的两个computation来测试MapReduce的性能。一个Computation搜索一个T的数据,从中获取一个特定的模式。另外一个computation对一个T的数据进行排序。

这两个程序表明了由用户实际编写的MapReduce程序的一个子集------一类程序用于将数据从一种表示方法切换到另外一种表示方法。另外一类程序则从大数据集中抽取出一小部分有趣的数据。

5.1 Cluster Configuration

全部程序都运行在一个由1800台机器组成的机器上。每一台机器都有两个2GHz 的Intel Xeon处理器,而且Hyper-Threading打开, 4GB内存,两个160GB的IDE磁盘,以及一个G的以太网链路。这些机器被安排在一个两层树状的交换网络中,根节点的带宽大概在100-200Gbps。由于全部机器都在同一个托管设备中,所以任意两台机器见的通讯时间少于1ms。

其中4GB中的1-1.5G是为集群中运行的其余任务预留的。程序在一个周末的下午运行,此时CPU,磁盘,网络基本都处于空闲状态。

5.2 Grep

grep程序须要扫描10的十次方条100-byte的记录,搜索一个相对罕见的三字符模式(出现了92337次)。输入被分红大概64MB份(M = 15000),全部的输出文件都存放在一个文件中(R = 1)。

Figure 2显示了Computation随着时间的变化过程。Y轴表明了输入数据的扫描速度。随着机器逐渐加入MapReduce的计算当中,速度愈来愈快,当有1764个worker加入时,达到峰值30GB/s。随着Map task的结束,速度开始降低而且在80s的时候到达0,。整个Computation从开始到结束总共花费了大概150s。这其中还包括了1分钟的启动开销。开销主要来源于将程序分发到worker machine中,和GFS交互并打开1000个输入文件,以及获取局部性优化所需的信息的延时。

 

5.3 Sort

排序程序用于对10的十次方条记录(大概1T的数据)进行排序。程序以TeraSort benchmark为模型。

相关文章
相关标签/搜索