天天看點

HadoopHadoop

使用者可以在不了解分布式底層細節的情況下,開發分布式程式。充分利用叢集的威力進行高速運算和存儲。

Hadoop的架構最核心的設計就是:HDFS和MapReduce。HDFS為海量的資料提供了存儲,則MapReduce為海量的資料提供了計算。

官網相關介紹:

What Is Apache Hadoop?

The Apache Hadoop project develops open-source software for reliable, scalable, distributed computing.

The Apache Hadoop software library is a framework that allows for the distributed processing of large data sets across clusters of computers using simple programming models. It is designed to scale up from single servers to thousands of machines, each offering local computation and storage. Rather than rely on hardware to deliver high-availability, the library itself is designed to detect and handle failures at the application layer, so delivering a highly-available service on top of a cluster of computers, each of which may be prone to failures.

The project includes these modules:

Hadoop Common: The common utilities that support the other Hadoop modules.

Hadoop Distributed File System (HDFS): A distributed file system that provides high-throughput access to application data.

Hadoop YARN: A framework for job scheduling and cluster resource management.

Hadoop MapReduce: A YARN-based system for parallel processing of large data sets.

Other Hadoop-related projects at Apache include:

一、MapReduce理論基礎

每個MapReduce job都是Hadoop用戶端想要執行的一個工作單元,它一般由輸入資料、MapReduce程式和配置資訊組成,而Hadoop會把每個job分隔成兩類任務(task):map任務和reduce任務。在Hadoop叢集中有兩類節點來執行兩類job程序的執行

1.1 大資料處理

任何基礎業務包含了收集、分析、監控、過濾、搜尋或組織web内容的公司或組織都面臨着所謂的“大資料”問題:“web規模”處理即海量資料處理的代名詞。社交類網站的興起也使得這些組織面臨着另一個問題:使用者行為資料分析,這涉及到通過日志檔案記錄使用者的對web頁面浏覽、點選、停留時長等,而後對日志檔案中的大量資料進行分析以支援進行合理、正确的商業決策。

那麼,大資料處理究竟意味着對多大規模的資料進行處理?一個簡單的例子:Google在2004年平均每天利用MapReduce處理100GB的資料,到2008年平均每天處理的資料已經達到20PB;2009年,Facebook的資料量達到2.5PB,且以每天15TB的速度在增長。PB級别的資料集正變得越來越常見,大資料時代的到來已然是不争的事實,密集資料處理也正迅速成為現實需求。

大資料問題的處理需要以與傳統資料處理方式所不同的方法去實作,這正是MapReduce思想得以大放光彩的核心所在。MapReduce在實作大資料處理上有着多個基礎理論思想的支撐,然而這些基礎理論甚至實作方法都未必是MapReduce所創,它們隻是被MapReduce采用獨特的方式加以利用而已。

(1) 向外擴充(Scale out)而非向上擴充(Scale up):大資料的處理更适合采用大量低端商業伺服器(scale out)而非少量高端伺服器(scale up)。後者正是向上擴充的系統性能提升方式,它通常采用有着SMP架構的主機,然而有着大量的CPU插槽(成百上千個)及大量的共享記憶體(可以多達數百GB)的高端伺服器非常昂貴,但其性能的增長卻非線性上升的,是以成本效益很一般。而大量的低端商業伺服器價格低廉、易于更換和伸縮等特性有效避免了向上擴充的敝端。

(2)假設故障很常見(Assume failures are common):在資料倉庫架構級别,故障是不可避免且非常普遍的。假設一款伺服器出故障的平均機率為1000天1次,那麼10000台這種伺服器每天出錯的可能性将達到10次。是以,大規模向外擴充的應用場景中,一個設計優良且具有容錯能力的服務必須能有效克服非常普遍的硬體故障所帶來的問題,即故障不能導緻使用者應用層面的不一緻性或非确定性。MapReduce程式設計模型能通過一系列機制如任務自動重新開機等健壯地應付系統或硬體故障。

(3)将處理移向資料(Move processing to the data):傳統高性能計算應用中,超級計算機一般有着處理節點(processing node)和存儲節點(storage node)兩種角色,它們通過高容量的裝置完成互聯。然而,大多數資料密集型的處理工作并不需要多麼強大的處理能力,于是把計算與存儲互相分開将使得網絡成為系統性能瓶頸。為了克服計算如此類的問題,MapReduce在其架構中将計算和存儲合并在了一起,并将資料處理工作直接放在資料存儲的位置完成,隻不過這需要分布式檔案系統予以支撐。

(4)順序處理資料并避免随機通路(Process data sequentially and avoid random access):大資料處理通常意味着海量的數量難以全部載入記憶體,因而必須存儲在磁盤上。然而,機械式磁盤尋道操作的先天性缺陷使得随機資料通路成為非常昂貴的操作,是以避免随機資料通路并以順序處理為目的完成資料組織成為亟待之需。固态磁盤雖然避免了機械磁盤的某此缺陷,然而其高昂的價格以及并沒有消除的随機通路問題仍然無法帶來性能上的飛躍發展。MapReduce則主要設計用來在海量資料集上完成批處理操作,即所有的計算被組織成較長的流式處理操作,以延遲換取較大的吞吐能力。

(5)向程式員隐藏系統級别的細節(Hide system-level details from the application developer):

(6)無縫擴充(Seamless scalability):

1.2 MapReduce和大資料問題

海量資料處理的核心思想無非是将一個較大的問題進行“分割包圍、逐個殲滅”。然而其難點和關鍵點在于如何将一個大的問題分分割成多個可以分别在不同的CPU上或不同的主機上進行處理的獨立小問題,而且這些獨立進行處理的小問題所産生的中間結果又該如何合并成最終結果并予以輸出。是以,看似簡單的化整為零的處理思想卻不得不面臨如下的難題:

(1) 如何将大問題分割為小任務?進一步地,如何将大問題分解為可以并行處理的小任務?

(2) 如何将分解好的小任務派送給分布式系統中的某主機且是較為适合解決此問題的主機上的worker完成處理?

(3) 如何保證某worker擷取所需的資料?

(4) 如何協調不同worker之間進行同步?

(5) 如何将某worker的部分結果共享給其它需要此結果的worker?

(6) 如何在出現軟體或硬體故障時仍然能保證上述工作的順利進行?

在傳統的并行或分布式程式設計模型中,程式員不得不顯式地解決上述的部分甚至是全部問題,而在共享記憶體程式設計中,程式員需要顯式地協調對共享資料結構的如互斥鎖的通路、顯式地通過栅(barrier)等裝置解決程序同步問題、并得時刻警惕着程式中可能出現的死鎖或競争條件。雖然有些程式設計語言也或多或少地規避了讓程式員面對上述問題,但卻也避免不了将資源配置設定給各worker的問題。MapReduce的優勢之一便是有效地向程式員隐藏了這些問題。

1.3 函數式編譯語言

MapReduce是一種類似于Lisp或ML的函數式程式設計語言。函數式程式設計的核心特性之一是基于高階函數,即能夠接受其它函數作為參數的函數完成程式設計。MapReduce有兩個常見地内置高階函數map和fold。

<a href="http://s4.51cto.com/wyfs02/M01/8C/23/wKioL1hjcOWRrNMKAACqr9dNo2w085.png-wh_500x0-wm_3-wmp_4-s_842852238.png" target="_blank"></a>

如圖所示,給定一個清單,map(接受一個參數)以函數f為其參數并将其應用于清單中的所有元素;fold(接受兩個參數)以函數g和一個初始值作為參數,然後将g應用于初始值和清單中的第一個元素,結果被放置于中間變量中。中間變量和第二個元素将作為g函數下一次應用時的參數,而後如此操作直至将清單中的所有元素處理完畢後,fold會将最終處理結果儲存至一個中間變量中。

于是,基于上述過程,我們可以把map視作利用f函數将給定資料集完成形式轉換的操作,同樣地,fold就可以被看作利用g函數完成資料聚合的操作。我們就可以由此得知,各函數式程式在運作時彼此間是隔離的,是以,在map中将f函數應用于清單中每一個元素的操作可以并行進行,進一步地講,它們可以分布于叢集中的不同節點上并行執行。然而,受限于資料的本地性,fold操作需要等到清單中的每一個元素都準備停當之後才能進行。幸運地是,現實生活中的應用程式并不要求g函數應用于清單中的所有元素,是以,清單中元素可以被分為多個邏輯組,并将fold操作并行地應用在這些邏輯組上即可。由此,fold操作也可以以并行的方式高效完成。

MapReduce有兩個常見地内置高階函數map和reduce,其map就類似于上述過程中的map操作,reduce對應于上述過程中的fold操作。隻不過,MapReduce的執行架構能自行協調map與reduce并将其應用于在商業伺服器硬體平台上并行處理海量資料。

更為精确地說,MapReduce有三個互相關聯卻各不相同的概念。首先,MapReduce是一個如上所述的函數式程式設計語言。其次,MapReduce也是一個運作架構,它能夠協調運作基于MapReduce思想開發的程式。最後,MapReduce還可以被看作程式設計模型和執行架構的軟體實作,如Google的專有實作和另一個開源實作Hadoop等。

1.4 mapper和reducer

鍵值對兒(Key-value pair)是MapReduce的基礎資料結構。Key和Value可以是基礎類型資料,如整數、浮點數、字元串或未經加工的位元組資料,也可以是任意形式的複雜資料類型。程式員可以自行定義所需的資料類型,也可借助于Protocol Buffer、Thrift或Avro提供的便捷方式完成此類工作。

MapReduce算法設計的工作之一就是在給定資料集上定義“鍵-值”資料結構,比如在搜尋引擎搜集、存儲網頁類工作中,key可以使用URL來表示,而value則是網頁的内容。而在有些算法中,Key也可以是沒有任何實際意義的資料,其在資料處理過程中可被安全忽略。在MapReduce中,程式員需要基于如下方式定義mapper和reducer:

map: (k1,v1)--&gt;[(k2,v20)]

reduce: (k2,[v2])--&gt;[(k3,v3)]

其中[...]意味着其可以是一個清單。這些傳遞給MapReduce進行處理的資料存儲于分布式檔案上,mapper操作将應用于每一個傳遞過來的鍵-值對并生成一定數量的中間鍵值對(intermediate key-value),而後reduce操作将應用于這些中間鍵值對并輸出最終的鍵值對。然而,mapper操作和reducer操作之間還隐含着一個應用于中間鍵值對的“分組”操作,同一個鍵的鍵值對需要被歸類至同一組中并發送至同一個reducer,而傳送給每個reducer的分組中的鍵值對是基于鍵進行排序後的清單。reducer生成的結果将會儲存至分布式檔案系統,并存儲為一個或多個以r(即reducer号碼)結尾的檔案,但mapper生成的中間鍵值對資料則不會被儲存。

在Hadoop中,mapper和reducer是分别由MAP和REDUCE方法實作的對象。每個map任務(接收一個稱作input split的鍵值對清單)都被初始化一個mapper對象,并會由執行架構為每個輸入的鍵值對調用一次其map方法。程式員可以配置啟動的map任務個數,但其真正啟動的數目則由執行架構根據資料的實體分布最終給定。類似地,每個reduce任務由REDUCE方法初始化為一個reduce對象,并會由執行架構為其接受的每個中間鍵值對調用一次REDUCE方法,所不同的是,程式員可以明确限定啟動的reduce任務的個數。

