Skip to content

6.824 Lab 1 MapReduce

Posted on:2022.07.25

TOC

Open TOC

lab1

使用 goland 调试

https://stackoverflow.com/questions/65137425/failed-in-error-plugin-was-built-with-a-different-version-of-package-while-deb

sequential

cd src/main
go build -race -buildmode=plugin ../mrapps/wc.go
go run -race mrsequential.go wc.so pg*.txt

distributed

cd src/main
go run -race mrcoordinator.go pg-*.txt
go run -race mrworker.go wc.so

basic

实际上理解了 rpc 后并不困难

基本的流程描述如下

  1. worker (client) 向 coordinator (server) 请求任务
  2. coordinator 为 worker 分配任务
  3. worker 在完成任务后通知 coordinator

coordinator 需要维护任务完成进度的数据结构,并使用 mutex 保护

task

下面进行任务的设计,显然有 map 和 reduce 两个任务

worker 需要得到 filepath / taskno / nReduce 信息

读取输入文件后 map,然后使用 os.CreateTemp 打开一系列的临时文件,通过 ihash(Key) % nReduce 得到输出的中间文件,并通过 json encoder 写入,最后 rename 即可

临时文件默认存放在 /tmp 中,重命名是为了消除随机的后缀,以供 reduce 阶段读取

中间文件的格式为 mr-X-Y,其中 X 为 taskno (map),Y 为 reduce 编号

worker 需要得到 taskno / nMap 信息

通过 json decoder 读取所有的中间文件后,sort 然后 reduce,思路类似 mrsequential.go,最后在工作目录打开输出文件并写入即可

之所以不使用临时文件,是因为后来的实现中避免了对同一文件的读写

所以 map 任务设计中重命名的步骤有点多余

并且硬链接不支持跨文件系统,重命名时会报错 EXDEV

输出文件的格式为 mr-out-X,其中 X 为 taskno (reduce)

early exit

考虑到 early exit test 中认为,只要 worker 和 coordinator 中有一个 exit,那么整个 Job 就完成了

为此,需要一种机制来同步 worker 和 coordinator 的 exit

方法时引入伪任务 sleep 和 exit

出现如下两种情形时,会分配 sleep 伪任务,就是让 worker 睡眠

当所有的 map task 均已分配,但 coordinator 未收到全部的 notification 时

当所有的 reduce task 均已分配,但 coordinator 未收到全部的 notification 时

由于 task 可能超时,所以需要让 worker 睡眠以待命

出现如下情形时,会分配 exit 伪任务,就是让 worker 退出

当 coordinator 收到全部的 notification 时

另外,即使 coordinator 已经 exit 了,worker 在 rpc 失败后也会自动退出

timeout

下面考虑超时的情形

需要在任务完成进度的数据结构中,维护每个任务开始的时间

当 worker 请求任务时,若 coordinator 发现某个任务在 running 但是已经超时了,就会重新分配该任务给 worker 并重新计时

相应的,worker 在开始任务时,为了避免文件读写冲突,会 remove 所有的相关的输出文件

注意这里细微的语义,参考 https://alfredthiel.gitbook.io/pintosbook/project-description/lab2-user-programs/faq#what-happens-when-an-open-file-is-removed 可知,当 remove 旧输出文件时并创建同名的新输出文件时,即使这两个文件同名,两个 worker 对其的写入也不会冲突

同时 coordinator 在接收 notification 时,也要判断任务是否超时来决定是否更新任务完成进度

log

使用官方的 log 库

worker 中涉及到大量对文件系统的操作,一旦出现错误,就直接 log.Fatalf 退出,根据上述分析,只要 worker 存在,就不会影响整个 Job 的完成,可以参考 crash test

可以重定向至 /dev/null,以更好的阅读测试输出的结果

nullPath := "/dev/null"
null, err := os.Open(nullPath)
if err != nil {
log.Fatalf("cannot open %v", nullPath)
}
log.SetOutput(null)

test

测试全部通过

ce88c752d4024a4aa43de697187c335b.png

由于并发的不确定性,多测几次也可以

a5bbcbd4d31b45fcb19f696220513933.png