阅读 577

[笔记]MIT6.824(2020,分布式) Lecture 1 Introduction

1.简介

Lecture 1主要是介绍了MIT6.824这门课程的课程安排,分布式的概念、为什么要使用分布式(水平和垂直维度提高系统的可用性与性能、高效利用廉价硬件集群的性能来快速完成海量数据处理任务)以及实现分布式过程中的挑战(CAP)。最后介绍了MapReduce以及它的优缺点。课后需要完成lab1,自己构建一个MapReduce系统。

课程的视频(B站就可以看):www.bilibili.com/video/BV1R7…

Lecture1的讲义:pdos.csail.mit.edu/6.824/notes…

MapReduce论文:pdos.csail.mit.edu/6.824/paper…

Lecture1课后lab1的要求:pdos.csail.mit.edu/6.824/labs/…

2.Lab1实现

实现lab1前,要求先读完MapReduce的论文,并仔细阅读lab1的要求文档。

lab要求使用Go语言。目标是实现MapReduce模型,需要分别实现Master和Worker线程。worker线程可以读写文件,调用Map和Reduce功能。Master线程,能将任务分发给worker,而且可以处理运行失败的worker,以及当某个worker运行的比较慢的时候,可以将同一个任务下发个另一个空闲的worker

2.0.GO语言入门学习

之前没用过GO,现学吧,把Go 语言基础语法 | 菜鸟教程给看完,知道GO的基础语法,就可以上手lab1开发了,有遇到问题就google下。

2.1.GO环境安装
  1. 按照lab1上的要求,下载1.3版本的免安装版的golang:golang.google.cn/dl/go1.13.w…
  2. 下载完成后解压zip包,配置golang的环境变量,将go下面的bin目录添加到path中,同时配置GOROOT和GOPATH。
2.2.IDE

​ 折腾了下用sublime安装godef和gosublime,太折腾了,而且也不是很好用。还是用GoLand(破解补丁)吧。

2.3.Go代码编写时要注意的
  1. GO rpc方法的格式:

    func (m *Master) RegisterWorker(mrworkerUUID string, ret *MRWorkerRegisterReply) error {
    
    	idleWorkers := m.workerMap[WorkerIdle]
    	idleWorkers = append(idleWorkers, MRWorker{uuid: mrworkerUUID})
    
    	for i, idleWorker := range m.workerMap[WorkerIdle] {
    		log.Printf("m.workerMap[WorkerIdle][%d] = %s\n", i, idleWorker.uuid)
    	}
    
    	ret.ret = true
    	return nil
    }
    复制代码
  2. 结构体struct中小写开头的成员变量表示protected级别,不能被其他package下的代码访问也不会参与序列化,所以在进行RPC调用的时候,如果有用到某个变量,应该将它首字母设置为大写:

    type MRWorkerRegisterReply struct {
    	Ret bool
    }
    复制代码
  3. golang打印输出fmt和log

  4. 数组元素拷贝时,如果不使用指针默认是元素值(不是内存地址值,是元素实际的值)拷贝:

    package main
    
    import "fmt"
    
    type MRWorker struct {
    	uuid string
    	status int
    
    }
    
    func main() {
    	var workerA = [2]MRWorker{{
    		uuid:   "1",
    		status: 1,
    	},{
    		uuid:   "2",
    		status: 1,
    	}}
    
    	var workerIdelArr []MRWorker
    	for i := range workerA {
    		if workerA[i].status == 1 {
    			workerIdelArr = append(workerIdelArr, workerA[i])
    		}
    	}
    
    	worker := workerIdelArr[0]
    	workerIdelArr = workerIdelArr[1:]
    
    	worker.status = 2
    
    	for _, mrWorker := range workerA {
    		fmt.Printf("uid = %s, status = %d \n ", mrWorker.uuid, mrWorker.status)
    	}
    }
    复制代码

    使用指针来操作数组:

    package main
    
    import "fmt"
    
    type MRWorker struct {
    	uuid string
    	status int
    
    }
    
    func main() {
    	var workerA = [2]MRWorker{{
    		uuid:   "1",
    		status: 1,
    	},{
    		uuid:   "2",
    		status: 1,
    	}}
    
    	var workerIdelArr []*MRWorker
        // TODO 不能使用这种遍历 for _, worker := range m.workerA 
    	for i := range workerA {
    		if workerA[i].status == 1 {
    			workerIdelArr = append(workerIdelArr, &workerA[i])
    		}
    	}
    
    	var worker *MRWorker = workerIdelArr[0]
    	workerIdelArr = workerIdelArr[1:]
    
    	(*worker).status = 2
    
    	for _, mrWorker := range workerA {
    		fmt.Printf("uid = %s, status = %d \n ", mrWorker.uuid, mrWorker.status)
    	}
    }
    
    // 输出
    uid = 1, status = 2 
    uid = 2, status = 1 
    复制代码
  5. string和int类型转换正确姿势:

    reduceNum := 1
    √ strconv.Itoa(reduceNum)
    × string(reduceNum)
    复制代码
  6. RPC接口必须要返回error,否则调用RPC接口的时候会报错找不到方法

    func (mrworker *MRWorker) Exit(reduceReq *MapReduceRequest, ret *RpcReply) error {
    	mrworker.Stop = true
    	ret.Ret = true
    	return nil
    }
    复制代码
  7. shell脚本不识别windows换行符,解决方式

    $ sh ./test-mr.sh
    ./test-mr.sh: line 2: $'\r': command not found
    ./test-mr.sh: line 6: $'\r': command not found
    ./test-mr.sh: line 8: $'\r': command not found
    ./test-mr.sh: line 11: $'\r': command not found
    
    复制代码
  8. 跑test-mr.sh前,看下这个shell脚本里的内容,看看是怎么测试的,这样子测试不通过的时候自己也能知道怎么去debug和处理。

2.5.成功的喜悦XD

lab1还是挺简单的,读一到两遍MapReduce的论文,然后仔细看下lab1的要求(一定要仔细看,很多细节要注意),基本上lab1对于有编程基础的人应该是没啥难度的。

完成lab1之后,跑测试的时候发现一个问题,每次跑完一个测试案例之后,在test-mr.sh中将map生成的中间文件删除了,再执行下一个测试,没问题,能全部跑通,但是如果不删除map生成的中间文件的话 reduce parallelism和crash两个test会跑的很慢,crash必定超时。。。

感觉还是前面测试案例产生的中间数据文件会对后面的测试有影响,在文件命名的时候,应该以每次测试为粒度,让相互之间的任务不收到影响,解决方式:通过给master添加了一个uuid来标识每次测试,顺利通过test-mr.sh。如果master在整个测试期间都不停止的话,就无法将uuid添加到master上,可以换种方式,在每个测试任务中都生成一个uuid并添加到这次测试任务中的的map job和reduce job上。修改完毕之后,测试全部跑通~。源码就不分享出来,一是第一次用Go写的有点糙,二是这个课程希望学生们不要将lab代码开源放到github上(如果将仓库设置成private是没问题的。老师还是担心学生们去github上搜线程的源码,自己不去动手搞lab,也就失去了这个lab的意义。)

image-20210131091746290

文章分类
后端