mapper和reducer可以直接在各自接收的資料上執行所需要的操作,然而,當使用到外部資源時,多個mapper或reducer之間可能會産生資源競争,這勢必導緻其性能下降,是以,程式員必須關注其所用資源的競争條件并加入适當處理。其次,mapper輸出的中間鍵值對與接受的鍵值對可以是不同的資料類型,類似地,reducer輸出的鍵值對與其接收的中間鍵值對也可以是不同的資料類型,這可能會給程式設計過程及程式運作中的故障排除帶來困難,但這也正是MapReduce強大功能的展現之一。

除了正常的兩階段MapReduce處理流外,其還有一些變化形式。比如将mapper輸出的結果直接儲存至磁盤中(每個mapper對應一個檔案)的沒有reducer的MapReduce作業,不過僅有reducer而沒有mapper的作業是不允許的。不過,就算用不着reducer處理具體的操作,利用reducer将mapper的輸出結果進行重新分組和排序後進行輸出也能以另一種形式提供的完整MapReduce模式。

MapReduce作業一般是通過HDFS讀取和儲存資料,但它也可以使用其它滿足MapReduce應用的資料源或資料存儲,比如Google的MapReduce實作中使用了Bigtable來完成資料的讀入或輸出。BigTable屬于非關系的資料庫,它是一個稀疏的、分布式的、持久化存儲的多元度排序Map,其設計目的是可靠的處理PB級别的資料,并且能夠部署到上千台機器上。在Hadoop中有一個類似的實作HBase可用于為MapReduce提供資料源和資料存儲。

1.5 Hadoop運作架構

MapReduce程式也稱作為MapReduce作業,一般由mapper代碼、reducer代碼以及其配置參數(如從哪兒讀入資料,以及輸出資料的儲存位置)組成。準備好的作業可通過JobTracker(作業送出節點)進行送出,然後由運作架構負責完成後續的其它任務。這些任務主要包括如下幾個方面。

(1) 排程

每個MapReduce作業都會劃分為多個稱作任務(task)的較小單元,而較大的作業劃分的任務數量也可能會超出整個叢集可運作的任務數,此時就需要排程器程式維護一個任務隊列并能夠追蹤正在運作态任務的相關程序,以便讓隊列中處于等待狀态的任務派送至某轉為可用狀态的節點運作。此外,排程器還要負責分屬于不同作業的任務協調工作。

對于一個運作中的作業來說,隻有所用的map任務都完成以後才能将中間資料分組、排序後發往reduce作業,是以,map階段的完成時間取決于其最慢的一個作業的完成時間。類似的,reduce階段的最後一個任務執行結束,其最終結果才為可用。是以,MapReduce作業完成速度則由兩個階段各自任務中的掉隊者決定,最壞的情況下,這可能會導緻作業長時間得不到完成。出于優化執行的角度,Hadoop和Google MapReduce實作了推測執行(Speculative execution)機制,即同一個任務會在不同的主機上啟動多個執行副本,運作架構從其最快執行的任務中取得傳回結果。不過,推測執行并不能消除其它的滞後場景,比如中間鍵值對資料的分發速度等。

(2) 資料和代碼的協同工作(data/code co-location)

術語“資料分布”可能會帶來誤導,因為MapReduce盡力保證的機制是将要執行的代碼送至資料所在的節點執行,因為代碼的資料量通常要遠小于要處理的資料本身。當然,MapReduce并不能消除資料傳送,比如在某任務要處理的資料所在的節點已經啟動很多任務時,此任務将不得不在其它可用節點運作。此時,考慮到同一個機架内的伺服器有着較充裕的網絡帶寬,一個較優選擇是從資料節點同一個機架内挑選一個節點來執行此任務。

(3) 同步(Synchronization)

異步環境下的一組并發程序因直接制約而互相發送消息而進行互相合作、互相等待,使得各程序按一定的速度執行的過程稱為程序間同步,其可分為程序同步(或者線程同步)和資料同步。就程式設計方法來說,保持程序間同步的主要方法有記憶體屏障(Memory barrier),互斥鎖(Mutex),信号量(Semaphore)和鎖(Lock),管程(Monitor),消息(Message),管道(Pipe)等。MapReduce是通過在map階段的程序與reduce階段的程序之間實施隔離來完成程序同步的,即map階段的所有任務都完成後對其産生的中間鍵值對根據鍵完成分組、排序後通過網絡發往各reducer方可開始reduce階段的任務,是以這個過程也稱為“shuffle and sort”。

(4) 錯誤和故障處理(Error and fault handling)

MapReduce運作架構本身就是設計用來容易發生故障的商用伺服器上了,是以,其必須有着良好的容錯能力。在任何類别的硬體故障發生時,MapReduce運作架構均可自行将運作在相關節點的任務在一個新挑選出的節點上重新啟動。同樣,在任何程式發生故障時,運作架構也要能夠捕獲異常、記錄異常并自動完成從異常中恢複。另外,在一個較大規模的叢集中,其它任何超出程式員了解能力的故障發生時,MapReduce運作架構也要能夠安全挺過。

1.6 partitioner和combiner

除了前述的内容中的組成部分,MapReduce還有着另外兩個元件:partiontioner和combiner。

Partitioner負責分割中間鍵值對資料的鍵空間(即前面所謂的“分組”),并将中間分割後的中間鍵值對發往對應的reducer,也即partitioner負責完成為一個中間鍵值對指派一個reducer。最簡單的partitioner實作是将鍵的hash碼對reducer進行取餘計算,并将其發往餘數對應編号的reducer,這可以盡力保證每個reducer得到的鍵值對數目大體上是相同的。不過,由于partitioner僅考慮鍵而不考慮“值”,是以,發往每個reducer的鍵值對在鍵數目上的近似未必意味着資料量的近似。

Combiner是MapReduce的一種優化機制,它的主要功能是在“shuffle and sort”之前先在本地将中間鍵值對進行聚合,以減少在網絡上發送的中間鍵值對資料量。是以可以把combiner視作在“shuffle and sort”階段之前對mapper的輸出結果所進行聚合操作的“mini-reducer”。在實作中,各combiner之間的操作是隔離的,是以,它不會涉及到其它mapper的資料結果。需要注意的是,就算是某combiner可以有機會處理某鍵相關的所有中間資料,也不能将其視作reducer的替代品,因為combiner輸出的鍵值對類型必須要與mapper輸出的鍵值對類型相同。無論如何,combiner的恰當應用将有機會有效提高作業的性能。

2.1 HDFS的設計理念

HDFS專為存儲大檔案而設計,可運作于普通的商業伺服器上,基于流式資料通路模型完成資料存取。HDFS将所有檔案的中繼資料存儲于名稱節點(NameNode)的記憶體中,能夠利用分布式特性高效地管理“大”檔案(GB級别甚至更大的檔案),對于有着海量小檔案的應用場景則會給名稱節點帶去巨大壓力并使得其成為系統性能瓶頸。再者,HDFS為MapReduce的計算架構而設計,存儲下來資料主要用于後續的處理分析,其通路模型為“一次寫入、多次讀取”;是以,資料在HDFS中存儲完成後,僅能在檔案尾部附加新資料,而不能對檔案進行修改。另外,HDFS專為了高效地傳輸大檔案進行了優化,其為了完成此目标,在“低延遲”特性上做出了很大讓步,是以,其不适用于較小通路延遲的應用。

2.2 HDFS架構

2.2.1 HDFS資料塊

與傳統檔案系統一樣,HDFS也在“塊(block)”級别存取檔案,所不同的是,傳統檔案系統資料塊一般較小(1KB、2KB或4KB等),HDFS的資料塊大小預設為64MB,甚至可以使用128MB或256MB級别的資料塊。HDFS使用塊抽象層管理檔案,可以實作将分塊分為多個邏輯部分後分布于多個存儲節點,也能夠有效簡化存儲子系統。而對于存儲節點來說,較大的塊可以減少磁盤的尋道次數,進而提升I/O性能。

2.2.2 名稱節點(NameNode)和資料節點(DataNode)

HDFS叢集中節點的工作模型為“master-worker”:其包含一個名稱節點(master)和多個資料節點(worker)。

名稱節點負責管理HDFS的名稱空間,即以樹狀結構組織的目錄及檔案的中繼資料資訊,這些資訊持久存儲于名稱節點本地磁盤上并儲存為名稱空間鏡像(namespace image)和編輯日志(edit log)兩個檔案。名稱節點并不存儲資料塊,它僅需要知道每個檔案對應資料塊的存儲位置,即真正存儲了資料塊的資料節點。然而,名稱節點并不會持久存儲資料塊所與其存儲位置的對應資訊,因為這些資訊是在HDFS叢集啟動由名稱節點根據各資料節點發來的資訊進行重建而來。這個重建過程被稱為HDFS的安全模式。資料節點的主要任務包括根據名稱節點或客戶的要求完成存儲或讀取資料塊,并周期性地将其儲存的資料塊相關資訊報告給名稱節點。

預設情況下,HDFS會在叢集中為每個資料塊存儲三個副本以確定資料的可靠性、可用性及性能表現。在一個大規模叢集中,這三個副本一般會儲存至不同機架中的資料節點上以應付兩種常見的故障:單資料節點故障和導緻某機架上的所有主機離線的網絡故障。另外,如前面MapReduce運作模型中所述,為資料塊儲存多個副本也有利于MapReduce在作業執行過程中透明地處理節點故障等,并為MapReduce中作業協同處理以提升性能提供了現實支撐。名稱節點會根據資料節點的周期性報告來檢查每個資料塊的副本數是否符合要求,低于配置個數要求的将會對其進行補足,而多出的将會被丢棄。

HDFS提供了POSIX網絡的通路接口,所有的資料操作對用戶端程式都是透明的。當用戶端程式需要通路HDFS中的資料時,它首先基于TCP/IP協定與名稱節點監聽的TCP端口建立連接配接,接着通過用戶端協定(Client Protocol)發起讀取檔案的請求,而後名稱節點根據使用者請求傳回相關檔案的塊辨別符(blockid)及存儲了此資料塊的資料節點。接下來用戶端向對應的資料節點監聽的端口發起請求并取回所需要資料塊。當需要存儲檔案并寫資料時,用戶端程式首先會向名稱節點發起名稱空間更新請求,名稱節點檢查使用者的通路權限及檔案是否已經存在,如果沒有問題,名稱空間會挑選一個合适的資料節點配置設定一個空閑資料塊給用戶端程式。用戶端程式直接将要存儲的資料發往對應的資料節點,在完成存儲後,資料節點将根據名稱節點的訓示将資料塊複制多個副本至其它節點。

2.2.3 名稱節點的可用性

由前一節所述的過程可以得知,名稱節點的當機将會導緻HDFS檔案系統中的所有資料變為不可用,而如果名稱節點上的名稱空間鏡像檔案或編輯日志檔案損壞的話,整個HDFS甚至将無從重建,所有資料都會丢失。是以,出于資料可用性、可靠性等目的,必須提供額外的機制以確定此類故障不會發生,Hadoop為此提供了兩種解決方案。

