閱讀335 返回首頁    go 阿裏雲 go 技術社區[雲棲]


用 Hadoop 進行分布式數據處理,從 入門、進階到應用開發

入門

簡介: 本文是討論 Hadoop 的係列中的第一篇。本文介紹 Hadoop 框架,包括 Hadoop 文件係統 (HDFS) 等基本元素和常用的節點類型。學習如何安裝和配置單節點 Hadoop 集群,然後研究 MapReduce 應用程序。最後,學習使用核心 Web 界麵監視和管理 Hadoop 的方法。

盡管 Hadoop 是一些大型搜索引擎數據縮減功能的核心部分,但是它實際上是一個分布式數據處理框架。搜索引擎需要收集數據,而且是數量極大的數據。作為分布式框架,Hadoop 讓許多應用程序能夠受益於並行數據處理。

本文並不打算介紹 Hadoop 及其架構,而是演示一個簡單的 Hadoop 設置。在 參考資料 中,可以找到關於 Hadoop 架構、組件和操作理論的更多信息。現在,我們來討論 Hadoop 的安裝和配置。

初始設置

對於本文中的示例,我們使用 Cloudera Hadoop 發行版。Cloudera 提供對各種 Linux® 發行版的支持,所以很適合初學者。

本文假設您的係統上已經安裝了 Java™(至少是 1.6 版)和 cURL。如果還沒有,需要先安裝它們(更多信息見 參考資料)。

因為我運行 Ubuntu(Intrepid 版),所以使用 apt 實用程序獲取 Hadoop 發行版。這個過程非常簡單,我可以獲取二進製包,而不需要下載並構建源代碼。首先,告訴 apt Cloudera 站點的信息。然後,在 /etc/apt/sources.list.d/cloudera.list 中創建一個新文件並添加以下文本:

deb https://archive.cloudera.com/debian intrepid-cdh3 contrib
deb-src https://archive.cloudera.com/debian intrepid-cdh3 contrib

如果您運行 Jaunty 或其他版本,隻需把 intrepid 替換為您的版本名(當前支持 Hardy、Intrepid、Jaunty、Karmic 和 Lenny)。

接下來,從 Cloudera 獲取 apt-key 以檢查下載的包:

$ curl -s https://archive.cloudera.com/debian/archive.key | \
sudo apt-key add - sudo apt-get update

然後,安裝采用偽分布式配置的 Hadoop(所有 Hadoop 守護進程在同一個主機上運行):

$ sudo apt-get install hadoop-0.20-conf-pseudo
$

注意,這個配置大約 23MB(不包括 apt 可能下載的其他包)。這個配置非常適合體驗 Hadoop 以及了解它的元素和界麵。

最後,我設置了不需要密碼的 SSH。如果打算使用 ssh localhost 並請求密碼,就需要執行以下步驟。我假設這是專用的 Hadoop 機器,因為這個步驟對安全性有影響(見清單 1)。

清單1:設置不需要密碼的SSH

$ sudo su -
# ssh-keygen -t dsa -P '' -f ~/.ssh/id_dsa
# cat ~/.ssh/id_dsa.pub >> ~/.ssh/authorized_keys

最後,需要確保主機上有供 datanode使用的足夠存儲空間(緩存)。存儲空間不足會導致係統表現異常(比如出現無法把數據複製到節點的錯誤)。

啟動Hadoop

現在可以啟動 Hadoop 了,這實際上要啟動每個 Hadoop 守護進程。但是,首先使用 hadoop 命令對 Hadoop File System (HDFS) 進行格式化。hadoop 命令有許多用途,稍後討論其中一部分。

首先,請求 namenode 對 DFS 文件係統進行格式化。在安裝過程中完成了這個步驟,但是了解是否需要生成幹淨的文件係統是有用的。

# hadoop-0.20 namenode -format

在確認請求之後,文件係統進行格式化並返回一些信息。接下來,啟動 Hadoop 守護進程。Hadoop 在這個偽分布式配置中啟動 5 個守護進程:namenode、secondarynamenode、datanode、jobtracker 和 tasktracker。在啟動每個守護進程時,會看到一些相關信息(指出存儲日誌的位置)。每個守護進程都在後台運行。圖 1 說明完成啟動之後偽分布式配置的架構。

圖1偽分布式hadoop配置

偽分布式 Hadoop 配置的框圖 

Hadoop 提供一些簡化啟動的輔助工具。這些工具分為啟動(比如 start-dfs)和停止(比如 stop-dfs)兩類。下麵的簡單腳本說明如何啟動 Hadoop 節點:

# /usr/lib/hadoop-0.20/bin/start-dfs.sh
# /usr/lib/hadoop-0.20/bin/start-mapred.sh
#

要想檢查守護進程是否正在運行,可以使用 jps 命令(這是用於 JVM 進程的 ps 實用程序)。這個命令列出 5 個守護進程及其進程標識符。

既然 Hadoop 守護進程已經在運行了,現在看看每個守護進程在 Hadoop 框架中的作用。namenode 是 Hadoop 中的主服務器,它管理文件係統名稱空間和對集群中存儲的文件的訪問。還有一個 secondary namenode,它不是 namenode 的冗餘守護進程,而是提供周期檢查點和清理任務。在每個 Hadoop 集群中可以找到一個 namenode 和一個 secondary namenode。

datanode 管理連接到節點的存儲(一個集群中可以有多個節點)。每個存儲數據的節點運行一個 datanode 守護進程。

最後,每個集群有一個 jobtracker,它負責調度 datanode 上的工作。每個 datanode 有一個 tasktracker,它們執行實際工作。jobtracker 和 tasktracker 采用主-從形式,jobtracker 跨 datanode 分發工作,而 tasktracker 執行任務。jobtracker 還檢查請求的工作,如果一個 datanode 由於某種原因失敗,jobtracker 會重新調度以前的任務。

在這個簡單的配置中,所有節點都駐留在同一個主機上(見 圖 1)。但是,通過前麵的討論很容易看出 Hadoop 如何提供並行處理。盡管架構很簡單,但是 Hadoop 能夠方便地實現數據分發、負載平衡以及以容錯的方式並行處理大量數據。

檢查hdfs

可以通過幾個檢查確認 Hadoop(至少是 namenode)已經啟動並正常運行。確認所有進程都在運行之後,可以使用 hadoop 命令檢查本地名稱空間(見清單 2)。

清單2檢查對hdfs的訪問
				
# hadoop-0.20 fs -ls /
Found 2 items
drwxr-xr-x   - root supergroup          0 2010-04-29 16:38 /user
drwxr-xr-x   - root supergroup          0 2010-04-29 16:28 /var
#

可以看出 namenode 已經啟動,能夠為本地名稱空間提供服務。注意,使用 hadoop-0.20 命令檢查文件係統。這個實用程序用於與 Hadoop 集群交互,包括檢查文件係統、在集群中運行作業等等。請注意命令的結構:指定 hadoop-0.20 實用程序之後,定義一個命令(在這裏是通用文件係統 shell)以及一個或多個選項(在這裏使用 ls 請求文件列表)。因為 hadoop-0.20 是 Hadoop 集群的主要接口之一,您會看到本文中多次使用這個實用程序。清單 3 提供另外幾個文件係統操作示例(創建子目錄 test,列出它的內容,然後刪除它),可以通過它們進一步了解這個接口。

