2021MIT6.824 Lab1总结:MapReduce

github地址
https://github.com/c-toast/6.824-golabs-2021
基础概念
Map:输入为某一个输入文件,输出为若干个Key-Value对。Map根据任务需求,必要时会在该局部输入中运行算法,将输入中的有效信息提取出来并组织成Key-Value的形式。
Reduce:输入为相关的(具有相同key的)Key-Value的集合,输出同样为相关的Key-Value的集合。输出集合的大小往往比输入集合的大小小,很多时候只包含1个Key-Value对。Reduce在相关的Key-Value对上运行算法,对其合并压缩,是负责整合信息的一个函数。

分布式系统的整体工作流程的抽象描述
第一步是Map任务,Master将庞大的数据拆分成许多小块,并将这些小块交给不同的节点执行Map。第二步是Reduce任务,将第一步中产生的所有Key-Value对可以按照相关性划分为若干个集合,针对每一个集合,Master指派某个节点去执行Reduce。

关于Key-Value结构
MapReduce是提取信息并格式化,再整合信息的一个过程。其采用Key-Value结构,用Key来代表数据的属性。之所以采用这种结构,一个原因是在进行分布式任务的过程中,不可避免地要将相同属性的数据交给不同的节点处理。为了便于整合,因此需要使用Key来标识属性。

注意点

  1. 无论是Map任务还是Reduce任务,都应当均衡地将任务分配给多个节点并行运行,而不是将大量任务交给一个节点,否则也就失去了使用分布式系统的意义。因此无论是Map还是Reduce任务,都需要对输入有一个合理的划分。
  2. 如果我们希望只进行一轮Reduce任务,那么交给Reduce任务的集合必须包含该拥有相同key的所有Key-Value对。否则,节点执行完Reduce任务之后得出来的结果将不会是最终结果,因为还有一些相同Key的Key-Value对的信息没有被整合进来,因而需要更多次Reduce任务。
  3. 由于Reduce任务同样需要均衡被分配给不同节点执行,这就对Map任务的输出提出了一定的要求。常见的做法是Map任务输出的Key-Value对要按照它们的Key值被划分到不同的region中。在Reduce任务中,master指派一个region给某个节点,该节点向所有worker请求该region,这样就实现了Reduce任务的划分。

数据传输的实现
无论是Map还是Reduce,都需要进行节点间的通信与数据传输。在Map任务中,master需要传递给worker输入文件。在Reduce任务中,worker需要得到存储在其它worker中的某个Key的的Key-Value对。

朴素的实现就是进行直接通信。例如在Reduce任务中,节点向其它所有节点都进行一次通信,请求它们的Key-Value对(Key-Value对存储在这些节点的disk中)。

一种更方便的实现是基于节点间的文件系统(如GFS)。在Map任务中,master将输入文件存储到GFS上,worker也从GFS上读取文件。worker完成Map后,将Key-Value对以文件的形式存到GFS上,执行Reduce任务的worker也直接从GFS读取相关文件。这中实现有以下几个值得注意和关键的地方:

  1. 前面虽然说Reduce每次对一个具有相同Key的Key-Value集合进行处理,但在GFS实现中,往往会进行批量处理,即worker会把Map输出中多个这样的Key-Value集合打包在一个文件(即region)中,Reduce接受这个文件和其它worker输出的其它相关的文件,同时对多个集合进行处理。
  2. worker要对输出文件有一个约定,把某些Key的Key-Valude对存储到以名字具有某些特征的文件中(即region)。这样执行Reduce的worker只要读取所有拥有这些特征的文件,就可以得到某个Key的所有Key-Value对,就不会出现前面注意点2中提到的问题。
  3. 利用临时文件以及对临时文件的原子性改名操作,可以实现任务的原子性。即任务进行的时候,所有的操作在临时文件上进行。任务完成后,再将临时文件的名字改为正式文件。

MIT6.824 MapReduce实验相关
在google的论文中提到,MapReduce能让开发者不必理会分布式系统编程的种种细节,只需要写好Map函数和Reduce函数就能让程序运行在分布式系统上。该实验并不是让我们去写Map或Reduce函数,而是让我们去实现一个简单的MapReduce框架,因此在实现的过程中,我们必须考虑分布式系统编程的细节,如performance,parallelism,fault tolerance。

在实验中,有如下几个需要注意的地方:

  1. 需要一个任务队列,当worker发出任务请求的时候,从任务队列中取出一个任务交给worker。该队列必须是互斥队列。可以用go中的chan实现。
  2. 需要一个结构体(如map)用于存储任务状态。当worker完成任务或任务超时的时候,需要从中取出该任务,读取状态并进行下一步操作(如当任务超时的时候重新发布任务)。由于worker请求任务时会对该结构体进行写操作,worker完成任务或超时时会进行读操作,因此该结构体必须是互斥的可以用mutex实现。
  3. 每一个任务结构体都必须是互斥的,因为完成任务时会对该结构体进行写操作(修改状态),任务超时时会对该结构体进行读操作。可以复用第二步中的mutex,也可以对每一个任务分配一个mutex以实现更细粒度的锁。
  4. 文件的数目即Map任务的数目,而nReduce代表Reduce任务的数目。worker要将Map函数输出的Key-Value对根据它们的hash(Key)%nReduce值找到相应index的文件并写入。执行Reduce的worker根据自己从master收到的Index读取所有文件名包含该Index的文件,然后执行Reduce。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值