最簡單的方式是将名稱節點上的持久中繼資料資訊實時存儲多個副本于不同的儲存設備中。Hadoop的名稱節點可以通過屬性配置使用多個不同的名稱空間儲存設備,而名稱節點對多個裝置的寫入操作是同步的。當名稱節點故障時,可在一台新的實體主機上加載一份可用的名稱空間鏡像副本和編輯日志副本完成名稱空間的重建。然而,根據編輯日志的大小及叢集規模,這個重建過程可能需要很長時間。

另一種方式是提供第二名稱節點(Secondary NameNode)。第二名稱節點并不真正扮演名稱節點角色,它的主要任務是周期性地将編輯日志合并至名稱空間鏡像檔案中以免編輯日志變得過大。它運作在一個獨立的實體主機上,并需要跟名稱節點同樣大的記憶體資源來完成檔案合并。另外,它還儲存一份名稱空間鏡像的副本。然而,根據其工作機制可知,第二名稱節點要滞後于主節點,是以名稱節點故障時,部分資料丢失仍然不可避免。

盡管上述兩種機制可以最大程式上避免資料丢失,但其并不具有高可用的特性,名稱節點依然是一個單點故障,因為其當機後,所有的資料将不能夠被通路,進而所有依賴于此HDFS運作的MapReduce作業也将中止。就算是備份了名稱空間鏡像和編輯日志,在一個新的主機上重建名稱節點并完成接收來自各資料節點的塊資訊報告也需要很長的時間才能完成。在有些應用環境中,這可能是無法接受的,為此,Hadoop 0.23引入了名稱節點的高可用機制——設定兩個名稱節點工作于“主備”模型,主節點故障時,其所有服務将立即轉移至備用節點。進一步資訊請參考官方手冊。

在大規模的HDFS叢集中,為了避免名稱節點成為系統瓶頸,在Hadoop 0.23版本中引入了HDFS聯邦(HDFS Federation)機制。HDFS聯邦中,每個名稱節點管理一個由名稱空間中繼資料和包含了所有塊相關資訊的塊池組成名稱空間卷(namespace volume),各名稱節點上的名稱空間卷是互相隔離的,是以,一個名稱節點的損壞并不影響其它名稱節點繼續提供服務。進一步資訊請參考官方手冊。

二、安裝配置hadoop:

2.1 安裝前的準備工作

本示例所示範的過程基于RHEL 5.8(32bit)平台,用到的應用程式如下所示。

JDK: jdk-7u5-linux-i586.rpm

Hadoop:hadoop-0.20.2-cdh3u5.tar.gz

安全起見,運作Hadoop需要以普通使用者的身份進行,是以,接下來先建立運作hadoop程序的使用者hadoop并給其設定密碼。

<code># useradd hadoop</code>

<code># echo "password" | passwd --stdin hadoop</code>

而後配置hadoop使用者能夠以基于密鑰的驗正方式登入本地主機,以便Hadoop可遠端啟動各節點上的Hadoop程序并執行監控等額外的管理工作。

<code>[root@master ~]</code><code># su - hadoop</code>

<code>[hadoop@master ~]$ </code><code>ssh</code><code>-keygen -t rsa -P </code><code>''</code> 

<code>[hadoop@master ~]$ </code><code>ssh</code><code>-copy-</code><code>id</code> <code>-i .</code><code>ssh</code><code>/id_rsa</code><code>.pub hadoop@localhost</code>

2.2 安裝JDK

Hadoop依賴于1.6 update 8或更新版本的Java環境。本文采用的jdk是rpm格式的安裝包,在oracle官方的下載下傳頁面中即可找到合适的版本。其安裝過程非常簡單,使用類似如下指令即可。

<code># rpm -ivh jdk-7u5-linux-i586.rpm</code>

Hadoop運作時需要能通路到如前安裝的Java環境,這可以通過将其二進制程式(/usr/java/latest)所在的目錄添加至PATH環境變量的路徑中實作,也可以通過設定hadoop-env.sh腳本來進行。這裡采用前一種方式,編輯/etc/profile.d/java.sh,在檔案中添加如下内容:

<code>JAVA_HOME=</code><code>/usr/java/latest/</code>

<code>PATH=$JAVA_HOME</code><code>/bin</code><code>:$PATH</code>

<code>export</code> <code>JAVA_HOME PATH</code>

切換至hadoop使用者,并執行如下指令測試jdk環境配置是否就緒。

<code># su - hadoop</code>

<code>$ java -version</code>

<code>java version </code><code>"1.7.0_05"</code>

<code>Java(TM) SE Runtime Environment (build 1.7.0_05-b05)</code>

<code>Java HotSpot(TM) Client VM (build 23.1-b03, mixed mode, sharing)</code>

2.3 hadoop安裝配置

2.3.1 安裝:

<code># tar xf hadoop-0.20.2-cdh3u5.tar.gz -C /usr/local</code>

<code># chown -R hadoop:hadoop /usr/local/hadoop-0.20.2-cdh3u5</code>

<code># ln -sv /usr/local/hadoop-0.20.2-cdh3u5 /usr/local/hadoop</code>

然後編輯/etc/profile.d/hadoop.sh,設定HADOOP_HOME環境變量的值為hadoop的解壓目錄,并讓其永久有效。編輯/etc/profile,添加如下内容:

<code>HADOOP_BASE=</code><code>/usr/local/hadoop</code>

<code>PATH=$HADOOP_BASE</code><code>/bin</code><code>:$PATH</code>

<code>export</code> <code>HADOOP_BASE PATH</code>

切換至hadoop使用者,并執行如下指令測試hadoop是否就緒。

<code># hadoop version</code>

<code>Hadoop 0.20.2-cdh3u5</code>

<code>Subversion git:</code><code>//ubuntu-slave02/var/lib/jenkins/workspace/CDH3u5-Full-RC/build/cdh3/hadoop20/0</code><code>.20.2-cdh3u5</code><code>/source</code> <code>-r 30233064aaf5f2492bc687d61d72956876102109</code>

<code>Compiled by jenkins on Fri Oct  5 17:21:34 PDT 2012</code>

<code>From </code><code>source</code> <code>with checksum de1770d69aa93107a133657faa8ef467</code>

2.3.2 Hadoop的配置檔案:

hadoop-env.sh: 用于定義hadoop運作環境相關的配置資訊,比如配置JAVA_HOME環境變量、為hadoop的JVM指定特定的選項、指定日志檔案所在的目錄路徑以及master和slave檔案的位置等;

core-site.xml: 用于定義系統級别的參數,如HDFS URL、Hadoop的臨時目錄以及用于rack-aware叢集中的配置檔案的配置等,此中的參數定義會覆寫core-default.xml檔案中的預設配置;

hdfs-site.xml: HDFS的相關設定,如檔案副本的個數、塊大小及是否使用強制權限等,此中的參數定義會覆寫hdfs-default.xml檔案中的預設配置;

mapred-site.xml:HDFS的相關設定,如reduce任務的預設個數、任務所能夠使用記憶體的預設上下限等,此中的參數定義會覆寫mapred-default.xml檔案中的預設配置;

masters: hadoop的secondary-masters主機清單,當啟動Hadoop時,其會在目前主機上啟動NameNode和JobTracker,然後通過SSH連接配接此檔案中的主機以作為備用NameNode; 

slaves:Hadoop叢集的slave主機清單,master啟動時會通過SSH連接配接至此清單中的所有主機并為其啟動DataNode和taskTracker程序;

2.3.3 Hadoop的分布式模型

Hadoop通常有三種運作模式:本地(獨立)模式、僞分布式(Pseudo-distributed)模式和完全分布式(Fully distributed)模式。

安裝完成後,Hadoop的預設配置即為本地模式,此時Hadoop使用本地檔案系統而非分布式檔案系統,而且其也不會啟動任何Hadoop守護程序,Map和Reduce任務都作為同一程序的不同部分來執行。是以,本地模式下的Hadoop僅運作于本機。此種模式僅用于開發或調試MapReduce應用程式但卻避免了複雜的後續操作。

僞分布式模式下,Hadoop将所有程序運作于同一台主機上,但此時Hadoop将使用分布式檔案系統,而且各jobs也是由JobTracker服務管理的獨立程序。同時,由于僞分布式的Hadoop叢集隻有一個節點,是以HDFS的塊複制将限制為單個副本,其secondary-master和slave也都将運作于本地主機。此種模式除了并非真正意義的分布式之外,其程式執行邏輯完全類似于完全分布式,是以,常用于開發人員測試程式執行。

要真正發揮Hadoop的威力,就得使用完全分布式模式。由于ZooKeeper實作高可用等依賴于奇數法定數目(an odd-numbered quorum),是以,完全分布式環境需要至少三個節點。

2.3.4 配置Hadoop的僞分布式模式

傳統上使用的hadoop-site.xml檔案已經過時,現在分别使用core-site.xml、mapred-site.xml和hdfs-site.xml來取代core-default.xml、mapred-default.xml和 hdfs-default.xml中的預設配置。hadoop為這些檔案提供了模闆,其關于xml文檔檔案格式定義的部分及&lt;configure&gt;&lt;/configure&gt;已經存在,此時所需要做的僅是在其中添加相應的配置即可。

2.3.4.1 編輯conf/core-site.xml,配置Hadoop的核心屬性

<code>&lt;?xml version=</code><code>"1.0"</code> <code>encoding=</code><code>"UTF-8"</code><code>?&gt;</code>

<code>&lt;?xml-stylesheet </code><code>type</code><code>=</code><code>"text/xsl"</code> <code>href=</code><code>"configuration.xsl"</code><code>?&gt;</code>

<code>&lt;configuration&gt;</code>

<code>  </code><code>&lt;property&gt;</code>

<code>    </code><code>&lt;name&gt;hadoop.tmp.</code><code>dir</code><code>&lt;</code><code>/name</code><code>&gt;</code>

<code>    </code><code>&lt;value&gt;</code><code>/hadoop/temp</code><code>&lt;</code><code>/value</code><code>&gt;</code>

<code>  </code><code>&lt;</code><code>/property</code><code>&gt;</code>

<code>  </code> 

<code>    </code><code>&lt;name&gt;fs.default.name&lt;</code><code>/name</code><code>&gt;</code>

<code>    </code><code>&lt;value&gt;hdfs:</code><code>//localhost</code><code>:8020&lt;</code><code>/value</code><code>&gt;</code>

<code>  </code><code>&lt;</code><code>/property</code><code>&gt;  </code>

<code>&lt;</code><code>/configuration</code><code>&gt;</code>

上面示例中hadoop.tmp.dir屬性用于定義Hadoop的臨時目錄,其預設為/tmp/hadoop-${username}。HDFS程序的許多目錄預設都在此目錄中,本示例将其定義到了/hadoop/temp目錄,需要注意的是,要保證運作Hadoop程序的使用者對其具有全部通路權限。fs.default.name屬性用于定義HDFS的名稱節點和其預設的檔案系統,其值是一個URI,即NameNode的RPC伺服器監聽的位址(可以是主機名)和端口(預設為8020)。其預設值為file:///,即本地檔案系統。

2.3.4.2 編輯conf/mapred-site.xml,定義MapReduce