清單3hdfs中文件係統操作
# hadoop-0.20 fs -mkdir test
# hadoop-0.20 fs -ls test
# hadoop-0.20 fs -rmr test
Deleted hdfs://localhost/user/root/test
# 

既然已經安裝了 Hadoop 並測試了文件係統的基本接口,現在就該在真實的應用程序中測試 Hadoop 了。在這個示例中,我們使用 MapReduce 處理一個小數據集。map(映射) 和 reduce(縮減) 源自函數式編程中的函數名,但是這個應用程序的核心功能是數據縮減。映射 是指把大量輸入處理成更小的子問題集(然後把這些子問題分發給並行的工作係統)。縮減 是指把子問題的答案組合成單一輸出集。注意,這裏沒有定義處理 的含義,因為框架允許您自己定義什麼是處理。典型的 MapReduce 示例是計算單詞在文檔集中出現的頻率。

根據前麵的討論,我們需要一個輸入集並產生一個輸出集。第一步是在文件係統中創建一個 input 子目錄,工作將放在這個目錄中。使用以下命令:

# hadoop-0.20 fs -mkdir input

接下來,在 input 目錄中放一些工作。在這裏,使用 put 命令把文件從本地文件係統轉移到 HDFS 中(見清單 4)。注意,下麵的命令格式把源文件轉移到 HDFS 子目錄 (input) 中。完成之後,在 HDFS 中就有兩個文本文件等待處理。

清單4把文件轉移到hdfs中
				
# hadoop-0.20 fs -put /usr/src/linux-source-2.6.27/Doc*/memory-barriers.txt  input
# hadoop-0.20 fs -put /usr/src/linux-source-2.6.27/Doc*/rt-mutex-design.txt  input
#

接下來,使用 ls 命令檢查文件是否存在(見清單 5)。

清單5 檢查hdfs中的文件
# hadoop-0.20 fs -ls input
Found 2 items
-rw-r--r--  1 root supergroup 78031 2010-04-29 17:35 /user/root/input/memory-barriers.txt
-rw-r--r--  1 root supergroup 33567 2010-04-29 17:36 /user/root/input/rt-mutex-design.txt 
#

確認工作已經放在 HDFS 中之後,就可以執行 MapReduce 函數了。這個函數隻需要一個命令,但是需要很長的請求,見清單 6。這個命令請求執行一個 JAR。它實際上實現許多功能,但是這個示例隻使用 wordcount。jobtracker 守護進程請求 datanode 執行 MapReduce 作業,這會產生相當多的輸出(這裏的輸出比較少是因為隻處理兩個文件)。它顯示 map 和 reduce 函數的進度,然後提供與文件係統的 I/O 和記錄處理相關的統計數據。

清單6執行計算單詞頻率的MapReduce程序
# hadoop-0.20 jar /usr/lib/hadoop-0.20/hadoop-0.20.2+228-examples.jar \
wordcount input output
10/04/29 17:36:49 INFO input.FileInputFormat: Total input paths to process : 2
10/04/29 17:36:49 INFO mapred.JobClient: Running job: job_201004291628_0009
10/04/29 17:36:50 INFO mapred.JobClient:  map 0% reduce 0%
10/04/29 17:37:00 INFO mapred.JobClient:  map 100% reduce 0%
10/04/29 17:37:06 INFO mapred.JobClient:  map 100% reduce 100%
10/04/29 17:37:08 INFO mapred.JobClient: Job complete: job_201004291628_0009
10/04/29 17:37:08 INFO mapred.JobClient: Counters: 17
10/04/29 17:37:08 INFO mapred.JobClient:   Job Counters 
10/04/29 17:37:08 INFO mapred.JobClient:     Launched reduce tasks=1
10/04/29 17:37:08 INFO mapred.JobClient:     Launched map tasks=2
10/04/29 17:37:08 INFO mapred.JobClient:     Data-local map tasks=2
10/04/29 17:37:08 INFO mapred.JobClient:   FileSystemCounters
10/04/29 17:37:08 INFO mapred.JobClient:     FILE_BYTES_READ=47556
10/04/29 17:37:08 INFO mapred.JobClient:     HDFS_BYTES_READ=111598
10/04/29 17:37:08 INFO mapred.JobClient:     FILE_BYTES_WRITTEN=95182
10/04/29 17:37:08 INFO mapred.JobClient:     HDFS_BYTES_WRITTEN=30949
10/04/29 17:37:08 INFO mapred.JobClient:   Map-Reduce Framework
10/04/29 17:37:08 INFO mapred.JobClient:     Reduce input groups=2974
10/04/29 17:37:08 INFO mapred.JobClient:     Combine output records=3381
10/04/29 17:37:08 INFO mapred.JobClient:     Map input records=2937
10/04/29 17:37:08 INFO mapred.JobClient:     Reduce shuffle bytes=47562
10/04/29 17:37:08 INFO mapred.JobClient:     Reduce output records=2974
10/04/29 17:37:08 INFO mapred.JobClient:     Spilled Records=6762
10/04/29 17:37:08 INFO mapred.JobClient:     Map output bytes=168718
10/04/29 17:37:08 INFO mapred.JobClient:     Combine input records=17457
10/04/29 17:37:08 INFO mapred.JobClient:     Map output records=17457
10/04/29 17:37:08 INFO mapred.JobClient:     Reduce input records=3381

處理結束之後,檢查結果。這個作業的作用是計算單詞在輸入文件中出現的次數。輸出是一個包含元組的文件,元組表示單詞和它在輸入中出現的次數。找到輸出文件之後,可以通過 hadoop-0.20 實用程序使用 cat 命令查看數據(見清單 7)。

清單7 檢查MapReduce計算wordcount的輸出結果
# hadoop-0.20 fs -ls /user/root/output
Found 2 items
drwxr-xr-x   - root supergroup          0 2010-04-29 17:36 /user/root/output/_logs
-rw-r--r--   1 root supergroup      30949 2010-04-29 17:37 /user/root/output/part-r-00000
#  
# hadoop-0.20 fs -cat output/part-r-00000 | head -13
!= 1
"Atomic 2
"Cache 2
"Control 1
"Examples 1
"Has 7
"Inter-CPU 1
"LOAD 1
"LOCK" 1
"Locking 1
"Locks 1
"MMIO 1
"Pending 5
#

還可以使用 hadoop-0.20 實用程序從 HDFS 中提取文件(見清單 8)。隻需使用 get 實用程序(它與前麵在 HDFS 中寫文件所用的put 相似)。對於 get 操作,指定 HDFS 中要提取的文件(來自 output 子目錄)和在本地文件係統中要寫的文件 (output.txt)。

