看了許久的代碼,把map的流程熟悉了下,不追求最准確的理解,記錄下來以免忘記。
對於JobTracker和TaskTracker等大層面有控制和通訊的代碼暫時不表
map過程俗氣的先上一個圖:
map這一端基本是這樣的流程:
input split分解成map個數量的部分輸入==》RecordReader分解成Mapper需要的(key,value)記錄==》執行map方法==》執行的結果起初在內存當中==》
當內存記錄過多的時候spill到硬盤上面,如果有分區(Partitioner的話),spill的文件會記錄分區的信息,單個spill文件首先按分區排序,然后按key排序==》
如果有多個spill文件則需要merge成一個大文件,是對spill文件的歸並排序.
input split部分:
通過實現InputFormat抽象類中的兩個方法就能達到效果。
getSplits(JobContext context),實現此方法,實現輸入的切分,切分成map個數量的獨立輸入,這樣每一個split都對應一個map
createRecordReader(InputSplit split,TaskAttemptContext context),實現此方法可以從split中讀取到map需要的(key,value)對,當然類型需要和map方法的key,value參數類型一致
map方法:
map(KEYIN key, VALUEIN value, Context context),是對外提供的主要方法,一般只要實現此方法就可以實現MapReduce程序中的map過程,對輸入(key,value)處理完之后,通過Context的方法寫入到內存當中
spill,sort,merge:
當map方法被執行的次數過多,內存肯定是不夠,所以此時需要持久化到硬盤里面去,此時就是spill的過程,在spill之前呢,其實是需要進行排序的也就是sort過程,sort過程首先按照分區進行排序,這樣每個分區的數據排在一起,因為一個分區的數據是一個reduce過程的輸入數據(確切的說是部分數據,因為map是有很多節點的,所有節點的分區數據之和才是reduce的輸入),之后還需要按照key進行排序(每個分區之內的key),這樣每個分區里面的key是有序的。排序以后就spill到硬盤當中。
當map過程都結束以后,spill到硬盤的文件數最起碼有一個,一般都是多個,這個時候就需要merge了,merge的時候是個典型的歸並排序,因為每個spill文件都是按照分區,然后按照分區中的key排序,所以merge過程是一個個分區的key進行歸並排序的。
其他:
一般實現一個mapreduce程序的map端需要做的事情有:
實現InputFormat,實現RecordReader,實現InputSplit,實現Mapper的map方法,如果有分區的話就實現Partitioner。對於性能方面的問題,另起一篇說明。