運作MapReduce需要為其指定一個主機作為JobTracker節點,在一個小規模的Hadoop叢集中,它通常跟NameNode運作于同一實體主機。可以通過mapred.job.trakcer屬性定義JobTracker監聽的位址(或主機名)和端口(預設為8021),與前面的fs.default.name屬性的值不同的是,這不是一個URI,而僅一個“主機-端口”組合。

在MapReduce作業運作過程中,中間資料(intermediate data)和工作檔案儲存于本地臨時檔案中。根據運作的MapReduce作業不同,這些資料檔案可能會非常大,是以,應該通過mapred.local.dir屬性為其指定一個有着足夠空間的本地檔案系統路徑,其預設值為${hadoop.tmp.dir}/mapred/local。mapred.job.tracker可以接受多個以逗号分隔路徑清單作為其值,并會以輪流的方式将資料分散存儲在這些檔案系統上,是以指定位于不同磁盤上的多個檔案系統路徑可以分散資料I/O。

另外,MapReduce使用分布式檔案系統為各TaskTracker儲存共享資料,這可以通過mapred.system.dir屬性進行定義,其預設值為${hadoop.tmp.dir}/mapred/system。下面給出了一個較簡單的mapred-site.xml檔案示例。

<code>&lt;?xml version=</code><code>"1.0"</code><code>?&gt;</code>

<code>    </code><code>&lt;name&gt;mapred.job.tracker&lt;</code><code>/name</code><code>&gt;</code>

<code>    </code><code>&lt;value&gt;localhost:8021&lt;</code><code>/value</code><code>&gt;</code>

2.3.4.3 編輯conf/hdfs-site.xml,定義hdfs的屬性

HDFS程序有許多屬性可以定義其工作路,如dfs.name.dir屬性定義的HDFS中繼資料持久存儲路徑預設為${hadoop.tmp.dir}/dfs/name、dfs.data.dir屬性定義的DataNode用于存儲資料塊的目錄路徑預設為${hadoop.tmp.dir}/dfs/data、fs.checkpoint.dir屬性定義的SecondaryNameNode用于存儲檢查點檔案的目錄預設為${hadoop.tmp.dir}/dfs/namesecondary。

為了資料可用性及備援的目的,HDFS會在多個節點上儲存同一個資料塊的多個副本,其預設為3個。而隻有一個節點的僞分布式環境中其僅用儲存一個副本即可,這可以通過dfs.replication屬性進行定義。如下所示的内容即可作為最簡單的hdfs-site.xml配置檔案。

<code>    </code><code>&lt;name&gt;dfs.replication&lt;</code><code>/name</code><code>&gt;</code>

<code>    </code><code>&lt;value&gt;1&lt;</code><code>/value</code><code>&gt;</code>

2.3.4.4 格式化名稱節點

以hadoop使用者運作如下指令

<code>$ hadoop namenode -</code><code>format</code>

其執行後會顯示為類似如下内容:

<code>12</code><code>/12/06</code> <code>22:16:02 INFO namenode.NameNode: STARTUP_MSG: </code>

<code>/************************************************************</code>

<code>STARTUP_MSG: Starting NameNode</code>

<code>STARTUP_MSG:   host = localhost.localdomain</code><code>/127</code><code>.0.0.1</code>

<code>STARTUP_MSG:   args = [-</code><code>format</code><code>]</code>

<code>STARTUP_MSG:   version = 0.20.2-cdh3u5</code>

<code>STARTUP_MSG:   build = git:</code><code>//ubuntu-slave02/var/lib/jenkins/workspace/CDH3u5-Full-RC/build/cdh3/hadoop20/0</code><code>.20.2-cdh3u5</code><code>/source</code> <code>-r 30233064aaf5f2492bc687d61d72956876102109; compiled by </code><code>'jenkins'</code> <code>on Fri Oct  5 17:21:34 PDT 2012</code>

<code>************************************************************/</code>

<code>12</code><code>/12/06</code> <code>22:16:03 INFO util.GSet: VM </code><code>type</code>       <code>= 32-bit</code>

<code>12</code><code>/12/06</code> <code>22:16:03 INFO util.GSet: 2% max memory = 19.33375 MB</code>

<code>12</code><code>/12/06</code> <code>22:16:03 INFO util.GSet: capacity      = 2^22 = 4194304 entries</code>

<code>12</code><code>/12/06</code> <code>22:16:03 INFO util.GSet: recommended=4194304, actual=4194304</code>

<code>12</code><code>/12/06</code> <code>22:16:03 INFO namenode.FSNamesystem: fsOwner=hadoop (auth:SIMPLE)</code>

<code>12</code><code>/12/06</code> <code>22:16:04 INFO namenode.FSNamesystem: supergroup=supergroup</code>

<code>12</code><code>/12/06</code> <code>22:16:04 INFO namenode.FSNamesystem: isPermissionEnabled=</code><code>true</code>

<code>12</code><code>/12/06</code> <code>22:16:04 INFO namenode.FSNamesystem: dfs.block.invalidate.limit=1000</code>

<code>12</code><code>/12/06</code> <code>22:16:04 INFO namenode.FSNamesystem: isAccessTokenEnabled=</code><code>false</code> <code>accessKeyUpdateInterval=0 min(s), accessTokenLifetime=0 min(s)</code>

<code>12</code><code>/12/06</code> <code>22:16:04 INFO common.Storage: Image </code><code>file</code> <code>of size 112 saved </code><code>in</code> <code>0 seconds.</code>

<code>12</code><code>/12/06</code> <code>22:16:05 INFO common.Storage: Storage directory </code><code>/hadoop/temp/dfs/name</code> <code>has been successfully formatted.</code>

<code>12</code><code>/12/06</code> <code>22:16:05 INFO namenode.NameNode: SHUTDOWN_MSG: </code>

<code>SHUTDOWN_MSG: Shutting down NameNode at localhost.localdomain</code><code>/127</code><code>.0.0.1</code>

其中的“Storage directory /hadoop/temp/dfs/name has been successfully formatted”一行資訊表明對應的存儲已經格式化成功。

2.3.4.5 啟動hadoop

Hadoop提供了2個腳本start-dfs.sh和start-mapred.sh,分别用于啟動hdfs相關的程序和mapred相關的程序。事實上,為了使用的便捷性,在NameNode和JobTracker運作于同一主機的場景中,Hadoop還專門提供了腳本start-all.sh腳本來自動執行前述兩個腳本。

<code>$ </code><code>/usr/local/hadoop/bin/start-all</code><code>.sh</code>

其會輸出類似如下内容:

<code>starting namenode, logging to </code><code>/usr/local/hadoop/logs/hadoop-hadoop-namenode-localhost</code><code>.localdomain.out</code>

<code>localhost: starting datanode, logging to </code><code>/usr/local/hadoop/logs/hadoop-hadoop-datanode-localhost</code><code>.localdomain.out</code>

<code>localhost: starting secondarynamenode, logging to </code><code>/usr/local/hadoop/logs/hadoop-hadoop-secondarynamenode-localhost</code><code>.localdomain.out</code>

<code>starting jobtracker, logging to </code><code>/usr/local/hadoop/logs/hadoop-hadoop-jobtracker-localhost</code><code>.localdomain.out</code>

<code>localhost: starting tasktracker, logging to </code><code>/usr/local/hadoop/logs/hadoop-hadoop-tasktracker-localhost</code><code>.localdomain.out</code>

運作jps指令檢視正在運作的Hadoop程序

<code>$ jps | </code><code>grep</code> <code>-iv </code><code>"jps"</code>

<code>29326 DataNode</code>

<code>29478 SecondaryNameNode</code>

<code>29685 TaskTracker</code>

<code>29208 NameNode</code>

<code>29563 JobTracker</code>

2.3.4.6 Hadoop程序監聽的位址和端口

Hadoop啟動時會運作兩個伺服器程序,一個為用于Hadoop各程序之間進行通信的RPC伺服器,另一個是提供了便于管理者檢視Hadoop叢集各程序相關資訊頁面的HTTP伺服器。

用于定義各RPC伺服器所監聽的位址和端口的屬性有如下幾個:

fs.default.name:定義HDFS的NameNode用于提供URI所監聽的位址和端口,預設端口為8020;

dfs.datanode.ipc.address:DataNode上IPC伺服器監聽的位址和端口,預設為0.0.0.0:50020;

mapred.job.tracker:JobTracker的PRC伺服器所監聽的位址和端口,預設端口為8021;

mapred.task.tracker.report.address:TaskTracker的RPC伺服器監聽的位址和端口;TaskTracker的子JVM使用此端口與TaskTracker進行通信,它僅需要監聽在本地回環位址127.0.0.1上,是以可以使用任何端口;隻有在當本地沒有回環接口時才需要修改此屬性的值;

除了RPC伺服器之外,DataNode還會運作一個TCP/IP伺服器用于資料塊傳輸,其監聽的位址和端口可以通過dfs.datanode.address屬性進行定義,預設為0.0.0.0:50010。

可用于定義各HTTP伺服器的屬性有如下幾個:

mapred.job.tracker.http.addrss:JobTracker的HTTP伺服器位址和端口,預設為0.0.0.0:50030;

mapred.task.tracker.http.address:TaskTracker的HTTP伺服器位址和端口,預設為0.0.0.0:50060;

dfs.http.address:NameNode的HTTP伺服器位址和端口,預設為0.0.0.0:50070;

dfs.datanode.http.address:DataNode的HTTP伺服器位址和端口,預設為0.0.0.0:50075;

dfs.secondary.http.address:SecondaryNameNode的HTTP伺服器位址和端口,預設為0.0.0.0:50090;

上述的HTTP伺服器均可以通過浏覽器直接通路以擷取對應程序的相關資訊。

下面的指令可以檢視jvm監聽的端口。 

<code>$ </code><code>netstat</code> <code>-tnlp | </code><code>grep</code> <code>"java"</code>

<code>(Not all processes could be identified, non-owned process info</code>

<code> </code><code>will not be shown, you would have to be root to see it all.)</code>

<code>tcp        0      0 0.0.0.0:50020               0.0.0.0:*                   LISTEN      29326</code><code>/java</code>          

<code>tcp        0      0 0.0.0.0:52805               0.0.0.0:*                   LISTEN      29208</code><code>/java</code>          

<code>tcp        0      0 0.0.0.0:50090               0.0.0.0:*                   LISTEN      29478</code><code>/java</code>          

<code>tcp        0      0 0.0.0.0:50060               0.0.0.0:*                   LISTEN      29685</code><code>/java</code>          

<code>tcp        0      0 0.0.0.0:50030               0.0.0.0:*                   LISTEN      29563</code><code>/java</code>          

<code>tcp        0      0 0.0.0.0:51664               0.0.0.0:*                   LISTEN      29478</code><code>/java</code>          

<code>tcp        0      0 0.0.0.0:54898               0.0.0.0:*                   LISTEN      29326</code><code>/java</code>          

<code>tcp        0      0 0.0.0.0:55475               0.0.0.0:*                   LISTEN      29563</code><code>/java</code>          

<code>tcp        0      0 127.0.0.1:8020              0.0.0.0:*                   LISTEN      29208</code><code>/java</code>          

<code>tcp        0      0 127.0.0.1:44949             0.0.0.0:*                   LISTEN      29685</code><code>/java</code>          