清單8 從hdfs中提取輸出
# hadoop-0.20 fs -get output/part-r-00000 output.txt
# cat output.txt | head -5
!= 1
"Atomic 2
"Cache 2
"Control 1
"Examples 1
# 

我們再來看一個示例,它使用相同的 JAR,但是目的不同(在這裏要試驗並行的 grep)。對於這個測試,仍然使用現有的輸入文件,但是要刪除 output 子目錄以便在測試時重新創建它:

# hadoop-0.20 fs -rmr output
Deleted hdfs://localhost/user/root/output

接下來,請求用於執行 grep 的 MapReduce 作業。在這種情況下,並行執行 grep(映射),然後組合 grep 的結果(縮減)。清單 9 給出這個使用模型的輸出(為了簡短,這裏刪除了一些輸出)。注意,這裏的命令請求是一個 grep,它從 input 子目錄獲取輸入,把結果放在 output 子目錄中。最後一個參數是要搜索的字符串(在這裏是 'kernel')。

清單9執行單詞計數的搜索mapreduce作業(grep)
# hadoop-0.20 jar /usr/lib/hadoop/hadoop-0.20.2+228-examples.jar \
grep input output 'kernel'
10/04/30 09:22:29 INFO mapred.FileInputFormat: Total input paths to process : 2
10/04/30 09:22:30 INFO mapred.JobClient: Running job: job_201004291628_0010
10/04/30 09:22:31 INFO mapred.JobClient:  map 0% reduce 0%
10/04/30 09:22:42 INFO mapred.JobClient:  map 66% reduce 0%
10/04/30 09:22:45 INFO mapred.JobClient:  map 100% reduce 0%
10/04/30 09:22:54 INFO mapred.JobClient:  map 100% reduce 100%
10/04/30 09:22:56 INFO mapred.JobClient: Job complete: job_201004291628_0010
10/04/30 09:22:56 INFO mapred.JobClient: Counters: 18
10/04/30 09:22:56 INFO mapred.JobClient:   Job Counters 
10/04/30 09:22:56 INFO mapred.JobClient:     Launched reduce tasks=1
10/04/30 09:22:56 INFO mapred.JobClient:     Launched map tasks=3
10/04/30 09:22:56 INFO mapred.JobClient:     Data-local map tasks=3
10/04/30 09:22:56 INFO mapred.JobClient:   FileSystemCounters
10/04/30 09:22:56 INFO mapred.JobClient:     FILE_BYTES_READ=57
10/04/30 09:22:56 INFO mapred.JobClient:     HDFS_BYTES_READ=113144
10/04/30 09:22:56 INFO mapred.JobClient:     FILE_BYTES_WRITTEN=222
10/04/30 09:22:56 INFO mapred.JobClient:     HDFS_BYTES_WRITTEN=109
...
10/04/30 09:23:14 INFO mapred.JobClient:     Map output bytes=15
10/04/30 09:23:14 INFO mapred.JobClient:     Map input bytes=23
10/04/30 09:23:14 INFO mapred.JobClient:     Combine input records=0
10/04/30 09:23:14 INFO mapred.JobClient:     Map output records=1
10/04/30 09:23:14 INFO mapred.JobClient:     Reduce input records=1
#

作業完成之後,檢查 output 目錄,找到結果文件,然後通過執行文件係統 cat 操作查看其內容(見清單 10)。

清單10檢查MapReduce的輸出結果

# hadoop-0.20 fs -ls output
Found 2 items
drwxr-xr-x  - root supergroup    0 2010-04-30 09:22 /user/root/output/_logs
-rw-r--r--  1 root supergroup   10 2010-04-30 09:23 /user/root/output/part-00000
# hadoop-0.20 fs -cat output/part-00000
17 kernel
# 

基於web的界麵

您已經知道如何檢查 HDFS 了,但是如果要尋找 Hadoop 的操作的相關信息,會發現 Web 界麵很有用。位於 Hadoop 集群最上層的是 namenode,它管理 HDFS。可以通過 https://localhost:50070 查看文件係統的高層信息(比如可用空間、已用空間和可用的 datanode)以及正在運行的作業。可以通過 https://localhost:50030 深入檢查 jobtracker(作業狀態)。注意,在這兩種情況下都引用 localhost,因為所有守護進程都在同一個主機上運行。


進階

分布式Hadoop的架構

根據 用 Hadoop 進行分布式數據處理,第 1 部分:入門,所有 Hadoop 守護進程都在同一個主機上運行。盡管不運用 Hadoop 的並行性,這個偽分布式配置提供一種簡單的方式來以最少的設置測試 Hadoop 的功能。現在,讓我們使用機器集群探討一下 Hadoop 的並行性。

根據第 1 部分,Hadoop 配置定義了讓所有 Hadoop 守護進程在一個節點上運行。因此,讓我們首先看一下如何自然分布 Hadoop 來執行並行操作。在一個分布式 Hadoop 設置中,您有一個主節點和一些從節點(見圖 1)。


圖1 hadoop主從節點的分解
Hadoop 主從節點分解 

如圖 1 所示,主節點包括名稱節點、從屬名稱節點和 jobtracker 守護進程(即所謂的主守護進程)。此外,這是您為本演示管理集群所用的節點(使用 Hadoop 實用程序和瀏覽器)。從節點包括 tasktracker 和數據節點(從屬守護進程)。兩種設置的不同之處在於,主節點包括提供 Hadoop 集群管理和協調的守護進程,而從節點包括實現 Hadoop 文件係統(HDFS)存儲功能和 MapReduce 功能(數據處理功能)的守護進程。

對於該演示,在一個 LAN 上創建一個主節點和兩個從節點。設置如圖 2 所示。現在,我們來探討用於多節點分布的 Hadoop 的安裝和配置。

圖2 hadoop集群設計
Hadoop 集群配置 

為簡化部署,要運用虛擬化技術,該技術有幾個好處。盡管在該設置中使用虛擬化技術看不出性能優勢,但是它可以創建一個 Hadoop 安裝,然後為其他節點克隆該安裝。為此,您的 Hadoop 集群應顯示如下:在一個主機上的虛擬機監控程序上下文中將主從節點作為虛擬機(VM)運行(見圖 3)。

圖3虛擬環境中的hadoop配置
虛擬環境中的 Hadoop 集群配置

升級hadoop 

在 用 Hadoop 進行分布式數據處理,第 1 部分:入門 中,我們安裝了在一個節點上運行的 Hadoop 的一個特殊分布(偽配置)。在本文中,我們要更新分布式配置。如果您沒有看過本係列的第 1 部分,那麼請閱讀第 1 部分,了解如何首先安裝 Hadoop 偽配置。

在偽配置中,您沒有進行任何配置,因為單個節點已經過預先配置。現在,您需要更新配置。首先,使用 update-alternatives 命令檢查當前配置,如清單 1 所示。該命令告訴您,配置在使用 conf.pseudo(最高優先級)。

清單1檢查當前hadoop配置

$ update-alternatives --display hadoop-0.20-conf
hadoop-0.20-conf - status is auto.
 link currently points to /etc/hadoop-0.20/conf.pseudo
