用戶配置並將壹個Hadoop作業提到Hadoop框架中,Hadoop框架會把這個作業分解成壹系列map tasks 和reduce tasks。Hadoop框架負責task分發和執行,結果收集和作業進度監控。
下圖給出了壹個作業從開始執行到結束所經歷的階段和每個階段被誰控制(用戶 or Hadoop框架)。
下圖詳細給出了用戶編寫MapRedue作業時需要進行那些工作以及Hadoop框架自動完成的工作:
在編寫MapReduce程序時,用戶分別通過InputFormat和OutputFormat指定輸入和輸出格式,並定義Mapper和Reducer指定map階段和reduce階段的要做的工作。在Mapper或者Reducer中,用戶只需指定壹對key/value的處理邏輯,Hadoop框架會自動順序叠代解析所有key/value,並將每對key/value交給Mapper或者Reducer處理。表面上看來,Hadoop限定數據格式必須為key/value形式,過於簡單,很難解決復雜問題,實際上,可以通過組合的方法使key或者value(比如在key或者value中保存多個字段,每個字段用分隔符分開,或者value是個序列化後的對象,在Mapper中使用時,將其反序列化等)保存多重信息,以解決輸入格式較復雜的應用。
2.2 用戶的工作
用戶編寫MapReduce需要實現的類或者方法有:
(1) InputFormat接口
用戶需要實現該接口以指定輸入文件的內容格式。該接口有兩個方法
public interface InputFormat<K, V> {
InputSplit[] getSplits(JobConf job, int numSplits) throws IOException; RecordReader<K, V> getRecordReader(InputSplit split, JobConf job, Reporter reporter) throws IOException;}
其中getSplits函數將所有輸入數據分成numSplits個split,每個split交給壹個map task處理。getRecordReader函數提供壹個用戶解析split的叠代器對象,它將split中的每個record解析成key/value對。
Hadoop本身提供了壹些InputFormat:
(2)Mapper接口
用戶需繼承Mapper接口實現自己的Mapper,Mapper中必須實現的函數是
void map(K1 key,
V1 value,
OutputCollector<K2,V2> output,
Reporter reporter
) throws IOException
其中,<K1 V1>是通過Inputformat中的RecordReader對象解析處理 的,OutputCollector獲取map()的輸出結果,Reporter保存了當前task處理進度。
Hadoop本身提供了壹些Mapper供用戶使用:
(3)Partitioner接口
用戶需繼承該接口實現自己的Partitioner以指定map task產生的key/value對交給哪個reduce task處理,好的Partitioner能讓每個reduce task處理的數據相近,從而達到負載均衡。Partitioner中需實現的函數是
getPartition(? K2? key, V2 value, int numPartitions)
該函數返回<K2 V2>對應的reduce task ID。
用戶如果不提供Partitioner,Hadoop會使用默認的(實際上是個hash函數)。
(4)Combiner
Combiner使得map task與reduce task之間的數據傳輸量大大減小,可明顯提高性能。大多數情況下,Combiner與Reducer相同。
(5)Reducer接口
用戶需繼承Reducer接口實現自己的Reducer,Reducer中必須實現的函數是
void reduce(K2 key,
Iterator<V2> values, OutputCollector<K3,V3> output, Reporter reporter) throws IOException
Hadoop本身提供了壹些Reducer供用戶使用:
(6)OutputFormat
用戶通過OutputFormat指定輸出文件的內容格式,不過它沒有split。每個reduce task將其數據寫入自己的文件,文件名為part-nnnnn,其中nnnnn為reduce task的ID。
3. 分布式緩存
Haoop中自帶了壹個分布式緩存,即DistributedCache對象,方便map task之間或者reduce task之間***享壹些信息,比如某些實際應用中,所有map task要讀取同壹個配置文件或者字典,則可將該配置文件或者字典放到分布式緩存中。
4.?多語言編寫MapReduce作業
Hadoop采用java編寫,因而Hadoop天生支持java語言編寫作業,但在實際應用中,有時候,因要用到非java的第三方庫或者其他原因,要采用C/C++或者其他語言編寫MapReduce作業,這時候可能要用到Hadoop提供的壹些工具。
如果妳要用C/C++編寫MpaReduce作業,可使用的工具有Hadoop Streaming或者Hadoop Pipes。
如果妳要用Python編寫MapReduce作業,可以使用Hadoop Streaming或者Pydoop。
如果妳要使用其他語言,如shell,php,ruby等,可使用Hadoop Streaming。
關於Hadoop Streaming編程,可參見我的這篇博文:《Hadoop Streaming編程》