源代码参见我的github: https://github.com/YaoZengzeng/MIT-6.824

Part I: Word count

MapReduce操作实际上就是将一个输入文件拆分成M份,交由M个Map task进行操作。每个Map task生成R个包含中间键值对的结果。R个Reduce task执行Reduce操作,其中第i个Reduce task操作每个Map task的第i个输出文件。最终,生成R个结果文件,通过Merge操作,将结果生成一个输出文件。

1、mapreduce.RunSingle执行流程分析:

(1)、src/mapreduce/mapreduce.go

func RunSingle(nMap int, nReduce int, file string, Map func(string) *list.List, Reduce func(string, *list.List) string)

该函数首先调用mr := InitMapReduce(nMap, nReduce, file, "")初始化一个MapReduce结构,再调用mr.Split(mr.file)切割输入文件,

最后再调用两个for循环,做nMap次DoMap(i, mr.file, mr.nReduce, Map  )操作和nReduce次DoReduce(i, mr.file, mr.nMap, Reduce)操作。

MapReduce结构如下所示:

type MapReduce struct {

  nMap        int  // Number of Map jobs

  nReduce       int  // Number of Reduce jobs
  file        string // Name of input file
  MasterAddress  string
  registerChannel  chan string
  DoneChannel    chan bool
  alive       bool
  l           net.Listener
  stats       *list.List
  // Map of registered workers that you need to keep up to date   Worker       map[string]*WorkerInfo
  // add any additional state here }

  

(2)、src/mapreduce/mapreduce.go

func InitMapReduce(nmap int, nreduce int, file string, master string) *MapReduce

该函数仅仅对一个MapReduce结构进行初始化,其中mr.alive = true, mr.registerChannel = make(chan string), mr.DoneChannel = make(chan bool)

// Split bytes of input file into nMap splits, but split only on white space

(3)、src/mapreduce/mapreduce.go

func (mr *MapReduce) Split(fileName string)

该函数的作用是将fileName切分成nMap块,先获取每个块的大小nchunk,再从输入文件中读取内容,写入输出文件中,每当读取内容的大小大于nchunk的整数倍时,再创建一个新的输出文件进行写操作。从而将输入文件切分到mr.nMap个输出文件中。其中,输出文件的命名方式为 "mrtmp." + fileName + "-" + strconv.Itoa(MapJob),其中MapJob就是一个编号。

// Read split for job, call Map for that split, and create nreduce partitions

(4)、src/mapreduce/mapreduce.go

func DoMap(JobNumber int, fileName string, nreduce int, Map func(string) *list.List)

该函数先根据name := MapName(fileName, JobNumber)中获取输入文件名,再将文件的内容读入[]byte切片b中,最后调用res := Map(string(b))

再将中间键值对存入nreduce个临时文件中,临时文件的命名规则为 MapName(fileName, MapJob) + "-" + strconv.Itoa(ReduceJob)。

其中将哪个中间键值对存入哪个文件是由中间键的哈希值决定的。如果中间键的哈希值恰好和reduce Job的编号相等,则将该中间键值对存入。这样做有一个好处,就是每个Map task的产生的具有相同键的键值对都会被放在同一序号的临时输出文件中,因此能被同一个Reduce task取到,因此每个Reduce task产生的结果对于每个单词就是最终结果,从而不需要对R个Reduce task的结果再进行合并操作。

KeyValue结构如下所示:

type KeyValue struct {

  Key     string
  Value   string
}

  

// Read map outputs for partition job, sort them by key, call reduce by each key

(5)、src/mapreduce/mapreduce.go

func DoReduce(job int, fileName string, nmap int, Reduce func(string, *list.List) string)

首先定义变量 kvs := make(map[string]*list.List),用于保存从nmap个文件中收集来的中间键值对,其中同一个中间键对应的中间值都保存在一个list中。

再对这些中间键进行排序,并且对每个中间键调用res := Reduce(k, kvs[k])函数,并将最终结果以KeyValue{k, res}的形式写入Merge文件中,Merge文件的命名形式为 "mrtmp." + fileName + "-res-" + strconv.Itoa(ReduceJob)

// Merge the results of the reduce jobs XXX use merge sort

(6)、src/mapreduce/mapreduce.go

func (mr *MapReduce) Merge()

首先定义变量 kvs := make(map[string]string),再从nReduce个文件中读入结果,放入kvs中。最后对所有键值进行排序,并按排序结果输出键值和对应的最终结果。

Part II:Distributing MapReduce jobs

MASTER 创建流

1、src/mapreduce/mapreduce.go

func MakeMapReduce(nmap int, nreduce int, file string, master) *MapReduce

(1)、首先调用mr := InitMapReduce(nmap, nreduce, file, master)初始化MapReduce结构

(2)、调用mr.StartRegistrationServer()

(3)、调用go mr.Run(),并return mr

2、src/mapreduce/mapreduce.go

func (mr *MapReduce) StartRegistrationServer()

(1)、调用rpcs := rpc.NewServer()和rpcs.Register(mr)生成一个RPC server

(2)、调用l, e := net.Listen("unix", mr.MasterAddress)并且将l赋值给mr.l

// now that we are listening on the master address, can fork off accepting connections to another thread

(3)、启动一个goroutine,调用conn, err := mr.l.Accept()建立连接,每建立一个连接就创建一个goroutine,

其中调用rpcs.ServeConn(conn)对连接进行处理,再调用conn.Close()关闭连接

// Run jobs in parallel, assuming a shared file system

3、src/mapreduce/mapreduce.go

func (mr *MapReduce) Run()

该函数首先调用mr.Split(mr.file)将输入文件切分为mr.nMap个文件,再调用mr.stats = mr.RunMaster(),接着调用mr.Merge()对mr.nReduce个输出文件进行合并,最后调用mr.CleanupRegistration(),注销worker。

4、src/mapreduce/master.go

func (mr *MapReduce) RunMaster() *list.List

5、src/mapreduce/mapreduce.go

func (mr *MapReduce) CleanupRegistration()

首先创建变量 args := &ShutdownArgs{},var reply ShutdownReply,最后调用ok := call(mr.MasterAddress, "MapReduce.Shutdown", args, &reply )

// call() returns true if the server responded, and false if call() was not able to contact the server.in particular, reply's

// contents are valid if and only if call() returned true

// you should assume that call() will time out and return an error after a while if it doesn't get a reply from the server

// please use call() to send all RPCs, in master.go, mapreduce.go, and worker.go. don't change this function

6、src/mapreduce/common.go

func call(srv string, rpcname string, args interface{}, reply interface{}) bool

首先调用 c, errx := rpc.Dial("unix", srv)建立连接,再调用err := c.Call(rpcname, args, reply)传送RPC

7、src/mapreduce/mapreduce.go

func (mr *MapReduce) Register(args *RegisterArgs, res *RegisterReply) error

调用mr.registerChannel <- args.Worker,res.Ok =true,并且返回nil

worker创建流

worker结构如下所示:

// Worker is a server waiting for DoJob or Shutdown RPCs

type Worker struct {

  name  string
  Reduce func(string, *list.List) string
  Map   func(string) *list.List
  nRPC  int
  nJobs  int
  l     net.Listener
}

  

// Set up a connection with the master, register with the master, and wait for jobs from the master

1、src/mapreduce/worker.go

func RunWorker(MasterAddress string, me string, MapFunc func(string) *list.List, ReduceFunc func(string, *list.List) string, nRPC int)

注:当参数nRPC的值为-1时,说明该worker永远不会fail,否则再接受nRPC个job之后fail

(1)、首先初始化一个Worker结构wk

(2)、调用rpcs := rpc.NewServer()和rpcs.Register(wk),创建一个rpc server

(3)、调用l, e := net.Listen("unix", me)和wr.l = l

(4)、调用Register(MasterAddress, me)

(5)、当wk.nRPC不为0时,一致循环接收conn, err := wk.l.Accept(),并且在err为nil时,调用wk.nRPC -= 1,go rpcs.ServeConn(conn), wk.nJobs += 1

// Tell the master we exist and ready to work

2、src/mapreduce/worker.go

func Register(master string, me string)

创建变量 args := &RegisterArgs{},args.Worker = me,var reply RegisterReply,最后调用ok := call(master, "MapReduce.Register", args, &reply)

Part III: Handling worker failures

tips:

(1)、master通过RPC超时来判断一个worker是否fail。

(2)、RPC failure并不意味着worker的故障;worker可能只是不可达了,但是仍然在进行计算。因此可能发生两个worker接受到了同一个job并且对它进行了计算。但是因为job都是幂等的,因此一个job是否被计算了两次是无所谓的,反正两次计算产生的是相同的结果。而且在我们的测试中,我们不会在job执行的过程中让worker发生故障,所以我们不需要担心多个worker写同一个输出文件的情况。

------------------------------------------------------------------------------------- 测试框架分析 -----------------------------------------------------------------------------------------

Test Basic:

1、src/mapreduce/test_test.go

func TestBasic(t *testing.T)

(1)、调用mr := setup()

(2)、for循环,调用go RunWorker(mr.MasterAddress, port("worker"+strconv.Itoa(i)), MapFunc, ReduceFunc, -1)

(3)、调用<-mr.DoneChannel等待MapReduce操作结束

(4)、最后依次调用check(t, mr.file),checkWorker(t, mr.stats),cleanup(mr)进行检查清理工作

2、src/mapreduce/test_test.go

func setup() *MapReduce

调用file := makeInput()创建输入文件,再调用master := port("master")创建一个UNIX-domain socket name,格式为/var/tmp/824-$(uid)/mr$(pid)-master

最后调用mr := MakeMapReduce(nMap, nReduce, file, master)

// Checks input file against output file: each input number should show up in the output file in string sorted order

3、src/mapreduce/test_test.go

func check(t *testing.T, file string)

该函数打开file文件,并从中读入所有行至var line []string中,并调用sort.Strings(lines)进行排序,最后逐行读取输出文件,并将两者进行比较

// Workers report back how many RPCs they have processed in the Shutdown reply.

// Check that they processed at least 1 RPC.

4、src/mapreduce/test_test.go

func checkWorker(t *testing.T, l *list.List)

遍历l,其中若有e.Value == 0,则报错

5、src/mapreduce/test_test.go

func cleanup(mr *MapReduce)

调用mr.CleanupFiles()删除所有临时文件,再调用RemoveFile(mr.file)删除输入文件

Test One Failure:

1、src/mapreduce/test_test.go

func TestOneFailure(t *testing.T)

首先调用mr := setup()建立MapReduce系统,再生成两个worker

其中一个worker的启动函数为go RunWorker(mr.MasterAddress, port("worker"+strconv.Itoa(0)), MapFunc, ReduceFunc, 10)

另一个worker的启动函数为go RunWorker(mr.MasterAddress, port("worker"+strconv.Itoa(1)), MapFunc, ReduceFunc, -1),之后再对结果进行检查并完成清理,流程和Basic基本类似。

Test Many Failures:

同样,首先调用mr := setup()建立MapReduce系统。当系统为完成之前,不断地进行循环,每隔一秒生成一个worker,并且每个worker做完10个job之后就会发生故障。

MIT 6.824 : Spring 2015 lab1 训练笔记的更多相关文章

  1. MIT 6.824 : Spring 2015 lab3 训练笔记

    摘要: 源代码参见我的github:https://github.com/YaoZengzeng/MIT-6.824 Lab3: Paxos-based Key/Value Service Intro ...

  2. MIT 6.824 : Spring 2015 lab2 训练笔记

    源代码参见我的github:https://github.com/YaoZengzeng/MIT-6.824 Lab 2:Primary/Backup Key/Value Service Overvi ...

  3. MIT 6.824(Spring 2020) Lab1: MapReduce 文档翻译

    首发于公众号:努力学习的阿新 前言 大家好,这里是阿新. MIT 6.824 是麻省理工大学开设的一门关于分布式系统的明星课程,共包含四个配套实验,实验的含金量很高,十分适合作为校招生的项目经历,在文 ...

  4. MIT 6.824学习笔记4 Lab1

    现在我们准备做第一个作业Lab1啦 wjk大神也在做6.824,可以参考大神的笔记https://github.com/zzzyyyxxxmmm/MIT6824_Distribute_System P ...

  5. MIT 6.824 lab1:mapreduce

    这是 MIT 6.824 课程 lab1 的学习总结,记录我在学习过程中的收获和踩的坑. 我的实验环境是 windows 10,所以对lab的code 做了一些环境上的修改,如果你仅仅对code 感兴 ...

  6. Spring in Action 学习笔记三-AOP

    面向切面的Spring 2015年10月9日 11:30             屏幕剪辑的捕获时间: 2015-10-9 14:30             屏幕剪辑的捕获时间: 2015-10-9 ...

  7. 1、Spring In Action 4th笔记(1)

    Spring In Action 4th笔记(1) 2016-12-28 1.Spring是一个框架,致力于减轻JEE的开发,它有4个特点: 1.1 基于POJO(Plain Ordinary Jav ...

  8. spring cloud(学习笔记)高可用注册中心(Eureka)的实现(二)

    绪论 前几天我用一种方式实现了spring cloud的高可用,达到两个注册中心,详情见spring cloud(学习笔记)高可用注册中心(Eureka)的实现(一),今天我意外发现,注册中心可以无限 ...

  9. spring 中bean学习笔记

    spring 中bean 一.bean的定义和应用 1. bean 形象上类似于getXX()和setXX()的一种. 2. 由于java是面向对象的,类的方法和属性在使用中需要实例化. 3. 规律: ...

随机推荐

  1. 使用 iosOverlay.js 创建 iOS 风格的提示和通知

    iosOverlay.js 用于在 Web 项目中实现 iOS 风格的通知和提示效果.为了防止图标加载的时候闪烁,你需要预加载的图像资源.不兼容 CSS 动画的浏览器需要 jQuery 支持.浏览器兼 ...

  2. 给你推荐10款优秀的 HTML5 动画工具

    HTML5 在过去三年快速增长,已经成为 Web 开发人员最喜欢的编程语言之一.强大的编程语言拥有开发更好的网页应用的能力. HTML5 中引入的新技术都非常好,像 Chrome.Firefox.Sa ...

  3. 为你的网页图标(Favicon)添加炫丽的动画和图片

    Favico.js 在让你的网页图标显示徽章,图像或视频.你设置可以轻松地在网页图标中使用动画,可以自定义类型的动画,背景颜色和文字颜色.它支持的动画,像幻灯片,渐变,弹出等等. 您可能感兴趣的相关文 ...

  4. 将Win10变回Win7/WinXP界面

    前往 Classic Shell 的网站(传送门:http://www.classicshell.net/)进行下载安装.第一次开启 时,程序会让你选择一款面板:第一个是 Windows 2000 的 ...

  5. 关于asp.net impersonation的一些谣传

    以下皆是理论知识,未经证实. system.web下面的配置节 <identity impersonate="true" /> 或者<identity imper ...

  6. Android HTTP实例 发送请求和接收响应

    Android HTTP实例 发送请求和接收响应 Android Http连接 实例:发送请求和接收响应 添加权限 首先要在manifest中加上访问网络的权限: <manifest ... & ...

  7. RecyclerView的基本使用

    1.布局文件中使用 <android.support.v7.widget.RecyclerView android:id="@+id/recycleview" android ...

  8. Facebook开源动画库 POP-POPBasicAnimation运用

    动画在APP开发过程中还是经常出现,将花几天的时间对Facebook开源动画库 POP进行简单的学习:本文主要针对的是POPBasicAnimation运用:实例源代码已经上传至gitHub,地址:h ...

  9. apache 虚拟ip

    参考 http://blog.sina.com.cn/s/blog_5d8ca1e90100hnpv.html <VirtualHost 127.0.0.1:80>      Docume ...

  10. Jexus-5.6.3使用详解、Jexus Web Server配置

    一.Jexus Web Server配置   在 jexus 的工作文件夹中(一般是“/usr/jexus”)有一个基本的配置文件,文件名是“jws.conf”. jws.conf 中至少有 Site ...