/etc/hadoop-0.20/conf.empty - priority 10
/etc/hadoop-0.20/conf.pseudo - priority 30
Current `best' version is /etc/hadoop-0.20/conf.pseudo.
$ 

下一步,通過複製現有配置(本例中為 conf.empty,如清單 1 所示)創建一個新配置:

$ sudo cp -r /etc/hadoop-0.20/conf.empty /etc/hadoop-0.20/conf.dist
$ 

最後,激活並檢查新配置:

清單2 激活並檢查hadoop配置
$ sudo update-alternatives --install /etc/hadoop-0.20/conf hadoop-0.20-conf \
  /etc/hadoop-0.20/conf.dist 40
$ update-alternatives --display hadoop-0.20-conf
hadoop-0.20-conf - status is auto.
 link currently points to /etc/hadoop-0.20/conf.dist
/etc/hadoop-0.20/conf.empty - priority 10
/etc/hadoop-0.20/conf.pseudo - priority 30
/etc/hadoop-0.20/conf.dist - priority 40
Current `best' version is /etc/hadoop-0.20/conf.dist.
$

現在,您有一個名為 conf.dist 的新配置,您要將其用於您的新分布式配置。此時該節點運行於一個虛擬環境中,將該節點克隆到另外兩個要充當數據節點的節點中。

配置hadoop以實現分布式操作

下一步是要使所有節點互聯互通。這可以 /etc/hadoop-0.20/conf.dist/ 中的兩個名為 masters 和 slaves 的文件中實現。本例中的三個節點的 IP 地址是靜態分配的,如清單 3 所示(來自 /etc/hosts):

清單3 改設置的hadoop節點
master 192.168.108.133
slave1 192.168.108.134
slave2 192.168.108.135

因此,在主節點上,更新 /etc/hadoop-0.20/conf.dist/masters 來確定主節點,如下所示:

master

然後在 /etc/hadoop-0.20/conf.dist/slaves 中確定從節點, 其中包括以下兩行:

slave1
slave2

接下來,從每個節點上,將 Secure Shell (ssh) 連接到所有其他節點,確保 pass-phraseless ssh 在運行。所有這些文件(masters,slaves)都由本係列第 1 部分中使用過的 Hadoop 啟動和停止工具使用。

下一步,在 /etc/hadoop-0.20/conf.dist 子目錄中繼續進行 Hadoop 配置。以下變更需要應用於所有節點(主節點和從節點),如同 Hadoop 文檔中所定義的。首先,在 core-site.xml 文件(清單 4)中確定 HDFS 主節點,它定義名稱節點的主機和端口(注意主節點的 IP 地址的使用)。core-site.xml 文件定義 Hadoop 的核心屬性。

清單 4 在core-site.xml中定義主節點
<configuration>

  <property>
    <name>fs.default.name<name>
    <value>hdfs://master:54310<value>
    <description>The name and URI of the default FS.</description>
  <property>

<configuration>

下一步,確認 MapReduce jobtracker。jobtracker 位於其自己的節點上,但對於本配置,將其放在主節點上,如清單 5 所示。mapred-site.xml 文件包含 MapReduce 屬性。

清單5 在mapred-site.xml中確認mapreduce 
<configuration>

  <property>
    <name>mapred.job.tracker<name>
    <value>master:54311<value>
    <description>Map Reduce jobtracker<description>
  <property>

<configuration>

最後,定義默認複製因子(清單 6)。該值定義將創建的副本數,一般小於 3。在本例中,將其定義為 2(數據節點的數量)。該值在包含 HDFS 屬性的 hdfs-site.xml 中定義。

清單6 在hdfs-site.xml中定義默認數據副本
<configuration>

  <property>
    <name>dfs.replication<name>
    <value>2<value>
    <description>Default block replication<description>
  <property>

<configuration>

配置項如 清單 4 所示,分布式設置所需的元素見 清單 5 和 清單 6。Hadoop 在這裏提供大量配置選項,支持您按需定製整個環境。參考資料 部分含有關於這些選項的更多信息。

完成配置之後,下一步是要格式化名稱節點(HDFS 主節點)。對於該操作,使用 hadoop-0.20 實用程序指定名稱節點和操作(-format):

清單7 格式化名稱節點
user@master:~# sudo su -
root@master:~# hadoop-0.20 namenode -format
10/05/11 18:39:58 INFO namenode.NameNode: STARTUP_MSG: 
/************************************************************
STARTUP_MSG: Starting NameNode
STARTUP_MSG:   host = master/127.0.1.1
STARTUP_MSG:   args = [-format]
STARTUP_MSG:   version = 0.20.2+228
STARTUP_MSG:   build =  -r cfc3233ece0769b11af9add328261295aaf4d1ad; 
************************************************************/
10/05/11 18:39:59 INFO namenode.FSNamesystem: fsOwner=root,root
10/05/11 18:39:59 INFO namenode.FSNamesystem: supergroup=supergroup
10/05/11 18:39:59 INFO namenode.FSNamesystem: isPermissionEnabled=true
10/05/11 18:39:59 INFO common.Storage: Image file of size 94 saved in 0 seconds.
10/05/11 18:39:59 INFO common.Storage: 
  Storage directory /tmp/hadoop-root/dfs/name has been successfully formatted.
10/05/11 18:39:59 INFO namenode.NameNode: SHUTDOWN_MSG: 
/************************************************************
SHUTDOWN_MSG: Shutting down NameNode at master/127.0.1.1
************************************************************/
root@master:~# 

格式化名稱節點之後,就可以啟動 Hadoop 守護進程了。可以對第 1 部分中的偽分布式配置執行同樣的操作,但進程為分布式配置完成同樣的工作。注意,這裏的代碼啟動名稱節點和從屬名稱節點(正如 jps 命令所指示):

清單8 啟動名稱節點
root@master:~# /usr/lib/hadoop-0.20/bin/start-dfs.sh
starting namenode, logging to 
  /usr/lib/hadoop-0.20/bin/../logs/hadoop-root-namenode-mtj-desktop.out
192.168.108.135: starting datanode, logging to 
  /usr/lib/hadoop-0.20/bin/../logs/hadoop-root-datanode-mtj-desktop.out
192.168.108.134: starting datanode, logging to 
  /usr/lib/hadoop-0.20/bin/../logs/hadoop-root-datanode-mtj-desktop.out
192.168.108.133: starting secondarynamenode, 
  logging to /usr/lib/hadoop-0.20/logs/hadoop-root-secondarynamenode-mtj-desktop.out
root@master:~# jps
7367 NameNode
7618 Jps
7522 SecondaryNameNode
root@master:~# 

現在,如果使用 jps 節點檢測其中一個從節點(數據節點),您會看到每個節點上都有一個數據節點守護進程:

清單9 訪問其中一個從節點的數據節點
root@slave1:~# jps
10562 Jps
10451 DataNode
root@slave1:~# 

