7 相关工作
很多系统都提供了严格的编程模式,并且通过对编程的严格限制来实现自动的并行计算。例如,一个结合函数可以在一个N个元素的所有前缀上进行计算,并且使用并发前缀计算,会在在N个并发节点上会耗费log N的时间[6,9,13]。MapReduce是这些模式下的,一个我们基于超大系统的现实经验的一个简化和精炼。并且,我们还提供了基于上千台处理器的容错实现。而大部分并发处理系统都只在小规模的尺度上实现,并且机器的容错还是程序员来操心的。
Bulk Synchronous Programming[17]以及一些MPI primitives[11]提供了更高级别的抽象,可以更容易写出并行处理的程序。这些系统和MapReduce系统的不同之处在于,MapReduce是通过限制性编程模式自动实现用户程序的并发处理,并且提供了透明的容错处理。
我们本地的优化策略是受active disks[12,15]等技术的影响的,在active disks中,计算任务是尽量推送到数据在本地磁盘的节点处理,这样就减少了网络系统的I/O吞吐。我们是在直接附带几个硬盘的通机器上执行我们的计算工作,不是在磁盘处理器上执行我们的工作,但是总的效果是一样的。
我们的backup task机制和早先CharlotteSystem[3]的机制比较类似。早先的简单调度的一个缺点是如果一个任务导致反复失效,那么整个计算就不能完成。我们通过在故障情况下跳过故障记录的方式,在某种程度上解决了这个问题。
MapReduce的实现依赖于一个内部的集群管理系统,这个集群管理系统负责在一个超大共享机器组上分布和运行用户任务。虽然这个不是本论文的重点,集群管理系统在理念上和Condor[16]等其他系统一样。
MapReduce函数库的排序部分和NOW-Sort[1]的操作上很类似。源机器(map workers)把待排序的数据进行分区,并且发送到R个reduce worker中的一个进行处理。每一个reduce worker作本地排序(尽可能在内存排序)。当然NOW-Sort没有刻意用户定义的Map和Reduce函数,而我们的函数库有,所以我们的函数库可以有很高的适应性。
River[2]提供了一个编程模式,在这样的编程模式下,处理进程可以通过分布式查询来互相传送数据的方式进行通讯。和MapReduce类似,River系统尝试提供对不同应用有近似平均的性能,即使在不对等的硬件环境下或者在系统颠簸的情况下也能提供近似平均的性能。River是通过精心调度硬盘和网络的通讯,来平衡任务的完成时间。MapReduce的框架是通过限制性编程模式,来把问题分解成为大量的任务。每一个任务都是动态调度到可用的worker上执行,这样快速的worker可以执行更多的任务。限制性编程模式同样允许我们在接近计算完成的时候调度backup 任务,在出现处理不均匀的情况下,大量的缩小整个完成的时间(比如在有慢机或者阻塞的worker的时候)。
BAD-FS[5]和MapReduce的编程模式完全不同,它不像MapReduce是基于很大的网络计算的。不过,这两个系统有两个基本原理很类似。(1)两个系统都使用重复执行来防止由于失效导致的数据丢失。(2)两个都使用数据本地化调度策略,使得处理尽可能在本地数据上进行,减少通过网络通讯的数据量。
TACC[7]是一个用于简单构造高可用性网络服务的系统。就像MapReduce,它依靠重新执行机制来实现的容错处理。
8 结束语
MapReduce的编程模式在Google成功应用于许多方面。我们把这种成功应用归结为几个方面:首先,这个编程模式易于使用,即使程序员没有并行或者分布式系统经验,由于MapReduce封装了并行的细节和容错处理,本地化计算,负载均衡等等,所以,使得编程非常容易。其次,大量不同的问题都可以简单通过MapReduce来解决。例如,MapReduce用于产生Google的web搜索服务所需要的数据,用来排序,用来数据挖掘,用于机器智能学习,以及很多其他系统。第三,我们已经在一个好几千台计算机的大型集群上开发实现了这个MapReduce。这个实现使得对于这些机器资源的利用非常简单,并且因此也适用于解决Google遇到的其他很多需要大量计算的问题。
我们也从MapReduce上学到了不少内容。首先,先执行编程模式使得并行和分布式计算非常容易,并且也易于构造这样的容错计算环境。其次,网络带宽是系统的资源的瓶颈。我们系统的一系列优化都使因此针对减少网络传输量为目的的:本地优化使得我们读取数据时,是从本地磁盘读取的,并且写出单个中间数据文件到本地磁盘也节约了网络带宽。第三,冗余执行可以减少慢机器带来的影响,并且解决由于机器失效导致的数据丢失问题。
9 感谢
Josh Levenberg校定和扩展了用户级别的MapReduce API,并且结合他的适用经验和其他人的改进建议,增加了很多新的功能。MapReduce使用Google文件系统GFS[8]来作为数据和输出。我们还感谢Percy Liang Olcan Sercinoglu 在开发用于MapReduce的集群管理系统得工作。Mike Burrows,Wilson Hsieh,Josh Levenberg,Sharon Perl,RobPike,Debby Wallach 为本论文提出了宝贵的意见。OSDI的无名审阅者,以及我们的审核者Eric Brewer,在论文应当如何改进方面给出了有益的意见。最后,我们感谢Google的工程部的所有MapReduce的用户,感谢他们提供了有用的反馈,以及建议,以及错误报告等等。
10 参考资料
[1] Andrea C. Arpaci-Dusseau, Remzi H. Arpaci-Dusseau,David E. Culler, Joseph M. Hellerstein, and David A. Patterson.High-performance sorting on networks of workstations.In Proceedings of the 1997 ACM SIGMOD InternationalConference on Management of Data, Tucson,Arizona, May 1997.
[2] Remzi H. Arpaci-Dusseau, Eric Anderson, NoahTreuhaft, David E. Culler, Joseph M. Hellerstein, David Patterson, and Kathy Yelick. Cluster I/O with River:Making the fast case common. In Proceedings of the Sixth Workshop on Input/Output in Parallel and Distributed Systems (IOPADS '99), pages 10.22, Atlanta, Georgia, May 1999.
[3] Arash Baratloo, Mehmet Karaul, Zvi Kedem, and Peter Wyckoff. Charlotte: Metacomputing on the web. In Proceedings of the 9th International Conference on Parallel and Distributed Computing Systems, 1996. [4] Luiz A. Barroso, Jeffrey Dean, and Urs H¨olzle. Web search for a planet: The Google cluster architecture. IEEE Micro, 23(2):22.28, April 2003.
[5] John Bent, Douglas Thain, Andrea C.Arpaci-Dusseau, Remzi H. Arpaci-Dusseau, and Miron Livny. Explicit control in a batch-aware distributed file system. In Proceedings of the 1st USENIX Symposium on Networked Systems Design and Implementation NSDI, March 2004.
[6] Guy E. Blelloch. Scans as primitive parallel operations.IEEE Transactions on Computers, C-38(11), November 1989.
[7] Armando Fox, Steven D. Gribble, Yatin Chawathe, Eric A. Brewer, and Paul Gauthier. Cluster-based scalable network services. In Proceedings of the 16th ACM Symposium on Operating System Principles, pages 78. 91, Saint-Malo, France, 1997.
[8] Sanjay Ghemawat, Howard Gobioff, and Shun-Tak Leung. The Google file system. In 19th Symposium on Operating Systems Principles, pages 29.43, Lake George, New York, 2003. To appear in OSDI 2004 12
[9] S. Gorlatch. Systematic efficient parallelization of scan and other list homomorphisms. In L. Bouge, P. Fraigniaud, A. Mignotte, and Y. Robert, editors, Euro-Par'96. Parallel Processing, Lecture Notes in Computer Science 1124, pages 401.408. Springer-Verlag, 1996.
[10] Jim Gray. Sort benchmark home page. http://research.microsoft.com/barc/SortBenchmark/.
[11] William Gropp, Ewing Lusk, and Anthony Skjellum. Using MPI: Portable Parallel Programming with the Message-Passing Interface. MIT Press, Cambridge, MA, 1999.
[12] L. Huston, R. Sukthankar, R.Wickremesinghe, M. Satyanarayanan, G. R. Ganger, E. Riedel, and A. Ailamaki. Diamond: A storage architecture for early discard in interactive search. In Proceedings of the 2004 USENIX File and Storage Technologies FAST Conference, April 2004.
[13] Richard E. Ladner and Michael J. Fischer. Parallel prefix computation. Journal of the ACM, 27(4):831.838, 1980. [14] Michael O. Rabin. Efficient dispersal of information for security, load balancing and fault tolerance. Journal of the ACM, 36(2):335.348, 1989.
[15] Erik Riedel, Christos Faloutsos, Garth A. Gibson, and David Nagle. Active disks for large-scale data processing. IEEE Computer, pages 68.74, June 2001.
[16] Douglas Thain, Todd Tannenbaum, and Miron Livny. Distributed computing in practice: The Condor experience. Concurrency and Computation: Practice and Experience, 2004.
[17] L. G. Valiant. A bridging model for parallel computation. Communications of the ACM, 33(8):103.111, 1997.
[18] Jim Wyllie. Spsort: How to sort a terabyte quickly. http://alme1.almaden.ibm.com/cs/spsort.pdf.
A 单词频率统计
本节包含了一个完整的程序,用于统计在一组命令行指定的输入文件中,每一个不同的单词出现频率。
#include "mapreduce/mapreduce.h"
// User's map function
class WordCounter : public Mapper {
public:
virtual void Map(const MapInput& input) {
const string& text = input.value();
const int n = text.size();
for (int i = 0; i < n; ) {
// Skip past leading whitespace
while ((i < n) && isspace(text[i]))
i++;
// Find word end
int start = i;
while ((i < n) && !isspace(text[i]))
i++;
if (start < i)
Emit(text.substr(start,i-start),"1");
}
}
};
REGISTER_MAPPER(WordCounter);
// User's reduce function
class Adder : public Reducer {
virtual void Reduce(ReduceInput* input) {
// Iterate over all entries with the
// same key and add the values
int64 value = 0;
while (!input->done()) {
value += StringToInt(input->value());
input->NextValue();
}
// Emit sum for input->key()
Emit(IntToString(value));
}
};
REGISTER_REDUCER(Adder);
int main(int argc, char** argv) {
ParseCommandLineFlags(argc, argv);
MapReduceSpecification spec;
// Store list of input files into "spec"
for (int i = 1; i < argc; i++) {
MapReduceInput* input = spec.add_input();
input->set_format("text");
input->set_filepattern(argv[i]);
input->set_mapper_class("WordCounter");
}
// Specify the output files:
// /gfs/test/freq-00000-of-00100
// /gfs/test/freq-00001-of-00100
// ...
MapReduceOutput* out = spec.output();
out->set_filebase("/gfs/test/freq");
out->set_num_tasks(100);
out->set_format("text");
out->set_reducer_class("Adder");
// Optional: do partial sums within map
// tasks to save network bandwidth
out->set_combiner_class("Adder");
// Tuning parameters: use at most 2000
// machines and 100 MB of memory per task
spec.set_machines(2000);
spec.set_map_megabytes(100);
spec.set_reduce_megabytes(100);
// Now run it
MapReduceResult result;
if (!MapReduce(spec, &result)) abort();
// Done: 'result' structure contains info
// about counters, time taken, number of
// machines used, etc.
return 0;
}
B 译者
崮山路上走9遍2005-8-8于大连完稿
BLOG: sharp838.mblogger.cn
EMAIL: sharp838@21cn.com;guangweishi@gmail.com
所有的版权归于原作者。
感谢:朱朱,洋洋,sophia