talent-plan tidb 部分個人題解-week 2
Week 2 的問題是 map reduce 優化,說實話,這周的示例程式碼寫的不怎麼樣,不知道為什麼都是同一個人的程式碼,同一個引數的名字還換來換去,讀起來會浪費一些時間。一些縮寫也讓人比較困惑,比如 fs,bs,別人要稍微思考一下才能看懂這是什麼東西,用 fileList 或者 bufferList 顯然更好啊,可能樣例程式碼的人是寫 acm 出身,比較喜歡趕時間。雖然 Go 的 runtime 程式碼裡也經常這麼幹,汗。
吐槽就到這裡。題目是想讓你先把 example 補全,能執行,然後再去實現自己的 map reduce 方法。要補兩個地方,第一個是 run 函式裡的 reduce phase,另一個是 worker 函式的 reduce phase 的具體實現工作。這裡提示比較少,不過看著函式名和程式碼上下文花半個小時可能就猜出來怎麼做了,嗯。
run 裡的 reduce phase 組裝一下引數,並且和上面 map phase 差不多,拼出相應的 task 結構,然後提交任務給worker 就行:
// reduce phase startTime := time.Now() tasks = make([]*task, 0, nReduce) for i := 0; i < nReduce; i++ { t := &task{ dataDir:dataDir, jobName:jobName, phase:reducePhase, taskNumber: i, nReduce:nReduce, nMap:nMap, reduceF:reduceF, } t.wg.Add(1) tasks = append(tasks, t) go func() { c.taskCh <- t }() } // 任務收集階段,需要把最終 merge 到的 filename 傳出 // 這裡稍微有一些疑惑 notifyList := []string{} for _, t := range tasks { t.wg.Wait() mergefileName := mergeName(t.dataDir, t.jobName, t.taskNumber) notifyList = append(notifyList, mergefileName) } du := time.Now().Sub(startTime) fmt.Println("reduce time: ", du) notify <- notifyList
這個 notifyList 的操作真是猜的,沒有任何描述,外部的 example test 寫的也比較奇怪,inputfiles 鬼知道在說什麼啊。
然後是 worker 裡的程式碼就參考這個commit 吧。
補完 example,跑 test 直接超過了 10min,test 被 kill 掉了。。汗,感覺出題人這裡還是出的有點問題,example 階段本意是隨便補補,能跑通就算過的。現在在稍微挫一點的電腦上,這個 test 10 分鐘根本跑不完。在自己家牛逼的 2018 mbp 上試了一下 4 分鐘就跑完了。出題人的電腦果然是好電腦,嗯。
原本 map reduce 兩個階段採用的序列化是標準庫中的 encoding/json,用火焰圖看 cpuprofile 可以看到基本 40+ 都在 json.Marshal,json.Unmarshal。在不修改序列化方式的前提下,最簡單的優化就是換個庫,用我們陶師傅寫的 jsoniter。
跑跑 benchmark,嗯,快了幾分鐘。但是 cpu 消耗的大頭還是在 json 編碼解碼上,用最粗暴的簡單字串連線,可以嘗試一下這裡的效能優化極限,基本可以把原來的整體時間縮短一半。仔細想想 apache 生態下那些大資料計算框架,基本都有特殊的協議(avro、pb 什麼的)對資料進行壓縮,所以用 json 之類的會慢倒也不奇怪了。到達優化極限之後,比較突出的問題就是 runtime.slicebytetoarray 之類的問題了,這明顯是因為 map reduce 框架和 mapF 以及 reduceF 的函式簽名中資料型別不匹配導致資料總是要從 string 轉成 []byte,從 []byte 轉成string 而帶來的問題,優化也比較簡單,能用 []byte 的地方全用 []byte 就行了,減少資料型別轉換。
題目還要求對 mapF 和 reduceF 的實現進行優化,round1 其實沒什麼好優化的,題目裡提到 case 的資料本身可能有傾斜,但實際經過實驗,在 round1 加入 map 輸出 url 和統計數,確實對資料傾斜有極大的優化,但因為 map 的問題,在傾斜不嚴重的資料集上跑反而更慢了。汗。所以還是要稍微權衡一下。round2 的執行時間本來也不太長,可以在 map 階段直接對每個 map 任務提前求 top 10,這樣 reduce 階段需要進行的任務就輕了很多,實際優化效果很好,能把 reduce 從幾百毫秒優化到幾 ms 甚至幾十 us,但沒啥用,round2 的 reduce 階段在全域性時間中的佔比非常少。
這周的 homework 做完還是有點虛的。。可能是需要做之前先看看 map reduce 的論文,就不會在理解這個框架上有磕絆了?大概吧。