下一步是要啟動 MapReduce 守護進程(jobtracker 和 tasktracker)。如 清單 10 所示執行該操作。注意,腳本啟動主節點上的 jobtracker(正如配置所定義的;參見 清單 5)和每個從節點上的 tasktrackers。主節點上的一個 jps 命令顯示 jobtracker 正在運行。

清單10 啟動MapReduce守護進程
root@master:~# /usr/lib/hadoop-0.20/bin/start-mapred.sh
starting jobtracker, logging to 
  /usr/lib/hadoop-0.20/logs/hadoop-root-jobtracker-mtj-desktop.out
192.168.108.134: starting tasktracker, logging to 
  /usr/lib/hadoop-0.20/bin/../logs/hadoop-root-tasktracker-mtj-desktop.out
192.168.108.135: starting tasktracker, logging to 
  /usr/lib/hadoop-0.20/bin/../logs/hadoop-root-tasktracker-mtj-desktop.out
root@master:~# jps
7367 NameNode
7842 JobTracker
7938 Jps
7522 SecondaryNameNode
root@master:~# 

最後,使用 jps 檢查一個從節點。這裏您可以看到,一個 tasktracker 守護進程將數據節點守護進程聯接到每個從數據節點上:

清單11 檢測其中一個從節點上的數據節點
root@slave1:~# jps
7785 DataNode
8114 Jps
7991 TaskTracker
root@slave1:~# 

啟動腳本、節點和啟動的守護進程之間的關係如圖 4 所示。如您所見,start-dfs 腳本啟動名稱節點和數據節點,而 start-mapred 腳本啟動 jobtracker 和 tasktrackers。

圖4 每個節點的啟動進程和守護進程的關係
每個節點的啟動腳本和守護進程的關係 

測試HDFS

既然 Hadoop 已經開始在整個集群中運行了,您可以運行一些測試來確保其正常運作(見清單 12)。首先,通過 hadoop-0.20 實用程序發出一個文件係統命令(fs),並請求一個 df(disk free)操作。與在 Linux® 中一樣,該命令僅確定特定設備的已用空間和可用空間。因此,對於新格式化的文件係統,就沒有已用空間。下一步,在 HDFS 的根上執行一個 ls 操作,創建一個子目錄,列出其內容,並刪除它。最後,在 hadoop-0.20 實用程序內,您可以使用 fsck 命令在 HDFS 上執行一個 fsck(文件係統檢查)。這一切 — 以及各種其他信息(比如檢測到兩個數據節點)— 都告訴您文件係統是正常的。

清單12 檢查HDFS
root@master:~# hadoop-0.20 fs -df
File system		Size	Used	Avail		Use%
/		16078839808	73728	3490967552	0%
root@master:~# hadoop-0.20 fs -ls /
Found 1 items
drwxr-xr-x   - root supergroup          0 2010-05-12 12:16 /tmp
root@master:~# hadoop-0.20 fs -mkdir test
root@master:~# hadoop-0.20 fs -ls test
root@master:~# hadoop-0.20 fs -rmr test
Deleted hdfs://192.168.108.133:54310/user/root/test
root@master:~# hadoop-0.20 fsck /
.Status: HEALTHY
 Total size:	4 B
 Total dirs:	6
 Total files:	1
 Total blocks (validated):	1 (avg. block size 4 B)
 Minimally replicated blocks:	1 (100.0 %)
 Over-replicated blocks:	0 (0.0 %)
 Under-replicated blocks:	0 (0.0 %)
 Mis-replicated blocks:		0 (0.0 %)
 Default replication factor:	2
 Average block replication:	2.0
 Corrupt blocks:		0
 Missing replicas:		0 (0.0 %)
 Number of data-nodes:		2
 Number of racks:		1

The filesystem under path '/' is HEALTHY
root@master:~#

執行一個MapReduce作業

下一步是執行一個 MapReduce 作業,以驗證整個設置運作正常(見清單 13)。該進程的第一步是要引入一些數據。因此,首先創建一個目錄來容納您的輸入數據(稱為 input),創建方式是使用 hadoop-0.20 實用程序的 mkdir 命令。然後,使用 hadoop-0.20 的put 命令將兩個文件放到 HDFS 中。您可以使用 Hadoop 實用程序的 ls 命令檢查輸入目錄的內容。

清單13 生成輸入數據
				
root@master:~# hadoop-0.20 fs -mkdir input
root@master:~# hadoop-0.20 fs -put \
  /usr/src/linux-source-2.6.27/Doc*/memory-barriers.txt input
root@master:~# hadoop-0.20 fs -put \
  /usr/src/linux-source-2.6.27/Doc*/rt-mutex-design.txt input
root@master:~# hadoop-0.20 fs -ls input
Found 2 items
-rw-r--r--  2 root supergroup  78031 2010-05-12 14:16 /user/root/input/memory-barriers.txt
-rw-r--r--  2 root supergroup  33567 2010-05-12 14:16 /user/root/input/rt-mutex-design.txt
root@master:~# 

下一步,啟動 wordcount MapReduce 作業。與在偽分布式模型中一樣,指定輸入子目錄(包含輸入文件)和輸出目錄(不存在,但會由名稱節點創建並用結果數據填充):

清單14 在集群上運行MapReduce wordcount計數
root@master:~# hadoop-0.20 jar \
  /usr/lib/hadoop-0.20/hadoop-0.20.2+228-examples.jar wordcount input output
10/05/12 19:04:37 INFO input.FileInputFormat: Total input paths to process : 2
10/05/12 19:04:38 INFO mapred.JobClient: Running job: job_201005121900_0001
10/05/12 19:04:39 INFO mapred.JobClient:  map 0% reduce 0%
10/05/12 19:04:59 INFO mapred.JobClient:  map 50% reduce 0%
10/05/12 19:05:08 INFO mapred.JobClient:  map 100% reduce 16%
10/05/12 19:05:17 INFO mapred.JobClient:  map 100% reduce 100%
10/05/12 19:05:19 INFO mapred.JobClient: Job complete: job_201005121900_0001
10/05/12 19:05:19 INFO mapred.JobClient: Counters: 17
10/05/12 19:05:19 INFO mapred.JobClient:   Job Counters 
10/05/12 19:05:19 INFO mapred.JobClient:     Launched reduce tasks=1
10/05/12 19:05:19 INFO mapred.JobClient:     Launched map tasks=2
10/05/12 19:05:19 INFO mapred.JobClient:     Data-local map tasks=2
10/05/12 19:05:19 INFO mapred.JobClient:   FileSystemCounters
10/05/12 19:05:19 INFO mapred.JobClient:     FILE_BYTES_READ=47556
10/05/12 19:05:19 INFO mapred.JobClient:     HDFS_BYTES_READ=111598
10/05/12 19:05:19 INFO mapred.JobClient:     FILE_BYTES_WRITTEN=95182
10/05/12 19:05:19 INFO mapred.JobClient:     HDFS_BYTES_WRITTEN=30949
10/05/12 19:05:19 INFO mapred.JobClient:   Map-Reduce Framework
10/05/12 19:05:19 INFO mapred.JobClient:     Reduce input groups=2974
10/05/12 19:05:19 INFO mapred.JobClient:     Combine output records=3381
10/05/12 19:05:19 INFO mapred.JobClient:     Map input records=2937
10/05/12 19:05:19 INFO mapred.JobClient:     Reduce shuffle bytes=47562
10/05/12 19:05:19 INFO mapred.JobClient:     Reduce output records=2974
10/05/12 19:05:19 INFO mapred.JobClient:     Spilled Records=6762
10/05/12 19:05:19 INFO mapred.JobClient:     Map output bytes=168718
10/05/12 19:05:19 INFO mapred.JobClient:     Combine input records=17457
10/05/12 19:05:19 INFO mapred.JobClient:     Map output records=17457
10/05/12 19:05:19 INFO mapred.JobClient:     Reduce input records=3381
root@master:~#

