This page looks best with JavaScript enabled

MIT 6.824 lab

 ·  ☕ 4 min read · 👀... views

According to Collaboration Policy, detailed code will not be placed here.

Just record the problems encountered during the lab.

Pre

go env

1
2
3
sudo apt install go
go env -w GO111MODULE=on
go env -w GOPROXY=https://goproxy.io,direct

source code

1
2
3
git clone git://g.csail.mit.edu/6.824-golabs-2020 6.824
cd 6.824
go mod init 6.824-lab

Lab1:MapReduce

前置知识:Go & net/rpc

题目中 src/mrapps/wc.go 中是已经写好的Map和Reduce方法
需要做的是填补 src/mr/master.go、rpc.go、worker.go
其中master由mrmaster调用、worker由mrworker调用
完成分布式MapReduce的架构设计并解决parallelism和fault tolerant

1
2
3
4
# 运行方式
# 初始状态下 反注释worker.go 中CallExample() 可以得到用rpc调用的y=x+1
go run mrmaster.go pg-*.txt
go run mrworker.go wc.so
1
2
3
4
5
cd src/main
# modify src/mrapps/wc.go import "6.824-lab/src/mr" before build    see [2]
# by default, we replace all "../mr" with "6.824-lab/src/mr"
go build -buildmode=plugin ../mrapps/wc.go
go run mrsequential.go wc.so pg*.txt

问题

Code

问题1和问题2都与这个master处理worker的ack处理函数有关

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
// 任务结束 更新task状态 重新调度
func (m *Master) TaskCompleted(task *Task, reply *ExampleReply) error {
	// worker可能断连后重新连接
	// 如果是worker和master在不同阶段 或者 在相同阶段但task状态为已完成
	// 则直接返回 让worker认为自己提交成功 然后尝试获取下一个任务(充分利用计算资源)
	if task.TaskState != m.MasterPhase || m.TaskMeta[task.TaskNumber].TaskStatus == Completed {
		return nil
	}

	m.mu.Lock()
	m.TaskMeta[task.TaskNumber].TaskStatus = Completed
	// 此处手动释放锁 否则下方函数中尝试获取锁永远失败
	m.mu.Unlock()

	switch task.TaskState {
	case Map:
		// 将该worker的nReduce个临时文件路径放到对应reducer的文件列表中
		for i := 0; i < task.NReducer; i++ {
			m.LocIntermediate[i] = append(m.LocIntermediate[i], task.Intermediates[i])
		}
		// for _, v := range m.LocIntermediate {
		// 	fmt.Println(v)
		// }
		if m.allTaskDone() {
			// 该函数里面也尝试上锁 但是前面已经上锁 导致该函数里面永远获取不到锁 所以一直等待
			m.createReduceTask()
			// fmt.Println(len(m.TaskQueue))
			m.MasterPhase = Reduce
		}
	case Reduce:
		if m.allTaskDone() {
			m.MasterPhase = Exit
		}
	}
	return nil
}

1同步锁阻塞

遇到mapper过程结束但是始终没有进入reduce过程的问题
尝试输出中间值发现判断allTaskDone()为true,但是尝试在createReduceTask()打印"create reduce task"字样失败
分析发现该函数里面也尝试上锁 但是外部函数已经上锁 编辑完资源后使用的是defer unlock 导致该函数里面永远获取不到锁 所以一直等待

解决方法是将defer unlock改成unlock

2crash test fail

看了一下是kill掉worker重启,主要考虑fault tolerant 任务重发及drop duplicated message

要有检测机制 过时重传任务 但是如何保证中间文件幂等呢?
一种解决思路是worker随意输出,向master ack的时候master判断任务是否已经被ack 是的话就丢弃掉worker传过来的地址 不是的话就将地址添加到维护的中间文件列表

本来是以每次append的方式输出到指定的nreducer个文件中,但是这样就没法保证持久化的中间文件是幂等的
解决方案是每次写成功到对应nReducer个文件中再通知完成
保证输出幂等的话只要每次写入不同的文件 写成功后再返回文件名给master即可
因为reducer并不知道由多少个worker master维护的对应reducer的intermediate文件列表也可以无限长
而中间文件名也可以摒弃原先intermediate[i]的命名方式直接改成随机字符串

worker可能断连后重新连接 当期完成他的任务将结果返回给master的时候 master需要进行特殊处理
如果是worker和master在不同阶段 或者 在相同阶段但task状态为已完成
则直接返回 让worker认为自己提交成功 然后尝试获取下一个任务(充分利用计算资源)

3connection refused

1
dialing:dial unix /var/tmp/824-mr-0: connect: connection refused

原因是master exit后worker尝试请求master失败
原本设置的task为0返回wait后worker sleep 5太长了 修改为sleep 1 然后master状态exit后sleep 1后再退出就解决问题了

Test

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
*** Starting wc test.
2022/03/11 13:07:44 rpc.Register: method "Done" has 1 input parameters; needs exactly three
--- wc test: PASS
*** Starting indexer test.
2022/03/11 13:07:50 rpc.Register: method "Done" has 1 input parameters; needs exactly three
--- indexer test: PASS
*** Starting map parallelism test.
2022/03/11 13:07:54 rpc.Register: method "Done" has 1 input parameters; needs exactly three
--- map parallelism test: PASS
*** Starting reduce parallelism test.
2022/03/11 13:08:02 rpc.Register: method "Done" has 1 input parameters; needs exactly three
--- reduce parallelism test: PASS
*** Starting crash test.
2022/03/11 13:08:11 rpc.Register: method "Done" has 1 input parameters; needs exactly three
--- crash test: PASS
*** PASSED ALL TESTS

Ref

[1] https://gitee.com/ruokeqx/mit6.824-lab [my code lib]
[2] http://nil.csail.mit.edu/6.824/2020/labs/lab-mr.html [mr lab page]
[3] https://github.com/golang/go/issues/26645 [cannot find module for path]
[4] https://www.bookstack.cn/read/go-rpc-programming-guide/part1-gorpc.md [go rpc]
[5] https://www.cnblogs.com/fydeblog/p/12826673.html

Share on

ruokeqx
WRITTEN BY
ruokeqx