源代码参见我的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. FancyBox - 经典的 jQuery Lightbox 插件

    FancyBox 是一款非常优秀的弹窗插件,能够为图片.HTML 内容和其它任务的多媒体内容提供优雅的弹出缩放效果.作为是最流行的 Lightbox 插件之一,可以通过 fitToView 实现自适应 ...

  2. 原生andriod浏览器回退后dom(click)事件全体失效问题探究

    问题描述 今天同事遇到一个神一样的BUG: 在原生浏览器下,为dom元素绑定一个click事件,其中有个a标签外链,点击a后进入其他页面,点击浏览器后退后,页面点击事件全体失效! 我于是用ios测了下 ...

  3. MAPINFO中利用GridMaker工具创建栅格图层

    在工作中需要使用栅格地图,以往都是由研发人员来创建,今天偶然发现Mapinfo中有GridMaker这样一个工具,结合网络搜索自己试了一下,居然做成功了,这里把步骤记录下来,方便以后查看. 1.首先在 ...

  4. SharePoint 2013 REST 服务使用简介

    1.创建测试使用列表”REST Demo”,插入一些测试数据,如下图: 2.添加内容编辑器,并且添加脚本引用以及HTML代码,如下图: Result的Div为显示结果使用,input标签触发REST服 ...

  5. [Android]异步加载图片,内存缓存,文件缓存,imageview显示图片时增加淡入淡出动画

    以下内容为原创,欢迎转载,转载请注明 来自天天博客:http://www.cnblogs.com/tiantianbyconan/p/3574131.html  这个可以实现ImageView异步加载 ...

  6. mac jdk 6设置

    新装的mac 系统10.10 ,jdk是1.8,因为一些工具要使用 jdk 6,以下是设置过程 查看版本 java -version 查看java是再哪:在/usr/bin/java whereis ...

  7. 【Android疑难杂症】GridView动态设置Item的宽高导致第一个Item不响应或显示不正常的问题

    前言 这个问题在之前做一个盒子项目时遇到过,最近又遇到了,使用GridView遇到的非常奇葩的问题,这里记录分享一下. 声明 欢迎转载,但请保留文章原始出处:)  博客园:http://www.cnb ...

  8. 【Android】Mac安装EasyTether导致无法识别设备的问题

    正文 想让手机走PC网络,然后抓包,于是搜索一番后安装了一个叫EasyTether的软件.还没来得及测试,就忙着写代码去了,重启MAC以后就发现连不上手机了,一开始并没有怀疑是 EasyTether的 ...

  9. android 数据存储Ⅰ

    本章讲述在Android开发中,简单的数据存储.涉及知识主要是SharedPreferences,及多页面切换ViewPager. 1.功能需求 做一个小应用.启动的时候有左右引导图.只有第一次启动时 ...

  10. 百度编辑器ueditor 异步加载时,初始化没办法赋值bug解决方法

    百度编辑器ueditor 异步加载时,初始化没办法赋值bug解决方法 金刚 前端 ueditor 初始化 因项目中使用了百度编辑器——ueditor.整体来说性能还不错. 发现问题 我在做一个编辑页面 ...