最後一步是探索輸出數據。由於您運行了 wordcount MapReduce 作業,結果是一個文件(從已處理映射文件縮減而來)。該文件包含一個元組列表,表示輸入文件中找到的單詞和它們在所有輸入文件中出現的次數:

清單15 檢測mapreduce的輸出
root@master:~# hadoop-0.20 fs -ls output
Found 2 items
drwxr-xr-x   - root supergroup          0 2010-05-12 19:04 /user/root/output/_logs
-rw-r--r--   2 root supergroup      30949 2010-05-12 19:05 /user/root/output/part-r-00000
root@master:~# hadoop-0.20 fs -cat output/part-r-00000 | head -13
!=	1
"Atomic	2
"Cache	2
"Control	1
"Examples	1
"Has	7
"Inter-CPU	1
"LOAD	1
"LOCK"	1
"Locking	1
"Locks	1
"MMIO	1
"Pending	5
root@master:~# 

盡管 hadoop-0.20 實用程序的功能極其豐富,但有時使用一個 GUI 會更方便。在執行文件係統檢測時,您可以通過 https://master:50070 鏈接到名稱節點,通過 https://master:50030 連接到 jobtracker 。您可以通過名稱節點檢測 HDFS,如圖 5 所示,在這裏您檢測輸入目錄(包含輸入數據 — 見上麵 清單 13)。

圖5 通過名稱節點檢測HDFS
通過名稱節點檢測 HDFS 

通過 jobtracker,您可以檢測運行中或已完成的作業。在圖 6 中,您可以看到對最後一個作業的檢測(來自 清單 14)。該圖展示了作為 Java 存檔(JAR)請求的輸出發出的各種數據,以及任務的狀態和數量。注意,這裏執行了兩個映射任務(每個輸入文件一個映射)和一個縮減任務(用於縮減兩個映射輸入)。

圖6 檢測一個已完成作業的狀態
檢查一個已完成作業的狀態 

最後,您可以通過名稱節點檢查數據節點的狀態。名稱節點主頁確定活動節點和死節點(作為鏈接)的數量,且允許您進一步檢測它們。圖 7 所示的頁麵顯示了活動數據節點以及每個節點的統計數據。

圖7 檢查活動數據節點的狀態
檢查活動數據節點的狀態 

通過名稱節點和 jobtracker Web 界麵,可以查看許多其他視圖,但出於簡潔,隻顯示該樣例集。在名稱節點和 jobtracker Web 頁麵內,您會找到大量鏈接,從而引導您獲取有關 Hadoop 配置和操作的其他信息(包括運行時日誌)。

此係列的文章 專注於單節點和多節點集群的 Hadoop 安裝及配置。最後這篇文章探索了 Hadoop 編程 — 特別是在 Ruby 語言中 map 和 reduce 應用程序開發。我之所以選擇 Ruby,首先是因為,它是一個您應該知道的很棒的麵向對象的腳本語言,其次,您將在 參考資料 部分發現很多參考,其中包括解決 Java™ 和 Python 語言的教程。通過這種 MapReduce 編程的探索,將向您介紹流式應用程序編程接口(Application Programming Interface,API)。此 API 提供方法以便在 Java 語言以外的多種語言中開發應用程序。

讓我們開始簡要介紹一下 map 和 reduce(從功能的角度考慮),然後再進一步鑽研 Hadoop 編程模型及其體係結構和用來雕刻、分配、管理工作的元素。

第 3 部分: 應用程序開發

maphe reduce的起源

是什麼功能性元素激發了 MapReduce 編程範例的創立?在 1958 年,John McCarthy 發明了名為 Lisp 的語言,其實現了數值和符號計算,但在遞歸形式下此語言非常不同於現在所使用的大多數語言。(在維基百科全書上記述著 Lisp 那段迷人的曆史,同時包括一個有用的教程 — 值得您花費時間來閱讀。)Lisp 最先是在 IBM® 704 中實現的,IBM® 704 是第一種大規模生產的計算機,也支持其他舊的語言,如 FORTRAN。

map 函數,源於功能性語言(如 Lisp)但如今在其他語言中也很常見,其中包含了一係列元素的函數的應用程序。這意味著什麼? 清單 1 通過 Scheme Shell (SCSH) 提供解釋會話,即一個 Lisp 衍生。第一行定義一個名為 square 的函數,該函數可接受參數並發出其平方根。下一行說明 map 函數的使用。如圖所示,通過 map,為已應用的函數提供您的函數和一係列元素。結果是一個包含平方元素的新列表。

