1. 程式人生 > 程式設計 >MIT6.824 Lab1 程式碼

MIT6.824 Lab1 程式碼

實驗專案由純 Go 語言開發。程式碼框架已經搭好並提供了各種條件的測試用例來模仿分散式場景下的意外事件。最終目的是在指定修改的地方 coding 並通過測試用例,同時需要關注時間消耗,一定程度上效能做到最優。 ### 熟悉專案 在 master_rpc.go 裡面啟動 master 提供 RPC 服務用來和 workers 之間用通訊。每個 worker 都會在 master.go 中的 Register() 的註冊服務。 MapReduce 會從 master.go 中的 run() 啟動。這個方法的簽名為

func (mr *Master) run(
        jobName string
,files []string,nreduce int,schedule func(phase jobPhase)
,finish func(),)
{} 複製程式碼

整個實驗分成了 sequential 和 parallel 兩種模式。最大的區別在於排程函式的實現方式,實驗在sequential 已經實現了序列的排程,而後面將要自己實現並行的排程器,也就是 run 方法中的 schedule 需要自己寫更快的。

Part I: Map/Reduce input and output

MapReduce 的基本輸入輸出

  1. 給 map task 的輸出進行分片 doMap 方法中的 mapF 會產生一個 key-value 陣列。需要做的就是把這個陣列按照裡面 key 轉換成比較均勻的的 nReduce 個由 key-value 組成的小陣列並寫到檔案當中。這裡有個要點,如果採用直接按順序劃分。比如說如果陣列的長度是 m,第一組是 0..m/nReduce-1,第二組是 m/nReduce..m/nReduce*2-1 直到劃分完。這樣做有個問題就是需要把相同 key 放到一組便於後面的 Reduce 操作。所以目前看來做 Hash 然後 mod nReduce 這樣既可以比較均勻劃分檔案,同時又可以讓相同 key 的在一個檔案裡面。

  2. 給 reduce task 組裝所有的輸入 讀取 1 產生的中間檔案。相同的 key 可以把對應的 value 組合起來產生多個 key-values 的資料結構。隨後對這樣的資料結構進行按照 key 排序並寫到 reduce 的輸出檔案當中。

通過 1,2 可以確定最終會產生 nMap * nReduce 箇中間檔案。

Part II: Single-worker word count

單機版的 word count

相對於 PartI 其中的 mapF 和 reduceF 需要按照當前使用者邏輯來實現。mapF 需要做的就是把出現過的單詞都轉換成 word-count 這樣的 key-value 結構。reduceF 只需要對出現過的內容做一個獲取長度就結束了。

Part III: Distributing MapReduce tasks

分散式版的 word count

在完成了 Part I 和 Part II 之後應該就對單機版的 word count 如何實現比較清晰了。在分散式場景下,workers 到 master 之間會用 rpc 的方式通訊。 workers 會充分利用計算機的多核實現併發。按照要求是需要實現排程器 schedule.go 中的 schedule() 方法。按照 sequential 的模式,排程器會被傳入當前的階段是 map 還是 reduce,並且只會被傳入一次。按照題目前面給的要求,輸入檔案的個數決定了 map worker 的個數。隨後 map worker 執行的同時,reduce worker 也在同時執行。那麼其實就是改造成了用 goroutine 來 rpc 呼叫對應的使用者方法,並用 waitGroup 來記錄完成情況。

Part IV: Handling worker failures

容錯 測試程式碼會讓部分 worker 出現失效,這個失效可以理解為不論當前工作完成多少,即使是完成了也有可能返回 false。這也就意味著可能出現多個 workers 做了同樣的任務。所以原則上,需要保證任務 idempotent,從函式式的角度而言,本身作為一個函式就應該是相同輸入相同輸出的狀態。為實現容錯,還需要實現重試機制。在多個 goroutine 同時跑的時候,最簡單的方法實現重試就是附加一個 retryChan 用來存放記錄重試任務。

原始碼