6.824 Lab1-MapReduce

MapReduce 框架

MapReduce框架用于大量数据的并行运算,框架的使用者只需要实现自己的Map和Reduce函数就可以使用。例如实验中进行的词频统计

func Map(filename string, contents string) []mr.KeyValue {
	// function to detect word separators.
	ff := func(r rune) bool { return !unicode.IsLetter(r) }

	// split contents into an array of words.
	words := strings.FieldsFunc(contents, ff)

	kva := []mr.KeyValue{}
	for _, w := range words {
		kv := mr.KeyValue{w, "1"}
		kva = append(kva, kv)
	}
	return kva
}

func Reduce(key string, values []string) string {
	// return the number of occurrences of this word.
	return strconv.Itoa(len(values))
}

Map函数使用一个key和一个value作为参数。入参中,key是输入文件的名字,通常会被忽略,因为我们不太关心文件名是什么,value是输入文件的内容。Map函数的输出是一个key-value对的列表。

Reduce函数的入参是某个特定key的所有实例(Map输出中的key-value对中,出现了一次特定的key就可以算作一个实例)。所以Reduce函数也是使用一个key和一个value作为参数,其中value是一个数组,里面每一个元素是Map函数输出的key的一个实例的value。在词频统计中,只需要统计单词的数量,因此Reduce只需要统计传入参数的长度。

而实验中要做的就是能够为Map和Reduce函数提供正确的输入并将输出保存到输出文件,并保证任务并行。

Worker

首先完成Worker的Map和Reduce任务的执行。

Map任务只需读取对应的文件内容,将内容传递给Map()函数即可。重点是处理输出,需要将输出进行排序并写入到对应的中间文件,以便后续Reduce处理。为了有序高效的处理,还需要使用hash将不同的key放入不同的桶中,实验要求NReduce=10,即桶的数量为10,Reduce阶段时,会以桶为单位进行处理。所以每个Map任务执行过后,会输出NReduce个中间文件。

Reduce任务,每个任务处理指定的桶,根据桶编号读取所有对应的中间文件,执行Reduce函数并写入到输出文件。

func Worker(mapf func(string, string) []KeyValue,
	reducef func(string, []string) string) {
	log.Printf("Worker started\n")
	for {
		taskReply := TaskReply{}
		CallTask(&TaskArgs{}, &taskReply)
		switch taskReply.TaskType {
		case TaskMap:
			Map(taskReply.MapInfo, mapf)
			finishMapArgs := FinishArgs{
				TaskId:   taskReply.MapInfo.TaskId,
				TaskType: TaskMap,
			}
			finishMapReply := FinishReply{}
			CallFinish(&finishMapArgs, &finishMapReply)
		case TaskReduce:
			Reduce(taskReply.ReduceInfo, reducef)
			finishReduceArgs := FinishArgs{
				TaskId:   taskReply.ReduceInfo.TaskId,
				TaskType: TaskReduce,
			}
			finishReduceReply := FinishReply{}
			CallFinish(&finishReduceArgs, &finishReduceReply)
		case TaskWait:
			time.Sleep(time.Second)
		case TaskExit:
		default:
			log.Printf("Worker exiting\n")
			return
		}
	}

}

Coordinator

Coordinator发布给Worker的任务要包含有任务类型,Worker需要根据不同的任务类型,选择不同的操作。要注意的是如果暂时没有任务,Worker需要等待一段时间再向Coordinator获取任务,这里的等待时间不宜过长,否则可能会导致并行测试失败,即所有任务都被一个Worker完成了,另一个Worker还在sleep

Coordinator负责任务的发布,因此数据结构中需要有一个数组来记录所有需要处理的文件。可以使用channel来进行任务的发布,任务发布协程和负责超时重传的定时器均可以向channel中写入任务(生产)。在收到Worker的任务请求时从channel中接收任务并发送即可(消费),若channel中暂时没有任务则将任务类型设为等待(这里可以使用select来分别处理这两种情况)。

Coordinator同时还需要一个定时器数组来保存每个任务的定时器,以便在收到Worker的任务完成通知时,取消超时任务。

Coordinator也需要一个状态字段,来记录当前阶段是Map还是Reduce以便发布对应的任务。

同时使用finishNum来记录当前已经完成的任务数,当任务全部完成时切换状态。

使用finishNum时,遇到了一个问题,当任务超时会调度新的Worker来执行,这时原本负责的Worker执行结束通知Coordinator,finishNum数量加一。但是新的Worker会再次重复执行该任务,完成后,finishNum再次加一。这显然是不允许的。所以需要一个数组来记录每个任务的状态,Coordinator收到任务完成通知时,检查该任务的状态,若本来就是已完成,则不会对finishNum加一,防止重复任务执行带来的影响。

另外对于fiishNum和状态字段,需要加锁来进行保护,避免同时修改。

Coordinator最终的数据结构如下

type Coordinator struct {
	mu           sync.Mutex
	files        []string
	taskStatus   []bool
	finishNum    int
	taskCh       chan int
    //通知任务发布协程,开始发送下一阶段任务
	stateCh      chan struct{}
	nReduce      int
	status       int
	timeout      time.Duration
	taskTimeouts []*time.Timer
}

另外Coordinator在任务全部完成退出时,可以先sleep,让Worker先退出。

MIT 6.824 课程的 Lab1 是关于 Map 的实现,这里单介绍一下实现过程。 MapReduce 是一种布式计算模型,它可以用来处理大规模数据集。MapReduce 的核心想是将数据划分为多个块,每个块都可以在不同的节点上并行处理,然后将结果合并在一起。 在 Lab1 中,我们需要实现 MapReduce 的基本功能,包括 Map 函数、Reduce 函数、分区函数、排序函数以及对作业的整体控制等。 首先,我们需要实现 Map 函数。Map 函数会读取输入文件,并将其解析成一系列键值对。对于每个键值对,Map 函数会将其传递给用户定义的 Map 函数,生成一些新的键值对。这些新的键值对会被分派到不同的 Reduce 任务中,进行进一步的处理。 接着,我们需要实现 Reduce 函数。Reduce 函数接收到所有具有相同键的键值对,并将它们合并成一个结果。Reduce 函数将结果写入输出文件。 然后,我们需要实现分区函数和排序函数。分区函数将 Map 函数生成的键值对映射到不同的 Reduce 任务中。排序函数将键值对按键进行排序,确保同一键的所有值都被传递给同一个 Reduce 任务。 最后,我们需要实现整个作业的控制逻辑。这包括读取输入文件、调用 Map 函数、分区、排序、调用 Reduce 函数以及写入输出文件。 Lab1 的实现可以使用 Go 语言、Python 或者其他编程语言。我们可以使用本地文件系统或者分布式文件系统(比如 HDFS)来存储输入和输出文件。 总体来说,Lab1 是一个比较简单的 MapReduce 实现,但它奠定了 MapReduce 的基础,为后续的 Lab 提供了良好的基础。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值