<code>tcp        0      0 127.0.0.1:8021              0.0.0.0:*                   LISTEN      29563</code><code>/java</code>          

<code>tcp        0      0 0.0.0.0:50070               0.0.0.0:*                   LISTEN      29208</code><code>/java</code>          

<code>tcp        0      0 0.0.0.0:50010               0.0.0.0:*                   LISTEN      29326</code><code>/java</code>          

<code>tcp        0      0 0.0.0.0:50075               0.0.0.0:*                   LISTEN      29326</code><code>/java</code>

2.4 Hadoop指令

hadoop有很多子指令,用于完成不同的功能,這個可以通過如下指令檢視。

<code>$ hadoop</code>

其中的fs子指令用于進行跟檔案系統相關的多種操作,如建立目錄、複制檔案或目錄等,其具體的使用幫助可以使用如下指令獲得。

<code>$ hadoop fs -help</code>

hadoop的fs指令能同時跟本地檔案系統和HDFS互動,甚至可以跟Amazon的S3進行互動。其使用URI格式路徑引用檔案路徑,完全的URI格式類似schema://authority/path,其中schema類似于協定,這裡可以使用hdfs或file,分别用于引用 HDFS檔案或本地檔案系統中的檔案。而對于HDFS來說,authority是指Namenode主機,path是指具體的檔案路徑。例如,在僞檔案系統模式中,HDFS運作于本機的8020端口,是以hdfs://localhost:8020/user/hadoop/test.txt就是一個完整意義上的URI。事實上,在使用中,也可以省略URI中的schema://authority部分,此時其使用配置檔案中預設名稱段的定義,如我們前面定義的類似如下段的配置資訊:

<code>    </code><code>&lt;value&gt;hdfs:</code><code>//localhost</code><code>:9000&lt;</code><code>/value</code><code>&gt;</code>

在fs指令用于實作在本地檔案系統和HDFS之間傳遞檔案時,可以使用-get(從HDFS中複制檔案至本地檔案系統)或-put(将本地檔案複制到HDFS中)指令實作,而fs會根據使用的指令來判斷哪個是本地檔案系統路徑,哪個是HDFS檔案系統路徑,如将本地的/etc/issue複制到HDFS中存放至目前hadoop使用者的目錄中,則可使用如下指令:

<code>$ hadoop fs -put </code><code>/etc/issue</code>  <code>hdfs:</code><code>//localhost</code><code>:9000</code><code>/user/hadoop/</code>

或使用指令

<code>$ hadoop fs -put </code><code>/etc/issue</code>  <code>/user/hadoop/</code>

複制的結果可以使用如下指令檢視:

<code>$ hadoop fs -</code><code>ls</code>

<code>Found 1 items</code>

<code>-rw-r--r--   1 hadoop supergroup         74 2012-09-20 23:03 </code><code>/user/hadoop/issue</code>

hadoop對檔案系統的管理是通過java類來實作的,而其用于檔案系統管理的類有多種,分别用于通過不同的方式通路不同的檔案系統。hdfs和file是schema中常見的兩種方式。

hadoop常用的指令行指令及其用法清單請參見如下連結:

HDFS指令:http://hadoop.apache.org/common/docs/r1.0.0/file_system_shell.html

MapReduce的job指令:http://hadoop.apache.org/common/docs/r1.0.0/commands_manual.html#job

2.5 測試Hadoop

Hadoop提供了MapReduce程式設計架構,其并行處理能力的發揮需要通過開發Map及Reduce程式實作。為了便于系統測試,Hadoop提供了一個單詞統計的應用程式算法樣例,其位于Hadoop安裝目錄下名稱類似hadoop-examples-*.jar的檔案中。除了單詞統計,這個jar檔案還包含了分布式運作的grep等功能的實作,這可以通過如下指令檢視。

<code>$ hadoop jar </code><code>/usr/local/hadoop/hadoop-examples-0</code><code>.20.2-cdh3u5.jar </code>

<code>An example program must be given as the first argument.</code>

<code>Valid program names are:</code>

<code>  </code><code>aggregatewordcount: An Aggregate based map</code><code>/reduce</code> <code>program that counts the words </code><code>in</code> <code>the input files.</code>

<code>  </code><code>aggregatewordhist: An Aggregate based map</code><code>/reduce</code> <code>program that computes the histogram of the words </code><code>in</code> <code>the input files.</code>

<code>  </code><code>dbcount: An example job that count the pageview counts from a database.</code>

<code>  </code><code>grep</code><code>: A map</code><code>/reduce</code> <code>program that counts the matches of a regex </code><code>in</code> <code>the input.</code>

<code>  </code><code>join</code><code>: A job that effects a </code><code>join</code> <code>over sorted, equally partitioned datasets</code>

<code>  </code><code>multifilewc: A job that counts words from several files.</code>

<code>  </code><code>pentomino: A map</code><code>/reduce</code> <code>tile laying program to </code><code>find</code> <code>solutions to pentomino problems.</code>

<code>  </code><code>pi: A map</code><code>/reduce</code> <code>program that estimates Pi using monte-carlo method.</code>

<code>  </code><code>randomtextwriter: A map</code><code>/reduce</code> <code>program that writes 10GB of random textual data per node.</code>

<code>  </code><code>randomwriter: A map</code><code>/reduce</code> <code>program that writes 10GB of random data per node.</code>

<code>  </code><code>secondarysort: An example defining a secondary </code><code>sort</code> <code>to the reduce.</code>

<code>  </code><code>sleep</code><code>: A job that sleeps at each map and reduce task.</code>

<code>  </code><code>sort</code><code>: A map</code><code>/reduce</code> <code>program that sorts the data written by the random writer.</code>

<code>  </code><code>sudoku: A sudoku solver.</code>

<code>  </code><code>teragen: Generate data </code><code>for</code> <code>the terasort</code>

<code>  </code><code>terasort: Run the terasort</code>

<code>  </code><code>teravalidate: Checking results of terasort</code>

<code>  </code><code>wordcount: A map</code><code>/reduce</code> <code>program that counts the words </code><code>in</code> <code>the input files.</code>

接下來的過程來示範在HDFS的wc-in目錄中存放兩個測試檔案,而後運作wordcount程式實作對這兩個測試檔案中各單詞出現次數進行統計的實作過程。首先建立wc-in目錄,并複制檔案至HDFS檔案系統中。

<code>$ hadoop fs -</code><code>mkdir</code> <code>wc</code><code>-</code><code>in</code>

<code>$ hadoop fs -put </code><code>/etc/rc</code><code>.d</code><code>/init</code><code>.d</code><code>/functions</code> <code>/etc/profile</code> <code>wc</code><code>-</code><code>in</code>

接下來啟動分布式任務,其中的wc-out為reduce任務執行結果檔案所在的目錄,此目标要求事先不能存在,否則運作将會報錯。

<code>$ hadoop jar </code><code>/usr/local/hadoop/hadoop-example-</code><code>*.jar wordcount </code><code>wc</code><code>-</code><code>in</code> <code>wc</code><code>-out</code>

輸出結果類似如下内容:

<code>12</code><code>/12/06</code> <code>23:11:38 INFO input.FileInputFormat: Total input paths to process : 2</code>

<code>12</code><code>/12/06</code> <code>23:11:38 WARN util.NativeCodeLoader: Unable to load native-hadoop library </code><code>for</code> <code>your platform... using </code><code>builtin</code><code>-java classes where applicable</code>

<code>12</code><code>/12/06</code> <code>23:11:38 WARN snappy.LoadSnappy: Snappy native library not loaded</code>

<code>12</code><code>/12/06</code> <code>23:11:38 INFO mapred.JobClient: Running job: job_201212062231_0001</code>

<code>12</code><code>/12/06</code> <code>23:11:39 INFO mapred.JobClient:  map 0% reduce 0%</code>

<code>12</code><code>/12/06</code> <code>23:11:50 INFO mapred.JobClient:  map 100% reduce 0%</code>

<code>12</code><code>/12/06</code> <code>23:11:58 INFO mapred.JobClient:  map 100% reduce 33%</code>

<code>12</code><code>/12/06</code> <code>23:12:00 INFO mapred.JobClient:  map 100% reduce 100%</code>

<code>12</code><code>/12/06</code> <code>23:12:02 INFO mapred.JobClient: Job complete: job_201212062231_0001</code>

<code>12</code><code>/12/06</code> <code>23:12:02 INFO mapred.JobClient: Counters: 26</code>

<code>12</code><code>/12/06</code> <code>23:12:02 INFO mapred.JobClient:   Job Counters </code>

<code>12</code><code>/12/06</code> <code>23:12:02 INFO mapred.JobClient:     Launched reduce tasks=1</code>

<code>12</code><code>/12/06</code> <code>23:12:02 INFO mapred.JobClient:     SLOTS_MILLIS_MAPS=14810</code>

<code>12</code><code>/12/06</code> <code>23:12:02 INFO mapred.JobClient:     Total </code><code>time</code> <code>spent by all reduces waiting after reserving slots (ms)=0</code>

<code>12</code><code>/12/06</code> <code>23:12:02 INFO mapred.JobClient:     Total </code><code>time</code> <code>spent by all maps waiting after reserving slots (ms)=0</code>

<code>12</code><code>/12/06</code> <code>23:12:02 INFO mapred.JobClient:     Launched map tasks=2</code>

<code>12</code><code>/12/06</code> <code>23:12:02 INFO mapred.JobClient:     Data-</code><code>local</code> <code>map tasks=2</code>

<code>12</code><code>/12/06</code> <code>23:12:02 INFO mapred.JobClient:     SLOTS_MILLIS_REDUCES=10058</code>

<code>12</code><code>/12/06</code> <code>23:12:02 INFO mapred.JobClient:   FileSystemCounters</code>

<code>12</code><code>/12/06</code> <code>23:12:02 INFO mapred.JobClient:     FILE_BYTES_READ=11699</code>

<code>12</code><code>/12/06</code> <code>23:12:02 INFO mapred.JobClient:     HDFS_BYTES_READ=15943</code>

<code>12</code><code>/12/06</code> <code>23:12:02 INFO mapred.JobClient:     FILE_BYTES_WRITTEN=182084</code>

<code>12</code><code>/12/06</code> <code>23:12:02 INFO mapred.JobClient:     HDFS_BYTES_WRITTEN=8152</code>

<code>12</code><code>/12/06</code> <code>23:12:02 INFO mapred.JobClient:   Map-Reduce Framework</code>

<code>12</code><code>/12/06</code> <code>23:12:02 INFO mapred.JobClient:     Map input records=666</code>

<code>12</code><code>/12/06</code> <code>23:12:02 INFO mapred.JobClient:     Reduce shuffle bytes=11705</code>

<code>12</code><code>/12/06</code> <code>23:12:02 INFO mapred.JobClient:     Spilled Records=1632</code>

<code>12</code><code>/12/06</code> <code>23:12:02 INFO mapred.JobClient:     Map output bytes=23420</code>

<code>12</code><code>/12/06</code> <code>23:12:02 INFO mapred.JobClient:     CPU </code><code>time</code> <code>spent (ms)=4300</code>

<code>12</code><code>/12/06</code> <code>23:12:02 INFO mapred.JobClient:     Total committed heap usage (bytes)=337190912</code>