清單1 SCSH上的map函數演示
> (define square (lambda (x) (* x x)))
> (map square '(1 3 5 7))
'(1 9 25 49)
>

Reduce 也適用於列表但是通常將列表縮減為標量值。清單 2中提供的示例說明用於將列表縮減為標量的其他 SCSH 函數 — 在這種情況下,用 (1 + (2 + (3 + (4 + (5))))) 的格式匯總值的列表。請注意這是典型的功能性編程,取決於迭代上的遞歸。

清單2 SCSH上的reduce函數演示
> (define (list-sum lis) (if (null? lis) 0 (+ (car lis) (list-sum (cdr lis)))))
> (list-sum '(1 2 3 4 5))
15
> 

有趣的是要注意遞歸與迭代在命令性語言中同樣高效,因為遞歸在幕後被轉化成迭代。

hadoop的編程模型

Google 引用 MapReduce 的概念作為處理或生成大型數據集的編程模型。在規範模型中,map 函數處理鍵值對,這將得出鍵值對的中間集。然後 reduce 函數會處理這些中間鍵值對,並合並相關鍵的值(請參考圖 1)。輸入數據使用這樣一種方法進行分區,即在並行處理的計算機集群中分區的方法。使用相同的方法,已生成的中間數據將被並行處理,這是處理大量數據的理想方法。

圖1 MapReduce的處理的簡化流程
MapReduce 處理的簡化視圖 

對於快速刷新器來說,查看圖 1 的體係結構,從 map 和 reduce 角度來進行字數統計(因為您將在本文中開發 map 和 reduce 應用程序)。在提供輸入數據時(進入 Hadoop 文件係統 [HDFS]),首先分段,然後分配給 map 工作線程(通過作業跟蹤器)。雖然 圖 2 中的示例顯示了一個被分段的簡短語句,但是分段的工作數量通常在 128MB 範圍內,其原因是建立工作隻需要很少的時間,因為有更多的工作要做,以便最大限度地減少這種開銷。map 工作線程(在規範的示例中)將工作分割成包含已標記單詞和初始值(在此情況下是 1)的單個矢量。在 map 任務完成時(如通過任務跟蹤器在 Hadoop 中所定義的),提供工作給 reduce 工作線程。通過代表所發現的鍵的數量的值,reduce 工作線程將許多鍵縮減為一個惟一的集合。

圖2 簡單的maprecduce流程
簡單的 MapReduce 示例 

請注意此過程可在相同的或不同的計算機中出現或者使用不同的數據分區來按順序或並行完成,且結果仍然是相同的。

雖然規範的視圖(用於使用字數統計生成搜索索引)是一種用來查看 Hadoop 方法,但結果是此計算模型被常規地應用到可計算問題上,正如您將要看到的那樣。

hadoop的靈活性

從 圖 2 中所示的簡單示例看,需注意 map 和 reduce 過程這兩個主要元素。雖然這裏存在一個這些過程如何工作的傳統視圖,但是它不是 map 和 reduce 體係結構所需要的。這就是 Hadoop 的真實力量 — 其靈活性用來實現在某種程度上活動的 map 和 reduce 過程,這解決了一個特定的應用程序。雖然字數統計示例對於大量的問題是有用且適用的,但是其他的模型仍然在此總體框架內適用。所需的就是使 map 和 reduce 應用程序的開發過程對於 Hadoop 可見。

在其他的應用程序中,Hadoop 已經被用於實現包括神經網絡算法的計算機學習應用程序,支持矢量計算機以及 k-means 集群(要獲得更多信息,請參考 參考資料 部分)。

數據流

雖然 Hadoop 是一個基於 Java 的框架,但是其有可能在 Java 語言以外的語言中編寫 msp 和 reduce 應用程序。Hadoop 內的  實用工具實現了一種數據流膠的類型。通過  實用工具,您可以定義您自己的可執行 map 和 reduce(使用每一個從標準輸入 [stdin] 提取的輸入和每一個通過標準輸出 [stdout] 提供的輸出),且  實用工具可適當地讀取和寫入數據,根據需要調用您的應用程序(請參考清單 3)。

清單3  使用hadoop流工具
				
hadoop jar $HADOOP_HOME/hadoop-流.jar \
	-input inputData
	-output outputData
	-mapper map_exec
	-reducer reduce_exec

清單 3 說明如何在 Hadoop 內使用  實用工具,圖 3 圖形化地顯示了如何定義流。請注意這是一個流使用的簡單示例。大量的選項可用於製定如何解析數據、製定如何調用圖像、為分區器和合成器指定替換圖像以及調整其他配置(要獲得更多信息,請參考 參考資料 部分)。

圖3 圖形流示例
圖形流示例 

Ruby示例

通過已經獲得的在  實用工具基本理解上的經驗,您已經準備編寫一個簡單的 Ruby map 和 reduce 應用程序並查看如何在 Hadoop 框架中使用過程。雖然此處的示例伴隨著規範的 MapReduce 應用程序,但是稍後您將看到其他的應用程序(取決於您將如何用 map 和 reduce 格式實現它們)。

首選是 mapper。此腳本從 stdin 提取文本輸入,首先標記它,然後將一係列鍵值對發送到 stdout。像大多數麵向對象的腳本語言一樣,這個任務幾乎太簡單了。如清單 4 中所示的 mapper 腳本(通過一些注釋和空白區域可給與其大一點的大小)。此程序使用一個迭代器來從 stdin 中讀取一行,同時另一個迭代器將該行分割成單個的標記。使用為 1 的相關值(通過選項卡分隔)將每一個標記(單詞)發送到 stdout。

清單4 map ruby腳本
#!/usr/bin/env ruby

# Our input comes from STDIN
STDIN.each_line do |line|

  # Iterate over the line, splitting the words from the line and emitting
  # as the word with a count of 1.
  line.split.each do |word|
    puts "#{word}\t1"
  end

end

下一步,查看 reduce 應用程序。雖然此應用程序稍微有些複雜,但是使用 Ruby hash(關聯陣列)可簡化 reduce 操作(請參考清單 5)。此腳本可通過來自 stdin (通過  實用工具傳遞)的輸入數據再次工作且將該行分割成一個單詞或值。而後該 hash 會檢查該單詞;如果發現,則將計數添加到元素。否則,您需要在該單詞的 hash 中創建新的條目,然後加載計數(應該是來自 mapper 過程的 1)。在所有輸入都被處理以後,通過 hash 可簡單迭代且將鍵值對發送到 stdout。

清單5 ruby reduce 腳本
#!/usr/bin/env ruby

# Create an empty word hash
wordhash = {}

# Our input comes from STDIN, operating on each line
STDIN.each_line do |line|

  # Each line will represent a word and count
  word, count = line.strip.split

  # If we have the word in the hash, add the count to it, otherwise
  # create a new one.
  if wordhash.has_key?(word)
    wordhash[word] += count.to_i
  else
    wordhash[word] = count.to_i
  end

end

# Iterate through and emit the word counters
wordhash.each {|record, count| puts "#{record}\t#{count}"}

隨著 map 和 reduce 腳本的完成,需從命令行測試它們。記得要使用 chmod +x 將這些文件更改為可執行。通過生成輸入文件來啟動,如清單 6 所示。

清單6 生成輸入文件
# echo "Hadoop is an implementation of the map reduce framework for " \
	"distributed processing of large data sets." > input
#

通過單詞輸入,現在您可以測試您的 mapper 腳本,如清單 7 所示。回想此腳本簡單地將輸入標記到鍵值對,此處每個值都將是1(非惟一輸入)。

清單7 測試mapper腳本
# cat input | ruby map.rb
Hadoop	1
is	1
an	1
implementation	1
of	1
the	1
map	1
reduce	1
framework	1
for	1
distributed	1
processing	1
of	1
large	1
data	1
sets.	1
#

到目前為止,一切都很順利。現在,在原始流格式中將整個應用程序一起調出。在清單 8 中,通過 map 腳本傳遞您的輸入、排序輸出(可選步驟)、然後通過 reduce 腳本傳遞由此產生的中間數據。

清單8 使用linux管道的簡單mapreduce

# cat input | ruby map.rb | sort | ruby reduce.rb
large	1
of	2
framework	1
distributed	1
data	1
an	1
the	1
reduce	1
map	1
sets.	1
Hadoop	1
implementation	1
for	1
processing	1
is	1
#

使用hadoop的ruby

在 shell 環境中您的 map 和 reduce 腳本按預期工作,通過 Hadoop 將它們放入測試中。我將會跳過 Hadoop 安裝任務(參考本係列的 用 Hadoop 進行分布式數據處理,第 1 部分:入門 或 用 Hadoop 進行分布式數據處理,第 2 部分:進階 以便建立 Hadoop 並使其運行)。

第一步將要在 HDFS 內為您的輸入信息創建輸入字典,然後提供一個將測試您腳本的簡單文件。清單 9 說明了此步驟(有關這些步驟的更多信息,請參考本係列的 用 Hadoop 進行分布式數據處理,第 1 部分:入門 或 用 Hadoop 進行分布式數據處理,第 2 部分:進階)。

清單9 為mapreduce過程創建輸入文件
# hadoop fs -mkdir input
# hadoop dfs -put /usr/src/linux-source-2.6.27/Documentation/memory-barriers.txt input
# hadoop fs -ls input
Found 1 items
-rw-r--r--  1 root supergroup  78031 2010-06-04 17:36 /user/root/input/memory-barriers.txt
# 

下一步,使用  實用工具,通過自定義腳本來調用 Hadoop,簡化輸出的輸入數據和位置(請參考清單 10)。在此示例中請注意 -file 選項會簡單地告訴 Hadoop 來打包您的 Ruby 腳本作為部分作業提交。

請單10 使用ruby mapreduce腳本使用hadoop流

# hadoop jar /usr/lib/hadoop-0.20/contrib/streaming/hadoop-0.20.2+228-streaming.jar \
  -file /home/mtj/ruby/map.rb -mapper /home/mtj/ruby/map.rb \
  -file /home/mtj/ruby/reduce.rb -reducer /home/mtj/ruby/reduce.rb \
  -input input/* -output output
packageJobJar: [/home/mtj/ruby/map.rb, /home/mtj/ruby/reduce.rb, /var/lib/hadoop-0.20/...
10/06/04 17:42:38 INFO mapred.FileInputFormat: Total input paths to process : 1
10/06/04 17:42:39 INFO streaming.StreamJob: getLocalDirs(): [/var/lib/hadoop-0.20/...
10/06/04 17:42:39 INFO streaming.StreamJob: Running job: job_201006041053_0001
10/06/04 17:42:39 INFO streaming.StreamJob: To kill this job, run:
10/06/04 17:42:39 INFO streaming.StreamJob: /usr/lib/hadoop-0.20/bin/hadoop job ...
10/06/04 17:42:39 INFO streaming.StreamJob: Tracking URL: https://localhost:50030/...
10/06/04 17:42:40 INFO streaming.StreamJob:  map 0%  reduce 0%
10/06/04 17:43:17 INFO streaming.StreamJob:  map 100%  reduce 0%
10/06/04 17:43:26 INFO streaming.StreamJob:  map 100%  reduce 100%
10/06/04 17:43:29 INFO streaming.StreamJob: Job complete: job_201006041053_0001
10/06/04 17:43:29 INFO streaming.StreamJob: Output: output
# 

最後,通過 hadoop 實用工具使用 cat 文件係統操作來探索輸出(請參考清單 11)。

清單11 exploring hadoop output
# hadoop fs -ls /user/root/output
Found 2 items
drwxr-xr-x  - root supergroup      0 2010-06-04 17:42 /user/root/output/_logs
-rw-r--r--  1 root supergroup  23014 2010-06-04 17:43 /user/root/output/part-00000
# hadoop fs -cat /user/root/output/part-00000 | head -12
+--->|	4
immediate	2
Alpha)	1
enable	1
_mandatory_	1
Systems	1
DMA.	2
AMD64	1
{*C,*D},	2
certainly	2
back	2
this	23
# 

在不到 30 行的腳本中,您已經在 Hadoop 框架內實現了 map 和 reduce 元素並演示了它們的執行。雖然是一個簡單的示例,但是通過自定義的和專有的算法說明了 Hadoop 背後真實的力量以及為什麼 Hadoop 正在成為一種用於處理大型數據集的流行框架。

hadoop其他的應用程序

Hadoop 可用於許多應用程序上,其已超越了為大型數據集簡單計算字數的工作。所有這一切的需要就是用矢量格式表達 Hadoop 基礎設施可以使用的數據。雖然規範的示例使用矢量表達作為鍵和值,但是並沒有限製您如何來定義值(例如一些值的匯總)。在更加豐富的應用程序集中此靈活性可以為 Hadoop 創造新的機會。

一個一直適合 MapReduce 字數統計模型的有趣的應用程序正在把 Web 服務器訪問的頻率製表(在開創性 Google 文章中討論)。對於此應用程序來說,URL 作為鍵來服務(從 Web 服務器訪問日誌攝取)。reduce 過程的結果是基於 Web 服務器日誌的給定 Web 站點的每次 URL 訪問的總數。

在計算機學習用戶程序中,Hadoop 已經作為處理大量 GA 個體的規模遺傳算法的一種方法(潛在解決方案)。map 過程執行傳統的遺傳算法,從本地池中搜索最佳單個解決方案。然後 reduce 應用程序成為來自 map 階段的單個解決方案的集成。這會允許單個節點識別最佳解決方案,然後允許這些解決方案在最適於生存的分布式顯示的 reduce 階段中相互競爭。

另外一個有趣的應用程序被創建用於識別僵屍網絡的垃圾郵件。此過程的第一步將會為減少垃圾郵件為目的而對電子郵件按來自給定組織而進行分類(基於一組指紋)。根據過濾的這些數據,對以特定方式(例如參考電子郵件正文中的相同鏈接)連接的郵件生成一個圖表。然後這些相關電子郵件會減少至主機(靜態或動態 IP 地址)以識別有問題的僵屍網絡。

在應用程序之外通過 map 和 reduce 基元來查看世界,Hadoop 作為在計算機集群之間分配工作的方式非常有用。 Map 和 reduce 並非必須強製某種特定類型的應用程序。相反地,Hadoop 可以被視為一種可以同時將數據和算法分配到主機以獲得更快速的並行處理速度的方法。

hadoop應用程序生態環境

雖然 Hadoop 提供了一個靈活的架構,但也可以使用其他應用程序轉換與其他應用程序的界麵。一個有趣的示例稱為 Hive,它是一個具有自己特定查詢語言(稱為 Hive QL)的數據倉庫基礎結構。Hive 使得 Hadoop 更加熟悉結構化查詢語言 (SQL) 背景,同時還支持傳統的 MapReduce 基礎結構來進行數據處理。

HBase 是另外一種位於 HDFS 頂部的有趣的應用程序。它是一個類似於 Google BigTable 的高性能數據庫係統。代替傳統的文件處理,HBase 使數據庫將 MapReduce 處理的輸入和輸出格式列表。

最後,Pig 是 Hadoop 中用於分析大型數據集的平台。Pig 提供可編譯 map 和 reduce 應用程序的高級語言。

這是 Hadoop 係列 的最後一篇文章,探索了在適用於 Hadoop 框架的 Ruby 中開發 map 和 reduce 應用程序。希望從這篇文章您可以看到 Hadoop 的真正力量。雖然 Hadoop 將您限製在一個特定的編程模型中,但是這種模型是靈活的且可被應用到大量的應用程序上。

參考文獻: