MIT 6.824学习记录(二)——MapReduce介绍

实验介绍

该实验的内容是:实现一个MapReduce程序,使得该代码可以通过脚本(课程中提供了该测试脚本,以及非核心逻辑的代码)的测试。
因此,在开始实验前,要先弄清楚什么是MapReduce。

为什么要用MapReduce

这个概念由谷歌在 2003 和 2004 年发表的论文中随着GFS一起公之于众。在当时,还没有一个足够好的分布式计算框架,而谷歌的搜索引擎排序等众多任务都需要分布式计算,分布式计算对于开发者的要求很高,因此谷歌推出了MapReduce,也就是说可以这么理解:对于某些分布式任务,开发者无需关心分布式计算的问题,只需要将任务拆分成map任务和reduce任务,并且将实现好了的map方法、reduce方法以及原始数据丢给MapReduce即可。

接下来我将用一个例子来介绍MapReduce:
这是一个大家都很喜欢的MapReduce的例子,那就是统计单词出现个数。
当前有一万个文档,每个文档都有上万个单词,我需要统计出所有单词出现的次数。

那么就可以有多种解决办法:

  • 单线程
    维护一个HashMap,将每一个不同的单词作为key,如果hashmap的key中不存在该单词,则插入一对KV,key是单词本身,value设为1,如果已存在该key,则将该key对应的value加一,然后耿直的遍历到结束。
    这个办法优点很明显:程序简单,谁都能写出来。
    缺点更明显:耗时太高,而且如果是多核处理器甚至多台服务器,完全无法发挥出硬件性能。

  • 多线程
    维护一个线程池,每个线程都去遍历不同的文件,将结果存入到文件系统中(或者回传给主线程),然后等到所有线程完成工作后进行整合。
    优点:性能提高,充分利用计算机资源。
    缺点:编写难度较高,容易遇到锁、一致性、同步等问题,并且在多台服务器的情况下,无法满足需求。除此之外,一旦需求变化,比如将任务改为“列出每个单词出现过的文档名”,整个程序都面临巨大改动。

因此,接下来就有请MapReduce出场:

MapReduce是如何使用的

首先我们假设有这样两个文件:
a.txt:

a b b c

b.txt:

b d e f f

我们需要对这两个文件的所有单词出现的次数进行统计。
那么需要将单词统计这个工作分解为两个小工作:

map

func map(fileName string, fileContent string) []KeyValue{}

传入一个文件名和文件的内容,返回一堆KV对,在这个“统计单词”的任务中,这个函数应该完成这个事:
对于fileContent中的任何一个单词,都转换成这样的一个KV对:{“word”: “1”}。那么对于我们的a.txt,
那么返回的就是:[{“a”: “1”}, {“b”: “1”}, {“b”: “1”}, {“c”: “1”}],很明显这个函数很简单,谁都可以写出来。

reduce

func reduce(key string, values []string)string

这个更简单,直接返回values数组的长度就可以了。
比如输入为:key = b, values = [“1”, “1”, “1”],则返回“3”

得到结果

将map方法、reduce方法、原始文件、M、R值(后面讲解意义)传给MapReduce,然后MapReduce就会返回给你:

a 1
b 3
c 1
d 1
e 1
f 2

MapReduce做了什么?

很明显,只靠上面那两个方法,还远远不够 ,那么接下来就介绍一下整个MapReduce流程是如何运作的。

接下来讲解MapReduce在这个过程中做了什么:

首先启动一个master服务,负责分配任务和返回最终结果。
启动一堆worker服务,这些worker会向master申请任务,master在进行一定的规划后,将文件分配给各个worker,安排它们执行Map任务。

需要注意的是:“Map任务”是指worker将文件内容传递给map方法,并将map方法返回的结果进行一定处理和存储的整个完整过程,切勿与map函数混淆。

worker在收到Map任务后,对于接收到的每一个文件,执行用户提供的map方法,这会得到一组KV对,然后把这些KV对按照一定的规则,存入到本地的R个文件中(R的具体数值由用户输入)。需要注意的是,所有worker得到的包含的同一个Key的KV对,必须保证在同一个文件中,比如worker1处理a.txt的时候得到一个{“b”:“1”},并把这个kv对保存在1.txt文件中,那么worker2在处理b.txt时得到了一个{“b”:“1”}时,也必须将该kv对放在1.txt中。这个“1.txt”的文件命名完全由MapReduce编写者决定,将什么key对应的kv对存储到哪个文件中,也是由MapReduce决定的。这里为了方便讲解,我们就假设这里的逻辑是:如果单词的首字母小于等于c,则把kv对放到1.txt中,否则放入2.txt中。
那么很容易可以知道,执行完所有Map任务后,我们会得到两个临时文件:
1.txt:

a 1
b 1
b 1
c 1
b 1

2.txt:

d 1
f 1
f 1

文件中的kv对的顺序不一定是这样的,但是内容肯定是这样的。

接下来worker再向master请求任务时,master就会给worker分配Reduce任务。
worker接收到的Reduce任务其实就是master制定给该worker的临时文件,比如上面的1.txt。
worker会将该文件中同一个key的kv对整合在一起,然后调用reduce函数,将得到的结果存入自己的结果文件中。

比如如果worker1接收到了Reduce任务,要求处理1.txt,那么调用三次reduce方法:

reduce("a", ["1"]) // return "1"
reduce("b", ["1", "1", "1"]) // return "3"
reduce("c", ["1"]) // return "1"

并将返回的结果和key一起存储到自己的结果文件中,比如worker1.txt:

a 1
b 3
c 1

worker2如果接收到了Reduce任务,处理2.txt,那么同样会得到worker2.txt:

d 1
f 2

等所有临时文件都已经被reduce处理过之后,我们就可以得到一堆结果文件,接下来MapReduce再按照结果文件的命名规则找到它们,并将文件进行拼接,就得到了最终的结果:
result:

a 1
b 3
c 1
d 1
e 1
f 2

上一章:MIT6.824学习记录(一)——课程介绍

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值