<code>12</code><code>/12/06</code> <code>23:12:02 INFO mapred.JobClient:     Combine input records=2343</code>

<code>12</code><code>/12/06</code> <code>23:12:02 INFO mapred.JobClient:     SPLIT_RAW_BYTES=226</code>

<code>12</code><code>/12/06</code> <code>23:12:02 INFO mapred.JobClient:     Reduce input records=816</code>

<code>12</code><code>/12/06</code> <code>23:12:02 INFO mapred.JobClient:     Reduce input </code><code>groups</code><code>=762</code>

<code>12</code><code>/12/06</code> <code>23:12:02 INFO mapred.JobClient:     Combine output records=816</code>

<code>12</code><code>/12/06</code> <code>23:12:02 INFO mapred.JobClient:     Physical memory (bytes) snapshot=324112384</code>

<code>12</code><code>/12/06</code> <code>23:12:02 INFO mapred.JobClient:     Reduce output records=762</code>

<code>12</code><code>/12/06</code> <code>23:12:02 INFO mapred.JobClient:     Virtual memory (bytes) snapshot=1122086912</code>

<code>12</code><code>/12/06</code> <code>23:12:02 INFO mapred.JobClient:     Map output records=2343</code>

指令的執行結果按上面指令的指定存儲于wc-out目錄中:

<code>$ hadoop fs -</code><code>ls</code> <code>wc</code><code>-out</code>

<code>Found 3 items</code>

<code>-rw-r--r--   1 hadoop supergroup          0 2012-12-06 23:12 </code><code>/user/hadoop/wc-out/_SUCCESS</code>

<code>drwxr-xr-x   - hadoop supergroup          0 2012-12-06 23:11 </code><code>/user/hadoop/wc-out/_logs</code>

<code>-rw-r--r--   1 hadoop supergroup       8152 2012-12-06 23:11 </code><code>/user/hadoop/wc-out/part-r-00000</code>

其中的part-r-00000正是其執行結果的輸出檔案,使用如下指令檢視其執行結果。

<code>$ hadoop fs -</code><code>cat</code> <code>wc</code><code>-out</code><code>/part-r-00000</code>

檔案的部分内容如下所示:

<code>"$BOOTUP"</code><code>17</code>

<code>"$CONSOLETYPE"</code><code>1</code>

<code>"$EUID"</code><code>2</code>

<code>"$GRAPHICAL"</code><code>1</code>

<code>"$HOME/.inputrc"</code><code>1</code>

<code>"$INPUTRC"</code><code>1</code>

<code>"$RC"</code><code>3</code>

<code>"$STRING2</code>

<code>"$answer"</code><code>4</code>

<code>"$base1</code>

<code>"$base"</code><code>1</code>

<code>"$corelimit2</code>

<code>"$file"</code><code>3</code>

<code>"$force"</code><code>1</code>

<code>"$gotbase"</code><code>1</code>

<code>"$i"</code><code>1</code>

<code>"$killlevel"</code><code>3</code>

<code>"$line"</code><code>2</code>

<code>"$pid"</code><code>8</code>

<code>"$pid_file"</code><code>9</code>

<code>"$rc"</code><code>1</code>

<code>"$remaining"</code><code>4</code>

<code>"$retry"</code><code>4</code>

<code>"$user"</code><code>1</code>

<code>"`id2</code>

<code>"after"</code><code>1</code>

<code>"color"</code><code>12</code>

<code>"hex"</code><code>1</code>

<code>"no1</code>

<code>"pidof"</code><code>1</code>

三、開發mapreduce:

盡管hadoop的架構是基于JAVA語言實作,但MapReduce程式卻未必一定要使用java來開發。

Hadoop Streaming:Hadoop提供的一個程式設計工具,它允許使用者使用任何可執行檔案或者腳本檔案作為Mapper和Reducer;

Hadoop Pipes和SWIG:開發MapReduce程式的可相容性 C++ API;

四、簡單配置Hadoop

4.1 設定Hadoop參數

Hadoop有很多參數,其預設配置大多數僅适用于standalone模式,雖然大多情況下在完全分布式(Fully distributed)模式中也沒有問題,但距最優化的運作模式去相去甚遠。在生産環境中通常需要調整的參數有:

1. dfs.name.dir —— NameNode節點用于存儲HDFS中繼資料的本地目錄,官方建議為/home/hadoop/dfs/name;

2. dfs.data.dir —— DataNode節點用于存儲HDFS檔案資料塊的本地目錄,官方建議為/home/hadoop/dfs/data;

3. mapred.system.dir —— HDFS中用于存儲共享的MapReduce系統檔案的目錄,官方建議為/hadoop/mapred/system;

4. mapred.local.dir —— TaskNode節點用于存儲臨時資料的本地檔案目錄;

5. mapred.tasktracker.{map|reduce}.tarks.maximum —— 在TaskTracker上可同時運作的的map或reduce任務的最大數目;

6. hadoop.tmp.dir —— Hadoop臨時目錄;

7. mapred.child.java.opts —— 每個子任務可申請使用的heap大小;官方建議為-Xmx512m;

8. mapred.reduce.tasks —— 每任務的reduce數量;

上述參數中的大多數都可以接受多個以逗号分隔的目錄,尤其是對于dfs.name.dir來說,多個目錄還可以達到備援的目的;而對于擁有多塊磁盤的DataNode,為其dfs.data.dir指定多個值可以存儲資料于多個磁盤,并能通過并行加速I/O操作。為mapred.local.dir指定多個眼光也能起到一定的加速作用。

此外,hadoop.tmp.dir對于不同的使用者來說其路徑是不相同的,事實上,應該盡量避免讓此路徑依賴使用者屬性,比如可以放在一個公共位置讓所有使用者都可以友善地通路到。在Linux系統下,hadoop.tmp.dir的預設路徑指向了/tmp,這的确是一個公共位置,但/tmp目錄所在的檔案系統大多數都有使用配額,而且空間也通常比較有限,是以,故此此路徑殊非理想之所在。建議将其指向一個有着足夠空間的檔案系統上的目錄。

預設配置中,Hadoop可以在每個TaskTracker上運作四個任務(兩個map任務,兩個reduce任務),這可以通過mapred.tasktracker.{map|reduce}.tarks.maximum進行配置,通常建議其個數為與CPU核心數目相同或者為CPU核心數目的2倍,但其最佳值通常依賴于諸多因素,而在CPU密集型的應用場景中也不應該将其最大數目設定得過高。除了CPU之外,還應該考慮每個任務所能夠使用的的heap空間大小所帶來的影響;預設情況下,Hadoop為每個任務指定了200MB的heap空間上限,由于每個job可能會申請使用很大的heap,是以,過高的設定可能會帶來意外的結果。

每個MapReduce任務可以通過mapred.reduce.tasks配置其運作的reduce任務數,通常也應該為其指定一個在多數場景下都能工作良好的預設值,比如Hadoop預設将此數目指定為1個,這對大多數任務來講都有着不錯的性能表現。而實際使用中,一般建議将此值設定為目前Hadoop叢集可以運作的reduce任務總數的0.95倍或1.75倍。0.95這個因子意味着Hadoop叢集可以立即啟動所有的reduce任務并在map任務完成時接收資料并進行處理,而1.75則意味着先啟動部分reduce任務,執行速度快的節點上的reduce完成後可再啟動一個新的reduce任務,而速度慢的節點則無須執行此類操作。這會帶來較為理想的負載均衡效果。

4.2 Hadoop狀态監測

Hadoop提供了fsck工具用于HDFS檔案系統狀态檢測,其使用文法如下:

hadoop fsck [GENERIC_OPTIONS] &lt;path&gt; [-move | -delete | -openforwrite] [-files [-blocks [-locations | -racks]]]

其中GENERIC_OPTIONS是hadoop的各子指令均支援使用的選擇,如使用-conf指定配置檔案等。在執行HDFS狀态檢測時,fsck會忽略正在被某客戶執行寫操作的檔案,這些正在被修改或寫入資料的檔案可以使用-openforwrite選項在檢測結果中予以顯示。

<code>$ hadoop </code><code>fsck</code> <code>/ -openforwrite</code>

<code>FSCK started by hadoop (auth:SIMPLE) from </code><code>/127</code><code>.0.0.1 </code><code>for</code> <code>path / at Thu Dec 06 23:19:35 CST 2012</code>

<code>.......Status: HEALTHY</code>

<code> </code><code>Total size:84064 B</code>

<code> </code><code>Total </code><code>dirs</code><code>:14</code>

<code> </code><code>Total files:7</code>

<code> </code><code>Total blocks (validated):6 (avg. block size 14010 B)</code>

<code> </code><code>Minimally replicated blocks:6 (100.0 %)</code>

<code> </code><code>Over-replicated blocks:0 (0.0 %)</code>

<code> </code><code>Under-replicated blocks:0 (0.0 %)</code>

<code> </code><code>Mis-replicated blocks:0 (0.0 %)</code>

<code> </code><code>Default replication factor:1</code>

<code> </code><code>Average block replication:1.0</code>

<code> </code><code>Corrupt blocks:0</code>

<code> </code><code>Missing replicas:0 (0.0 %)</code>

<code> </code><code>Number of data-nodes:1</code>

<code> </code><code>Number of racks:1</code>

<code>FSCK ended at Thu Dec 06 23:19:35 CST 2012 </code><code>in</code> <code>14 milliseconds</code>

<code>The filesystem under path </code><code>'/'</code> <code>is HEALTHY</code>

fsck會為每個健康狀态的檔案列印一個點号(.),如上面的輸出結果所示。同時,每個檔案其複制塊數多于、少于配置的數目、錯誤的複制塊、損壞的資料塊及缺少資料塊的相關資訊也會由fsck在執行結果中顯示。其中,多于或少于配置的數目,或錯誤的複制塊不會被視作嚴重的錯誤,而錯誤的複制塊、損壞的複制塊或缺少複制塊則意味着資料的永久性丢失。使用fsck的-delete選項則可用于在檢測過程中删除這些損壞狀态的檔案,-move選項則可用于将這些檔案移動至lost+found目錄中。

fsck指令格式中的[-files [-blocks [-locations | -racks]]]用于讓其輸出更為詳細的檢測資訊,-files後的每個選項都依賴于其前面選項,是以,要使用-blocks則必須同時使用-files,要使用-locations則必須同時使用-blocks和-files;而-locations和-racks則既可為同級别的選項,使用時二選一,也可将-racksg與-locations同時使用。-files選項用于輸出檔案自身的狀态資訊,如檔案路徑、大小、占用的資料塊及狀态;-blocks選項用于輸出每個資料塊的相關資訊;-locations用于輸出每個複制塊的具體位置;-racks則用于顯示資料節點位置的拓撲資訊。

<code>$ hadoop </code><code>fsck</code> <code>/ -openforwrite -files -blocks -locations -racks</code>

<code>FSCK started by hadoop (auth:SIMPLE) from </code><code>/127</code><code>.0.0.1 </code><code>for</code> <code>path / at Thu Dec 06 23:20:56 CST 2012</code>

<code>/ &lt;</code><code>dir</code><code>&gt;</code>

<code>/hadoop</code> <code>&lt;</code><code>dir</code><code>&gt;</code>

