凡事预则立,不预则废 – 《礼记·中庸》
Coordinator 流程:
- 读入:Coordinator接收传入文件参数。每个文件都作为独立的文件。 M M M 等于文件数量。然后这些任务都用Task结构体保存。Task记录任务的文件名,id(独立生成),类型(Map or Reduce)以及状态(completed,in-progress,idle)。这些Task会被生产到一个channel中,后续所有的任务调度都通过Channel来实现。
- MapStage :主要是分发各种MapTask。使用一个数组记录所有in-progress或completed的map task。
- MapStage下收到请求,任务分发:Worker请求Coordinator分发任务。Coordinator收到请求时,worker会返回上一个任务的执行情况。如果上一个任务不为空,则将其生产的文件记录保存为一个新的reduce task。然后我们对in-progress和completed的所有task进行扫描,有执行中但距离上次执行时间已过去20s的任务,我们认为这个任务出了问题需要重新生产到channel中。当channel中无法读取数据,且数组中无in-progress任务的时候,我们认为任务已完成,可进入Reduce状态。若有,则等待,令worker sleep个5s再看看。
- ReduceStage :这个时候我们要执行ReduceTask了。跟MapStage类似,用一个新的数组记录所有in-progress或completed的reduce task。
- ReduceStage下收到请求,任务分发:跟MapStage的流程类似。最后如果处理完成,channel没有Task可读且数组内无in-progress任务,则直接跳转到结束状态。
type Task struct {
id int
taskType int // 0 map 1 reduce -1 wait
status int //0 idle 1 in-progress 2 completed
file string // task's input path
dispatchTime time.Time
}
var mapOngoingTasks []*Task
var reduceOngoingTasks []*Task
var taskReady chan *Task
var machines = 0
Worker
请求机器的ID和任务
func AcquireId(resp *AcquireIdResp)
type AcquireIdResp struct {
Id int
}
func AcquireTask(req *AcquireTaskReq, resp *AcquireTaskResp)
type AcquireTaskReq struct {
TaskType int // 0 map 1 reduce -1 wait -2 quit
LastTaskId int // -1 wait
LastOutputPath string // default ""
}
type AcquireTaskResp struct {
TaskType int // 0 map 1 reduce -1 wait -2 quit
TaskId int // -1 wait
InputPath string // default ""
}
完整代码会公布在GitHub中
待填坑