mapreduce执行过程流程图_MapReduce —— 历久而弥新

本文深入探讨MapReduce的执行过程,包括Map和Reduce的抽象、任务执行流程、局部性优化、容错机制及任务粒度管理。通过对谷歌原始论文的解析,阐述MapReduce在大数据处理中的核心思想和经典实现,揭示了分布式计算的内在原理。
摘要由CSDN通过智能技术生成

e8d7b6eb764d6a9d98e64cc4597d3362.png

引子

MapReduce 是谷歌 2004 年(Google 内部是从03年写出第一个版本)发表的论文里提出的一个概念。虽然已经过去15 年了,但现在回顾这个大数据时代始祖级别概念的背景、原理和实现,仍能获得对分布式系统的很多直觉性的启发,所谓温故而知新。

在Google 的语境里,MapReduce 既是一种编程模型,也是支持该模型的一种分布式系统实现。它的提出,让没有分布式系统背景的开发者,也能较轻松的利用大规模集群以高吞吐量的方式来处理海量数据。其解决问题思路很值得借鉴:找到需求的痛点(如海量索引如何维护,更新和排名),对处理关键流程进行高阶抽象(分片Map,按需Reduce),以进行高效的系统实现(所谓量体裁衣)。这其中,如何找到一个合适的计算抽象,是最难的部分,既要对需求有直觉般的了解,又要具有极高的计算机科学素养。当然,并且可能更为接近现实的是,该抽象是在根据需求不断试错后进化出的海水之上的冰山一角。

作者:青藤木鸟Muniao's blog转载请注明出处

需求

谷歌当时作为互联网的最大入口,维护着世界全网索引,最早触到了数据量的天花板。即,哪怕针对很简单的业务逻辑:如从爬虫数据中生成倒排索引、将图状网页集合用不同方式组织、计算每个主机爬取的网页数量、给定日期的高频查询词汇等等,在全球互联网数据的尺度的加成下,也变的异常复杂。

这些复杂性包括:输入数据分散在非常多的主机上、计算耗资源太多单机难以完成、输出数据需要跨主机进行重新组织。为此,不得不针对每个需求重复构造专用系统,并耗费大量代码在分发数据和代码、调度和并行任务、应对机器故障和处理通信失败等问题上。

抽象

map 和 reduce 的抽象灵感来自于函数式编程语言 Lisp,为什么选定这两个概念呢?这来源于谷歌人对其业务的高度提炼:首先输入可以切分成一个个逻辑的记录 (record);然后对其每个 record 执行某种映射 (map) 操作,生成一些键值对组成的中间结果(为什么要分键和值呢?为最后一步做铺垫,允许用户将中间结果以任意指定的方式——,来进行组织规约);最后在具有相同键的中间结果子集上执行规约reduce ,包括排序,统计,提取最值等等)操作。

函数式模型的另一个特点在于对 map 操作实现的约束,即规定用户应提供一个无副作用的 map 操作(相关概念有纯函数确定性幂等性等等,当然他们的概念并不一样,后面小结会详细讨论)。如此限制,好处有二,可以进行大规模并行执行,可以通过换地儿重试来屏蔽主机故障。

具体到落地上,mapreduce 都是用户自定义函数。map 函数接受一个 Record,不过为了灵活,一般也组织为键值对;然后产生 List[key, value],reduce 函数接受一个 key 和该 key 对应的所有中间结果 List[value]。即:

map (k1,v1)             -→ list(k2,v2)
reduce (k2,list(v2))    -→ list(v2)

拿由谷歌这篇论文提出,后来成为大数据处理界的 hello world 级别示例程序 Word Count (对一堆文档中的单词计数)来说,mapreduce 的实现长这样:

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));

这里有两个有意思的点:

  1. 中间变量需要网络传输,必然会涉及到序列化。MapReduce 的最初版本选择是一切解释权归运行时的用户代码所有,我只是傻傻的传 string。即,规定用户在 map 中将任何输出的中间结果对象都转换为 string,然后在 reduce 函数中接收该 Iterator[string] 后,自行解析为自己想要的格式。当然,在后来的模仿框架如 Hadoop 中,序列化和解序列化部分被拿了出来,可以由用户来自定义实现来满足功能或性能上的需求。没去查证,谷歌后来相比对此也做了优化。这是一种很自然的系统演化思路,初期设计尽量简单粗暴以求快速实现可用原型;在积累使用经验后再对某些不便模块进行扩展设计。
  2. reduce 接受 value 集合被组织为了迭代器(Iterator)。相信用过 Python 的同学应该对迭代器不陌生,它是一个很简单的接口,包括 nextstop 两个语义。配合 for loop ,构成一个很强大的抽象。不管你底层是一个内存中的 List、还是文件内容、还是网络 IO 流,只要能在运行时知道如何得到下一条记录,什么时候时候停止,都能被 for 循环来利用,进行逐一处理。迭代器抽象的一个好处在于,不必将待迭代的内容一次加载到内存,可以对数据增量式的惰性加载。MapReduce 框架的此处实现也正是利用了该特性。

实现概览

抽象定了,那么实现自然可以有不同,这也是接口和实现分离的意义所在。前者的抽象是一种思想,谷歌已经给你做了;后者的实现,完全可以根据自己的生产环境进行量体裁衣的来定制实现。谷歌在 paper 中给了一种内部经典版,Hadoop 也提供了一套通用版,当然我们也可以根据自己的业务需求和场景约束来实现一个合身版。

谷歌发布论文时 实现

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值