<code>/hadoop/temp</code> <code>&lt;</code><code>dir</code><code>&gt;</code>

<code>/hadoop/temp/mapred</code> <code>&lt;</code><code>dir</code><code>&gt;</code>

<code>/hadoop/temp/mapred/staging</code> <code>&lt;</code><code>dir</code><code>&gt;</code>

<code>/hadoop/temp/mapred/staging/hadoop</code> <code>&lt;</code><code>dir</code><code>&gt;</code>

<code>/hadoop/temp/mapred/staging/hadoop/</code><code>.staging &lt;</code><code>dir</code><code>&gt;</code>

<code>/hadoop/temp/mapred/system</code> <code>&lt;</code><code>dir</code><code>&gt;</code>

<code>/hadoop/temp/mapred/system/jobtracker</code><code>.info 4 bytes, 1 block(s):  OK</code>

<code>0. blk_8000193754097372869_1002 len=4 repl=1 [</code><code>/default-rack/127</code><code>.0.0.1:50010]</code>

<code>/user</code> <code>&lt;</code><code>dir</code><code>&gt;</code>

<code>/user/hadoop</code> <code>&lt;</code><code>dir</code><code>&gt;</code>

<code>/user/hadoop/wc-in</code> <code>&lt;</code><code>dir</code><code>&gt;</code>

<code>/user/hadoop/wc-in/functions</code> <code>14291 bytes, 1 block(s):  OK</code>

<code>0. blk_-2535948061878952264_1003 len=14291 repl=1 [</code><code>/default-rack/127</code><code>.0.0.1:50010]</code>

<code>/user/hadoop/wc-in/profile</code> <code>1426 bytes, 1 block(s):  OK</code>

<code>0. blk_5095873178802140996_1004 len=1426 repl=1 [</code><code>/default-rack/127</code><code>.0.0.1:50010]</code>

<code>/user/hadoop/wc-out</code> <code>&lt;</code><code>dir</code><code>&gt;</code>

<code>/user/hadoop/wc-out/_SUCCESS</code> <code>0 bytes, 0 block(s):  OK</code>

<code>/user/hadoop/wc-out/_logs</code> <code>&lt;</code><code>dir</code><code>&gt;</code>

<code>/user/hadoop/wc-out/_logs/history</code> <code>&lt;</code><code>dir</code><code>&gt;</code>

<code>/user/hadoop/wc-out/_logs/history/job_201212062231_0001_1354806698562_hadoop_word</code><code>+count 14687 bytes, 1 block(s):  OK</code>

<code>0. blk_-6941616318716878099_1014 len=14687 repl=1 [</code><code>/default-rack/127</code><code>.0.0.1:50010]</code>

<code>/user/hadoop/wc-out/_logs/history/localhost_1354804300040_job_201212062231_0001_conf</code><code>.xml 45504 bytes, 1 block(s):  OK</code>

<code>0. blk_438023500023782106_1011 len=45504 repl=1 [</code><code>/default-rack/127</code><code>.0.0.1:50010]</code>

<code>/user/hadoop/wc-out/part-r-00000</code> <code>8152 bytes, 1 block(s):  OK</code>

<code>0. blk_-4078455009405364683_1013 len=8152 repl=1 [</code><code>/default-rack/127</code><code>.0.0.1:50010]</code>

<code>Status: HEALTHY</code>

<code>FSCK ended at Thu Dec 06 23:20:56 CST 2012 </code><code>in</code> <code>28 milliseconds</code>

此外,也可以使用hadoop的dfsadmin列印hdfs檔案系統的狀态資訊。

<code>$ hadoop dfsadmin -report</code>

<code>Configured Capacity: 41604677632 (38.75 GB)</code>

<code>Present Capacity: 38942863360 (36.27 GB)</code>

<code>DFS Remaining: 38942621696 (36.27 GB)</code>

<code>DFS Used: 241664 (236 KB)</code>

<code>DFS Used%: 0%</code>

<code>Under replicated blocks: 0</code>

<code>Blocks with corrupt replicas: 0</code>

<code>Missing blocks: 0</code>

<code>-------------------------------------------------</code>

<code>Datanodes available: 1 (1 total, 0 dead)</code>

<code>Name: 127.0.0.1:50010</code>

<code>Decommission Status : Normal</code>

<code>Non DFS Used: 2661814272 (2.48 GB)</code>

<code>DFS Remaining: 38942621696(36.27 GB)</code>

<code>DFS Remaining%: 93.6%</code>

<code>Last contact: Thu Dec 06 23:22:28 CST 2012</code>

4.3 啟用HDFS的資源回收筒

HDFS支援檔案删除的“資源回收筒”功能,被删除的檔案不會立即從存儲空間中擦除,而是先被移入使用者家目錄中的.Trash子目錄中,當檔案删除的時長超出事先預定義的時長後就會被自動從資源回收筒中删除,在此之前,使用者可以随時恢複被删除的檔案。預設情況下,HDFS禁用了資源回收筒功能,如果想啟用,隻需要在core-site.xml配置檔案中使用fs.trash.interval定義删除檔案的保留時長即可,其時長的預設機關為分鐘,值0表示禁用資源回收筒。如下所示的例子中,定義了被删除檔案的保留時長為7天。

<code>&lt;property&gt;</code>

<code>&lt;name&gt;fs.trash.interval&lt;</code><code>/name</code><code>&gt;</code>

<code>&lt;value&gt;10080&lt;</code><code>/value</code><code>&gt;</code>

<code>&lt;</code><code>/property</code><code>&gt;</code>

五、完全分布式Hadoop

在需要時,可以通過conf/hadoop-env.sh腳本自定義Hadoop程序的環境變量,至少,JAVA_HOME是每個節點所必須事先正确定義的環境變量。另外,也可以通過HADOOP_*_OPTS為對應的Hadoop的5類程序(NameNode、DataNode、SecondaryNameNode、JobTracker和TaskTracker)定義運作參數,比如:HADOOP_NAMENODE_OPTS用于定義NameNode程序的運作參數,以此類推。

此外,HADOOP_LOG_DIR用于定義程序日志檔案的存儲目錄,HADOOP_HEAPSIZE用于定義Hadoop程序可用的堆空間大小,機關是MB,預設為1000MB。

5.1、配置Hadoop程序

5.1.1 配置NomeNode的URI

在配置檔案conf/core-site.xml中定義fs.default.name參數即可。

5.1.2 配置HDFS的相關參數

在配置檔案conf/hdfs-site.xml中定義dfs.name.dir(NameNode用于存儲名稱空間和事務日志的本地檔案系統路徑)和dfs.data.dir(DataNode用于存儲資料塊的一個或多個本地檔案系統路徑,有多個路徑時彼此間用逗号隔開)兩個參數即可。

5.1.3 配置Jobtracker和TaskTracker程序的相關參數

在conf/mapred-site.xml檔案中進行,主要有以下參數:

mapred.job.tracker:JobTracker程序所在主機的主機名(或IP)和端口;

mapred.system.dir:MapReduce用于存儲系統檔案的HDFS檔案系統路徑,如/hadoop/mapred/system/;

mapred.local.dir:MapReduce用于存儲臨時資料的本地檔案系統路徑,指定多個路徑可以分散I/O壓力,彼此間需要使用逗号分隔;

mapred.tasktracker.{map|reduce}.tasks.maximum:在每一個TaskTracker上可以運作的MapReduce任務的最大數量,預設為2(maps任務和reduces任務各兩個);

dfs.hosts/dfs.hosts.exclude:允許使用或禁止使用的DataNode清單;

mapred.hosts/mapred.hosts.exclude:允許使用或禁用的TaskTracker清單;

mapred.queue.names:可以接受送出的任務的隊列名稱清單;MapReduce至少支援一個預設的“default”隊列,是以,此參數的值清單中中必須要包含default;

mapred.queue.queue-name.acl-administer-jobs:可以檢視作業詳情的使用者群組的清單;名稱群組各自使用一個清單,兩個清單之間使用空格分隔,而每個清單内的名稱則使用逗号分隔,如:user1,user2 grp1,grp2;如果僅定義組清單而不提供使用者清單,在組清單之前加一個空白字元即可;

5.2、生産環境中常用的配置

......

5.3、安裝完全分布式Hadoop

5.3.1 安裝準備工作

本安裝示例将使用三台主機(RHEL 5.8 32bit)來實作,其規劃如下所示:

IP位址主機名運作的程序或扮演的角色

172.16.100.11 master.shine.comNameNode,JobTracker

172.16.100.12datanode.shine.comDataNode,TaskTracker

172.16.100.13snn.shine.comSecondaryNameNode

用到的應用程式:

先在叢集中的每個節點上建立運作hadoop程序的使用者hadoop并給其設定密碼。

設定叢集各節點的/etc/hosts檔案内容如下:

<code>172.16.100.11master.shine.commaster</code>

<code>172.16.100.12datanode.shine.comdatanode</code>

<code>172.16.100.13snn.shine.comsnn</code>

而後配置master節點的hadoop使用者能夠以基于密鑰的驗正方式登入其它各節點,以便啟動程序并執行監控等額外的管理工作。以下指令在master節點上執行即可。

<code>[hadoop@master ~]$ </code><code>ssh</code><code>-copy-</code><code>id</code> <code>-i .</code><code>ssh</code><code>/id_rsa</code><code>.pub hadoop@datanode</code>

<code>[hadoop@master ~]$ </code><code>ssh</code><code>-copy-</code><code>id</code> <code>-i .</code><code>ssh</code><code>/id_rsa</code><code>.pub hadoop@snn</code>

5.3.2 安裝JDK

以下操作需要在每個節點上執行一遍。

編輯/etc/profile.d/java.sh,在檔案中添加如下内容:

5.3.3 安裝Hadoop

叢集中的每個節點均需要安裝Hadoop,以根據配置或需要啟動相應的程序等,是以,以下安裝過程需要在每個節點上分别執行。

然後編輯/etc/profile,設定HADOOP_HOME環境變量的值為hadoop的解壓目錄,并讓其永久有效。編輯/etc/profile.d/hadoop.sh,添加如下内容:

<code>HADOOP_HOME=</code><code>/usr/local/hadoop</code>

<code>PATH=$HADOOP_HOME</code><code>/bin</code><code>:$PATH</code>

<code>$ hadoop version</code>

5.3.4 配置Hadoop

叢集中的每個節點上Hadoop的配置均相同,Hadoop在啟動時會根據配置檔案判定目前節點的角色及所需要運作的程序等,是以,下述的配置檔案修改需要在每一個節點上運作。

(1) 修改/usr/local/hadoop/conf/core-site.xml内容如下

<code>&lt;!-- Put site-specific property overrides </code><code>in</code> <code>this </code><code>file</code><code>. --&gt;</code>

<code>    </code><code>&lt;property&gt;</code>

<code>        </code><code>&lt;name&gt;fs.default.name&lt;</code><code>/name</code><code>&gt;</code>

<code>        </code><code>&lt;value&gt;hdfs:</code><code>//master</code><code>.shine.com:8020&lt;</code><code>/value</code><code>&gt;</code>

<code>        </code><code>&lt;final&gt;</code><code>true</code><code>&lt;</code><code>/final</code><code>&gt;</code>

