標籤:http io ar os 使用 sp for 檔案 資料
Mapper的處理過程:
1.1. InputFormat 產生 InputSplit,並且調用RecordReader將這些邏輯單元(InputSplit)轉化為map task的輸入。其中InputSplit是map task處理的最小輸入單元的邏輯表示。
1.2. 在用戶端代碼中調用Job類來設定參數,並執行在hadoop叢集的上的MapReduce程式。
1.3. Mapper類在Job中被執行個體化,並且通過MapContext對象來傳遞參數設定。可以調用Job.getConfiguration().set(“myKey”, “myVal”)來設定參數。
1.4. Mapper的run()方法調用了自身的setup()來設定參數。
1.5. Mapper的run()方法調用map(KeyInType, ValInType, Context)方法來依次處理InputSplit中輸入的key/value資料對。並且可以通過Context參數的Context.write(KeyOutType, ValOutType)方法來發射處理的結果。使用者程式還可以用Context來設定狀態資訊等。同時,使用者還可以用Job.setCombinerClass(Class)來設定Combiner,將map產生的中間態資料在Mapper本地進行匯聚,從而減少傳遞給Reducer的資料。
1.6. Mapper的run()方法調用cleanup()方法。
一些說明:
所有的中間結果都會被MapReduce架構自動的分組,然後傳遞給Reducer(s)去產生最後的結果。使用者可以通過Job.setGroupingComparatorClass(Class)來設定Comparator。如果這個Comparator沒有被設定,那麼所有有一樣的key的資料不會被排序。
Mapper的結果都是被排序過的,並被劃分為R個區塊(R是Reducer的個數)。使用者可以通過實現自訂的Partitioner類來指定哪些資料被劃分給哪個Reducer。
中間態的資料往往用(key-len, key, value-len, value)的簡單格式儲存。使用者程式可以指定CompressionCodec來壓縮中間資料。
Map的數目由輸入資料的總大小決定。一般來說,一個計算節點10-100個map任務有較好的並行性。如果cpu的計算量很小,那麼平均每個計算節點300個map任務也是可以的。但是每個任務都是需要時間來初始化的,因此每個任務不能劃分的太小,至少也要平均一個任務執行個一分鐘。可以通過mapreduce.job.maps參數來設定map的數目。更進一步說,任務的數量是有InputFormat.getSplits()方法來控制的,使用者可以重寫這個方法。
------------------------------------------------------------------------------------------------------------------------------------------------
Reducer主要分三個步驟:
1. Shuffle洗牌
這步驟是Reducer從相關的Mapper節點擷取中間態的資料。
2. Sort排序
在洗牌的同時,Reducer對擷取的資料進行排序。在這個過程中,可以用Job.setGroupingComparatorClass(Class)來對同一個key的資料進行Secondary Sort二次排序。
3. Reduce
Reduce的調用順序和Map差不多,也是通過run()方法調用setup(),reduce(),cleanup()來實現的。Reducer輸出的資料是沒有經過排序的。
Reduce 的數目可以通過Job.setNumReduceTasks(int)來設定。一般來說,Reduce的數目是節點數的0.95到1.75倍。
Reduce的數目也可以設定為0,那麼這樣map的輸出會直接寫到檔案系統中。
Reduce中還可以使用Mark-Reset的功能。簡而言之就是可以在遍曆map產生的中間態的資料的時候可以進行標記,然後在後面適當的時候用reset回到最近標記的位置。當然這是有一點限制的,如下面的例子,必須自己在Reduce方法中對reduce的Iterator重新new 一個MarkableIterator才能使用。
public void reduce(IntWritable key, Iterable<IntWritable> values, Context context) throws IOException, InterruptedException {
MarkableIterator<IntWritable> mitr = new MarkableIterator<IntWritable>(values.iterator());
// Mark the position
mitr.mark();
while (mitr.hasNext()) {
i = mitr.next();
// Do the necessary processing
}
// Reset
mitr.reset();
// Iterate all over again. Since mark was called before the first
// call to mitr.next() in this example, we will iterate over all
// the values now
while (mitr.hasNext()) {
i = mitr.next();
// Do the necessary processing
}
}
3. Partitioner
Partitioner 對map輸出的中間態資料按照reduce的數目進行分區,一般通過hash來進行劃分。預設的實現是HashPartitioner。
4. Reporting Progress
MapReduce程式可以通過mapper或者reducer的Context來彙報應用程式的狀態。
5. Job
當我們在寫MapReduce程式的時候,通常,在main函數裡。建立一個Job對象,設定它的JobName,然後配置輸入輸出路徑,設定我們的Mapper類和Reducer類,設定InputFormat和正確的輸出類型等等。然後我們會使用job.waitForCompletion()提交到JobTracker,等待job運行並返回,這就是一般的Job設定過程。JobTracker會初始化這個Job,擷取輸入分區,然後將一個一個的task任務分配給TaskTrackers執行。TaskTracker擷取task是通過心跳的傳回值得到的,然後TaskTracker就會為收到的task啟動一個JVM來運行。
Job其實就是提供配置作業、擷取作業配置、以及提交作業的功能,以及跟蹤作業進度和控製作業。Job類繼承於JobContext類。JobContext提供了擷取作業配置的功能,如作業ID,作業的Mapper類,Reducer類,輸入格式,輸出格式等等,它們除了作業ID之外,都是唯讀。 Job類在JobContext的基礎上,提供了設定作業配置資訊的功能、跟蹤進度,以及提交作業的介面和控製作業的方法。
一個Job對象有兩種狀態,DEFINE和RUNNING,Job對象被建立時的狀態時DEFINE,若且唯若Job對象處於DEFINE狀態,才可以用來設定作業的一些配置,如Reduce task的數量、InputFormat類、工作的Mapper類,Partitioner類等等,這些設定是通過設定配置資訊conf來實現的;當作業通過submit()被提交,就會將這個Job對象的狀態設定為RUNNING,這時候作業以及提交了,就不能再設定上面那些參數了,作業處於調度運行階段。處於RUNNING狀態的作業我們可以擷取作業、maptask和reduce task的進度,通過代碼中的*Progress()獲得,這些函數是通過info來擷取的,info是RunningJob對象,它是實際在啟動並執行作業的一組擷取作業情況的介面,如Progress。
在waitForCompletion()中,首先用submit()提交作業,然後等待info.waitForCompletion()返回作業執行完畢。verbose參數用來決定是否將運行進度等資訊輸出給使用者。submit()首先會檢查是否正確使用了new API,這通過setUseNewAPI()檢查舊版本的屬性是否被設定來實現的,接著就connect()串連JobTracker並提交。實際提交作業的是一個JobClient對象,提交作業後返回一個RunningJob對象,這個對象可以跟蹤作業的進度以及含有由JobTracker設定的作業ID。
getCounter()函數是用來返回這個作業的計數器列表的,計數器被用來收集作業的統計資訊,比如失敗的map task數量,reduce輸出的記錄數等等。它包括內建計數器和使用者定義的計數器,使用者自訂的計數器可以用來收集使用者需要的特定資訊。計數器首先被每個task定期傳輸到TaskTracker,最後TaskTracker再傳到JobTracker收集起來。這就意味著,計數器是全域的。
http://www.aboutyun.com/thread-7066-1-1.html
關於Mapper、Reducer的個人總結(轉)