实验项目由纯 Go 语言开发。代码框架已经搭好并提供了各类条件的测试用例来模仿分布式场景下的意外事件。最终目的是在指定修改的地方 coding 并经过测试用例,同时须要关注时间消耗,必定程度上性能作到最优。 ### 熟悉项目 在 master_rpc.go
里面启动 master 提供 RPC 服务用来和 workers 之间用通讯。每一个 worker 都会在 master.go
中的 Register() 的注册服务。 MapReduce 会从 master.go 中的 run() 启动。这个方法的签名为git
func (mr *Master) run( jobName string, files []string, nreduce int, schedule func(phase jobPhase), finish func(), ) {}
复制代码
整个实验分红了 sequential 和 parallel 两种模式。最大的区别在于调度函数的实现方式,实验在sequential 已经实现了串行的调度,然后面将要本身实现并行的调度器,也就是 run 方法中的 schedule 须要本身写更快的。github
MapReduce 的基本输入输出数组
给 map task 的输出进行分片 doMap 方法中的 mapF 会产生一个 key-value 数组。须要作的就是把这个数组按照里面 key 转换成比较均匀的的 nReduce 个由 key-value 组成的小数组并写到文件当中。这里有个要点,若是采用直接按顺序划分。好比说若是数组的长度是 m,第一组是 0..m/nReduce-1, 第二组是 m/nReduce..m/nReduce*2-1 直到划分完。这样作有个问题就是须要把相同 key 放到一组便于后面的 Reduce 操做。因此目前看来作 Hash 而后 mod nReduce 这样既能够比较均匀划分文件,同时又可让相同 key 的在一个文件里面。数据结构
给 reduce task 组装全部的输入 读取 1 产生的中间文件。相同的 key 能够把对应的 value 组合起来产生多个 key-values 的数据结构。随后对这样的数据结构进行按照 key 排序并写到 reduce 的输出文件当中。并发
经过 1,2 能够肯定最终会产生 nMap * nReduce 个中间文件。框架
单机版的 word count分布式
相对于 PartI 其中的 mapF 和 reduceF 须要按照当前用户逻辑来实现。mapF 须要作的就是把出现过的单词都转换成 word-count 这样的 key-value 结构。reduceF 只须要对出现过的内容作一个获取长度就结束了。ide
分布式版的 word count函数
在完成了 Part I 和 Part II 以后应该就对单机版的 word count 如何实现比较清晰了。在分布式场景下,workers 到 master 之间会用 rpc 的方式通讯。 workers 会充分利用计算机的多核实现并发。按照要求是须要实现调度器 schedule.go
中的 schedule() 方法。按照 sequential 的模式,调度器会被传入当前的阶段是 map 仍是 reduce,而且只会被传入一次。按照题目前面给的要求,输入文件的个数决定了 map worker 的个数。随后 map worker 执行的同时,reduce worker 也在同时执行。那么其实就是改形成了用 goroutine 来 rpc 调用对应的用户方法, 并用 waitGroup 来记录完成状况。性能
容错 测试代码会让部分 worker 出现失效,这个失效能够理解为不论当前工做完成多少,即便是完成了也有可能返回 false。这也就意味着可能出现多个 workers 作了一样的任务。因此原则上,须要保证任务 idempotent,从函数式的角度而言,自己做为一个函数就应该是相同输入相同输出的状态。为实现容错,还须要实现重试机制。在多个 goroutine 同时跑的时候,最简单的方法实现重试就是附加一个 retryChan 用来存放记录重试任务。