<code>        </code><code>&lt;description&gt;The name of the default </code><code>file</code> <code>system. A URI whose scheme and authority determine the FileSystem implimentation.&lt;</code><code>/description</code><code>&gt;</code>

<code>    </code><code>&lt;</code><code>/property</code><code>&gt;</code>

(2)修改/usr/local/hadoop/conf/mapred-site.xml檔案為如下内容

<code>        </code><code>&lt;name&gt;mapred.job.tracker&lt;</code><code>/name</code><code>&gt;</code>

<code>        </code><code>&lt;value&gt;master.shine.com:8021&lt;</code><code>/value</code><code>&gt;</code>

<code>        </code><code>&lt;description&gt;The host and port that the MapReduce JobTracker runs at. &lt;</code><code>/description</code><code>&gt;</code>

(3) 修改/usr/local/hadoop/conf/hdfs-site.xml檔案為如下内容 

<code>&lt;name&gt;dfs.replication&lt;</code><code>/name</code><code>&gt;</code>

<code>&lt;value&gt;1&lt;</code><code>/value</code><code>&gt;</code>

<code>&lt;description&gt;The actual number of replications can be specified when the </code><code>file</code> <code>is created.&lt;</code><code>/description</code><code>&gt;</code>

<code>        </code><code>&lt;name&gt;dfs.data.</code><code>dir</code><code>&lt;</code><code>/name</code><code>&gt;</code>

<code>        </code><code>&lt;value&gt;</code><code>/hadoop/data</code><code>&lt;</code><code>/value</code><code>&gt;</code>

<code>        </code><code>&lt;final&gt;ture&lt;</code><code>/final</code><code>&gt;</code>

<code>        </code><code>&lt;description&gt;The directories where the datanode stores blocks.&lt;</code><code>/description</code><code>&gt;</code>

<code>        </code><code>&lt;name&gt;dfs.name.</code><code>dir</code><code>&lt;</code><code>/name</code><code>&gt;</code>

<code>        </code><code>&lt;value&gt;</code><code>/hadoop/name</code><code>&lt;</code><code>/value</code><code>&gt;</code>

<code>        </code><code>&lt;description&gt;The directories where the namenode stores its persistent matadata.&lt;</code><code>/description</code><code>&gt;</code>

<code>        </code><code>&lt;name&gt;fs.checkpoint.</code><code>dir</code><code>&lt;</code><code>/name</code><code>&gt;</code>

<code>        </code><code>&lt;value&gt;</code><code>/hadoop/namesecondary</code><code>&lt;</code><code>/value</code><code>&gt;</code>

<code>        </code><code>&lt;description&gt;The directories where the secondarynamenode stores checkpoints.&lt;</code><code>/description</code><code>&gt;</code>

說明:根據此配置,需要事先在各節點上建立/hadoop/,并讓hadoop使用者對其具有全部權限。也可以不指定最後三個屬性,讓Hadoop為其使用預設位置。

(4)修改/usr/local/hadoop/conf/masters檔案,指定SecondaryNameNode節點的主機名或IP位址,本示例中為如下内容:

snn.shine.com

(5)修改/usr/local/hadoop/conf/slaves檔案,指定各DataNode節點的主機名或IP位址,本示例中隻有一個DataNode:

datanode.shine.com

(6)初始化資料節點,在master上執行如下指令

5.3.5 啟動Hadoop

在master節點上執行Hadoop的start-all.sh腳本即可實作啟動整個叢集。

<code>[hadoop@master ~]$ start-all.sh</code>

其輸出内容如下所示:

<code>starting namenode, logging to </code><code>/usr/local/hadoop/logs/hadoop-hadoop-namenode-master</code><code>.shine.com.out</code>

<code>datanode.shine.com: starting datanode, logging to </code><code>/usr/local/hadoop/logs/hadoop-hadoop-datanode-datanode</code><code>.shine.com.out</code>

<code>snn.shine.com: starting secondarynamenode, logging to </code><code>/usr/local/hadoop/logs/hadoop-hadoop-secondarynamenode-node3</code><code>.shine.com.out</code>

<code>starting jobtracker, logging to </code><code>/usr/local/hadoop/logs/hadoop-hadoop-jobtracker-master</code><code>.shine.com.out</code>

<code>datanode.shine.com: starting tasktracker, logging to </code><code>/usr/local/hadoop/logs/hadoop-hadoop-tasktracker-datanode</code><code>.shine.com.out</code>

如果要停止Hadoop的各程序,則使用stop-all.sh腳本即可。

不過,在一個較大規模的叢集環境中,NameNode節點需要在内在中維護整個名稱空間中的檔案和塊的中繼資料資訊,是以,其有着較大的内在需求;而在運作着衆多MapReduce任務的環境中,JobTracker節點會用到大量的記憶體和CPU資源,是以,此場景中通常需要将NameNode和JobTracker運作在不同的實體主機上,這也意味着HDFS叢集的主從節點與MapReduce的主從節點将分屬于不同的拓撲。啟動HDFS的主從程序則需要在NameNode節點上使用start-dfs.sh腳本,而啟動MapReduce的各程序則需要在JobTracker節點上通過start-mapred.sh腳本進行。這兩個腳本事實上都是通過hadoop-daemons.sh腳本來完成程序啟動的。

5.4 環境設定

5.4.1 記憶體設定

預設情況下,Hadoop為每個程序配置設定1000MB(1GB)的記憶體空間,但這可以在hadoop-env.sh檔案中通過HADOOP_HEAPSIZE環境變量進行調整。此外,TaskTracker會為worker主機上的每個map或reduce任務的分别啟動一個JVM,這些JVM都需要在程序的HEAP中申請用到記憶體空間。每個TaskTracker可同時運作的map任務總數和reduce任務總數分别由mapred.tasktracker.map.tasks.maximum和mapred.tasktracker.reduce.tasks.maximum這兩個屬性進行指定,而它們的預設值都為2。用于運作map或reduce任務的JVM可用記憶體大小可由mapred.child.java.opts屬性指定,其預設設定為-Xmx200m,意指每個任務可以使用最多200MB的記憶體空間。由此算來,每個worker主機預設将使用2800MB的記憶體空間。

除了使用mapred.child.java.opts為每個JVM為map任務和reduce任務設定相同可用記憶體屬性之外,還可以使用mapreduce.map.java.opts和mapreduce.reduce.java.opts分别設定map任務和reduce任務的JVM可用記憶體的屬性。

在TaskTracker上可同時運作的任務數取決于其主機的CPU數量。由于MapReduce作業大多為I/O密集型應用,是以,讓同行運作任務數多于CPU的個數可以提高資源利用效率,其可以多出的數量取決于實際的作業本身。這裡有一個通用法則,即讓同行運作的作業數量為CPU數量的1至2之間的數字倍數,比如作業數1.5倍于CPU數。與此同時,一定要注意系統上可用記憶體的數量是否符合任務數的設定,比如在一個4顆CPU的DataNode上,可以設定mapred.tasktracker.map.tasks.maximum和mapred.tasktrackers.reduce.tasks.maximum屬性的值都為3(不是4個,因為datanode和tasktracker都是運作的任務,它們要占去兩個名額),假設每個任務的可用記憶體為400MB,那麼這些作業總共需要的記憶體數為6*400MB,即2.4GB,考慮到作業系統及其它程序所需用的記憶體等,這個數值可能需要更大。

在hadoop-env.sh檔案中,可以使用HADOOP_NAMENODE_OPTS、HADOOP_SECONDARYNAMENODE_OPTS、HADOOP_DATANODE_OPTS、HADOOP_BALANCER_OPTS、HADOOP_JOBTRACKER_OPTS變量分别為對應的5類程序設定運作參數,比如可以使用HADOOP_NAMENODE_OPTS單獨設定namenode程序使用不的HEAPSIZE大小。

5.4.2 Hadoop日志

Hadoop的系統日志預設存放于其安裝目錄中的logs子目錄,如果需要自定義其存儲位置,可以在hadoop-env.sh中設定HADOOP_LOG_DIR環境變量來指定新位置。Hadoop的每個程序均會生成兩個日志檔案,一個是由log4j生成的并以.log為字尾的日志檔案,另一個是以.out為字尾的日志檔案,它負責記錄發往标準輸出和錯誤輸出的資訊。

大多數應用的日志住處均發送至.log類的檔案中,是以在故障排查時其也是最需要關注的日志檔案。然後,Hadoop為log4j提供的預設配置中,其每天會自動做一次日志滾動,并且永遠不會删除日志檔案,是以,管理者需要手動歸檔并删除老舊的日志檔案。.out類的日志檔案中很少出現資訊,而且,Hadoop的每次重新開機都會導緻日志自動滾動,并隻會儲存最至5次的滾動日志檔案版本。

除了字尾不同之外,這兩種日志檔案的名稱格式是一樣的,預設均為hadoop-&lt;username&gt;-&lt;processname&gt;-&lt;hostname&gt;,比如hadoop-hadoop-namenode-master.shine.com.log。可以在hadoop-env.sh檔案中使用HADOOP_IDENT_STRING變量将日志檔案名稱格式中的&lt;username&gt;限制為所需要的字元串。

5.4.3 SSH相關的設定

Hadoop運作時,它利用控制腳本(如start-dfs.sh)在master節點上基于SSH遠端管理各worker節點上的程序,是以,為SSH設定合适的參數将用助于Hadoop的健壯性,如合适的連接配接逾時時間(ConnectTimeout)将有助于Hadoop避免被失效的節點阻塞,将StrictHostKeyChecking設定為no将能夠使得master自動添加各節點的主機密鑰等。

Hadoop的控制腳本可以使用rsync将配置檔案同步至叢集中的其它節點,預設為禁用。如果需要,可以通過HADOOP_MASTER變量将其啟用。不過,由于各點上HADOOP_MASTER預設均為禁用,是以,其第一次配置還是需要其它的方式進行。

其它各SSH相關參數說明及其用法在hadoop-env.sh中均有詳細注釋,是以,這裡不再給出進一步資訊。

5.5 Hadoop的其它常用屬性

5.5.1 緩沖大小(Buffer size)

Hadoop為其I/O操作使用了4KB的緩沖區容量,這個值是相當保守的。在當今的硬體和作業系統上,可以安全地增大此值以提高系統性能;一般說來,128KB(131072 bytes)是比較理想的設定。如果需要,可以在core-site.xml中通過io.file.buffer.size屬性進行定義。

5.5.2 HDFS塊大小

HDFS預設塊大小為64MB,然而128MB(134,217,728 bytes)是更常用的設定,甚至有些叢集中使用了256MB。較大的塊可以有效降低NameNode上的記憶體壓力,并能支援使用更多的資料量。如果需要,可以在hdfs-site.xml檔案中使用dfs.block.size屬性進行定義。

5.5.3 慢啟動Reduce任務

在一個作業中,預設情況下排程器會在map任務完成5%時開始排程啟動目前作業的reduce任務。對于較大的作業來說,過早地啟動reduce會導緻叢集性能的下降。在mapred-site.xml檔案中為mapred.reduce.slowstart.completed.maps屬性來設定一個更大的值(比如0.8,即80%)可以在更晚的時間點啟動reduce作業。

本文轉自 SoulMio 51CTO部落格,原文連結:http://blog.51cto.com/bovin/1886990,如需轉載請自行聯系原作者