海量資料(「Big Data」)是指那些足夠大的資料,以至於無法再使用傳統的方法進行處理。 在過去,一直是Web搜尋引擎的建立者們首當其衝的面對這個問題。 而今天,各種社交網路,移動應用以及各種感應器和科學領域每天創建著上PB的資料。 為了應對這種大規模資料處理的挑戰,google創造了MapReduce。 Google的工作以及yahoo創建的Hadoop孵化出一個完整的海量資料處理工具的生態系統。
隨著MapReduce的流行,一個由資料存儲層,MapReduce和查詢(簡稱SMAQ)組成的海量資料處理的棧式模型也逐漸展現出來。 SMAQ系統通常是開源的,分散式的,運行在普通硬體上。
就像由Linux, Apache, MySQL and PHP 組成的LAMP改變了互聯網應用開發領域一樣,SMAQ將會把海量資料處理帶入一個更廣闊的天地。 正如LAMP成為Web2.0的關鍵推動者一樣,SMAQ系統將支撐起一個創新的以資料為驅動的產品和服務的新時代。
儘管基於Hadoop的架構佔據了主導地位,但是SMAQ模型也包含大量的其他系統,包括主流的NoSQL資料庫。 這篇文章描述了SMAQ棧式模型以及今天那些可以包括在這個模型下的海量資料處理工具。
MapReduce
MapReduce是google為創建web網頁索引而創建的。 MapReduce框架已成為今天大多數海量資料處理的廠房。 MapReduce的關鍵在於,將在資料集合上的一個查詢進行劃分,然後在多個節點上並存執行。 這種分散式模式解決了資料太大以至於無法存放在單獨一台機器上的難題。
為了理解MapReduce是如何工作的,我們首先看它名字所體現出的兩個過程。 首先在map階段,輸入資料被一項一項的處理,轉換成一個中間結果集,然後在reduce階段,這些中間結果又被規約產生一個我們所期望得到的歸納結果。
說到MapReduce,通常要舉的一個例子就是查找一篇文檔中不同單詞的出現個數。 在map階段單詞被抽出來,然後給個count值1,在reduce節點,將相同的單詞的count值累加起來。
看起來是不是將一個很簡單的工作搞地很複雜了,這就是MapReduce。 為了讓MapReduce完成這項任務,map和reduce階段必須遵守一定的限制來使得工作可以並行化。 將查詢請求轉換為一個或者多個MapReduce並不是一個直觀的過程,為了解決這個問題,一些更高級的抽象被提出來,我們將在下面關於查詢的那節裡進行討論。
使用MapReduce解決問題,通常需要三個操作:
資料載入—用資料倉儲的叫法,這個過程叫做抽取(extract),轉換(transform),載入(load){簡稱ETL}更合適些。 為了利用MapReduce進行處理,資料必須從來源資料裡抽取出來,進行必要的結構化,載入到MapReduce可以訪問的存儲層。
MapReduce—從存儲層訪問資料,進行處理,再將結果返回給存儲層
結果抽取—一旦處理完畢,為了讓結果對於人來說是可用的,還需要能夠將存儲層的結果資料進行查詢和展示。
很多SMAQ系統都具有自身的一些屬性,主要就是圍繞上述三個過程的簡化。
Hadoop MapReduce
Hadoop是主要的開源MapReduce實現。 由yahoo資助,2006年由Doug Cutting創建,2008年達到了web規模的資料處理容量。
Hadoop專案現在由Apache管理。 隨著不斷的努力,和多個子專案一起共同構成了完整的SMAQ模型。
由於是用java實現的,所以Hadoop的MapReduce實現可以通過java語言交互。 創建MapReduce job通常需要寫一些函數用來實現map和reduce階段需要做的計算。 處理資料必須能夠載入到Hadoop的分散式檔案系統中。
以wordcount為例,map函數如下(來源於Hadoop MapReduce文檔,展示了其中關鍵的步驟)
public static class Map
extends Mapper {
private final static IntWritable one = new IntWritable(1);
private Text word = new Text();
public void map(LongWritable key, Text value, CoNtext coNtext)
throws IOException, InterruptedException {
String line = value.toString();
StringTokenizer tokenizer = new StringTokenizer(line);
while (tokenizer.hasMoreTokens()) {
word.set(tokenizer.nextToken());
coNtext.write(word, one);
}
}
}
對應的reduce函數如下:
public static class Reduce
extends Reducer {
public void reduce(Text key, Iterable values,
CoNtext coNtext) throws IOException, InterruptedException {
int sum = 0;
for (IntWritable val : values) {
sum += val.get();
}
coNtext.write(key, new IntWritable(sum));
}
}
使用Hadoop運行一個MapReduce job包括如下幾個步驟:
1. 用一個java程式定義MapReduce的各個階段
2. 將資料載入進檔案系統
3. 提交job進行執行
4. 從檔案系統獲取執行結果
直接通過java API,Hadoop MapReduce job寫起來可能很複雜,需要程式師很多方面的參與。 為了讓資料載入和處理工作更加簡單直接,圍繞著Hadoop一個很大的生態系統已經形成。
其他實現
MapReduce已經在很多其他的程式語言和系統中實現,詳細的清單可以參考Wikipedia's entry for MapReduce.。 尤其是幾個NoSQL資料庫已經集成了MapReduce,後面我們會對此進行描述。
Storage
從資料獲取到結果存放,MapReduce都需要與存儲打交道。 與傳統資料庫不同,MapReduce的輸入資料並不是關聯式的。 輸入資料存放在不同的chunk上,能夠劃分給不同的節點,然後提供以key-value的形式提供給map階段。 資料不需要一個schema,而且可能是無結構的。 但是資料必須是可分佈的,能夠提供給不同的處理節點。
存儲層的設計和特點很重要不僅僅是因為它與MapReduce的介面,而且因為它們直接決定了資料載入和結果查詢和展示的方便性。
Hadoop分散式檔案系統
Hadoop使用的標準存儲機制是HDFS。 作為Hadoop的核心部分,HDFS有如下特點,詳細參見HDFS design document.:
容錯 -- 假設失敗是常態允許HDFS運行在普通硬體上
流資料訪問 – HDFS實現時考慮的是批量處理,因此著重于高吞吐率而不是資料的隨機訪問
高度可擴充性 – HDFS可以擴展到PB級的資料,比如Facebook就有一個這樣的產品級使用
可攜性 – Hadoop是可以跨作業系統移植的
單次寫 – 假設檔寫後不會改變,HDFS簡化了replication提高了資料吞吐率
計算當地語系化 – 考慮到資料量,通常將程式移到資料附近執行會更快,HDFS提供了這方面的支援
HDFS提供了一個類似于標準檔案系統的介面。 與傳統資料庫不同,HDFS只能進行資料存儲和訪問,而不能為資料建立索引。 無法對資料進行簡單的隨機訪問。 但是一些更高級的抽象已經創建出來,用來提供對Hadoop的更細細微性的功能,比如HBase。
HBase,Hadoop資料庫
一種使HDFS更具可用性的方法是HBase。 模仿谷歌的BigTable資料庫,HBase也是一個設計用來存儲海量資料的列存式資料庫。 它也屬於NoSQL資料庫範疇,類似于Cassandra and Hypertable。
HBase使用HDFS作為底層存儲系統,因此也具有通過大量容錯分散式節點來存儲大量的資料的能力。 與其他的列存儲資料庫類似,HBase也提供基於REST和Thrift的訪問API。
由於創建了索引,HBase可以為一些簡單的查詢提供對內容快速的隨機訪問。 對於複雜的操作,HBase為Hadoop MapReduce提供資料來源和存儲目標。 因此HBase允許系統以資料庫的方式與MapReduce進行交互,而不是通過底層的HDFS。
Hive
資料倉儲或者是使報告和分析更簡單的存儲方式是SMAQ系統的一個重要應用領域。 最初在Facebook開發的Hive,是一個建立在Hadoop之上是資料倉儲框架。 類似于HBase,Hive提供一個在HDFS上的基於表的抽象,簡化了結構化資料的載入。 與HBase相比,Hive只能運行MapReduce job進行批量資料分析。 如下面查詢那部分描述的,Hive提供了一個類SQL的查詢語言來執行MapReduce job。
Cassandra and Hypertable
Cassandra和 Hypertable都是具有BigTable模式的類似于HBase的列存儲資料庫。
作為Apache的一個專案,Cassandra最初是在Facebook產生的。 現在應用在很多大規模的web網站,包括Twitter, Facebook, Reddit and Digg。 Hypertable產生于Zvents,現在也是一個開源專案。
這兩個資料庫都提供與Hadoop MapReduce交互的介面,允許它們作為Hadoop MapReduce job的資料來源和目標。 在更高層次上,Cassandra提供與Pig查詢語言的集成(參見查詢章節),而Hypertable已經與Hive集成。
NoSQL資料庫的MapReduce實現
目前為止我們提到的存儲解決方案都是依賴于Hadoop進行MapReduce。 還有一些NoSQL資料庫為了對存儲資料進行平行計算本身具有內建的Mapreduce支援。 與Hadoop系統的多元件SMAQ架構不同,它們提供一個由storage, MapReduce and query一體組成的自包含系統。
基於Hadoop的系統通常是面向批量處理分析,NoSQL存儲通常是面向即時應用。 在這些資料庫裡,MapReduce通常只是一個附加功能,作為其他查詢機制的一個補充而存在。 比如,在Riak裡,對MapReduce job通常有一個60秒的超時限制,而通常來說, Hadoop 認為一個job可能運行數分鐘或者數小時。
下面的這些NoSQL資料庫都具有MapReduce功能:
CouchDB,一個分散式資料庫,提供了半結構化的文檔存儲功能。 主要特點是提供很強的多副本支援,以及可以進行分散式更新。 在CouchDB裡,查詢是通過使用javascript定義MapReduce的map和reduce階段實現的。
MongoDB,本身很類似于CouchDB,但是更注重性能,對於分散式更新,副本,版本的支援相對弱些。 MapReduce也是通過javascript描述的。
Riak,與前面兩個資料庫也很類似。 但是更關注高可用性。 可以使用javascript或者Erlang描述MapReduce。
與關聯式資料庫的集成
在很多應用中,主要的來源資料存儲在關聯式資料庫中,比如Mysql或者Oracle。 MapReduce通常通過兩種方式使用這些資料:
使用關聯式資料庫作為源(比如社交網路中的朋友清單)
將MapReduce結果重新注入到關聯式資料庫(比如基於朋友的興趣產生的產品推薦清單)
理解MapReduce如何與關聯式資料庫交互是很重要的。 最簡單的,通過組合使用SQL匯出命令和HDFS操作,分隔符號文字檔可以作為傳統關聯式資料庫和Hadoop系統間的導入匯出格式。 更進一步的講,還存在一些更複雜的工具。
Sqoop工具是設計用來將資料從關聯式資料庫導入到Hadoop系統。 它是由Cloudera開發的,一個專注于企業級應用的Hadoop平臺轉銷商。 Sqoop是與具體資料庫無關的,因為它使用了java的JDBC資料庫API。 可以將整個表導入,也可以使用查詢命令限制需要導入的資料。
Sqoop也提供將MapReduce的結果從HDFS導回關聯式資料庫的功能。 因為HDFS是一個檔案系統,所以Sqoop需要以分隔符號標識的文本為輸入,需要將它們轉換為相應的SQL命令才能將資料插入到資料庫。
對於Hadoop系統來說,通過使用Cascading API中的cascading.jdbc和 cascading-dbmigrate也能實現類似的功能。
與streaming資料來源的集成
關聯式資料庫以及流式資料來源(比如web伺服器日誌,感應器輸出)組成了海量資料系統的最常見的資料來源。 Cloudera的Flume專案就是旨在提供流式資料來源與Hadoop之間集成的方便工具。 Flume收集來自于集群機器上的資料,將它們不斷的注入到HDFS中。 Facebook的Scribe伺服器也提供類似的功能。
商業性的SMAQ解決方案
一些MPP資料庫具有內建的MapReduce功能支援。 MPP資料庫具有一個由並行運行的獨立節點組成的分散式架構。 它們的主要功能是資料倉儲和分析,可以使用SQL。
Greenplum:基於開源的PostreSQL DBMS,運行在分散式硬體組成的集群上。 MapReduce作為SQL的補充,可以進行在Greenplum上的更快速更大規模的資料分析,減少了幾個數量級的查詢時間。 Greenplum MapReduce允許使用由資料庫存儲和外部資料源組成的混合資料。 MapReduce操作可以使用Perl或者Python函數進行描述。
Aster Data 的nCluster資料倉儲系統也提供MapReduce支援。 MapReduce操作可以通過使用Aster Data的SQL-MapReduce技術調用。 SQL-MapReduce技術可以使SQL查詢和通過各種語言(C#, C++, JAVA, R or Python)的原始程式碼定義的MapReduce job組合在一塊。
其他的一些資料倉儲解決方案選擇提供與Hadoop的連接器,而不是在內部集成MapReduce功能。
Vertica:是一個提供了Hadoop連接器的列存式資料庫。
Netezza:最近由IBM收購。 與Cloudera合作提高了它與Hadoop之間的互通性。 儘管它解決了類似的問題,但是實際上它已經不在我們的SMAQ模型定義之內,因為它既不開源也不運行在普通硬體上。
儘管可以全部使用開源軟體來創建一個基於Hadoop的系統,但是集成這樣的一個系統仍然需要一些努力。 Cloudera的目的就是使得Hadoop更能適應用企業化的應用,而且在它們的Cloudera Distribution for Hadoop (CDH)中已經提供一個統一的Hadoop發行版本。
查詢
通過上面的java代碼可以看出使用程式語言定義MapReduce job的map和reduce過程並不是那麼的直觀和方便。 為了解決這個問題,SMAQ系統引人了一個更高層的查詢層來簡化MapReduce操作和結果查詢。
很多使用Hadoop的組織為了使操作更加方便,已經對Hadoop的API進行了內部的封裝。 有些已經成為開源專案或者商業性產品。
查詢層通常並不僅僅提供用於描述計算過程的特性,而且支援對資料的存取以及簡化在MapReduce集群上的執行流程。
Pig
由yahoo開發,目前是Hadoop專案的一部分。 Pig提供了一個稱為Pig Latin的高級查詢語言來描述和運行MapReduce job。 它的目的是讓Hadoop更容易被那些熟悉SQL的開發人員訪問,除了一個JAVA API,它還提供一個互動式的介面。 Pig目前已經集成在Cassandra 和HBase資料庫中。 下面是使用Pig寫的上面的wordcount的例子,包括了資料的載入和預存程序($0代表記錄的第一個欄位)。
input = LOAD 'input/sentences.txt' USING TextLoader();
words = FOREACH input GENERATE FLATTEN(TOKENIZE($0));
grouped = GROUP words BY $0;
counts = FOREACH grouped GENERATE group, COUNT(words);
ordered = ORDER counts BY $0;
STORE ordered INTO 'output/wordCount' USING PigStorage();
Pig是非常具有表達力的,它允許開發者通過UDFs(User Defined Functions )書寫一些定制化的功能。 這些UDF使用java語言書寫。 儘管它比MapReduce API更容易理解和使用,但是它要求使用者去學習一門新的語言。 某些程度上它與SQL有些類似,但是它又與SQL具有很大的不同,因為那些熟悉SQL的人們很難將它們的知識在這裡重用。
Hive
正如前面所述,Hive是一個建立在Hadoop之上的開源的資料倉儲。 由Facebook創建,它提供了一個非常類似于SQL的查詢語言,而且提供一個支援簡單內建查詢的web介面。 因此它很適合於那些熟悉SQL的非開發者使用者。
與Pig和Cascading的需要進行編譯相比,Hive的一個長處是提供即席查詢。 對於那些已經成熟的商務智慧系統來說,Hive是一個更自然的起點,因為它提供了一個對於非技術使用者更加友好的介面。 Cloudera的Hadoop發行版本裡集成了Hive,而且通過HUE專案提供了一個更高級的使用者介面,使得使用者可以提交查詢並且監控MapReduce job的執行。
Cascading, the API Approach
Cascading提供了一個對Hadoop的MapReduce API的包裝以使它更容易被java應用程式使用。 它只是一個為了讓MapReduce集成到更大的系統中時更簡單的一個包裝層。 Cascading包括如下幾個特性:
旨在簡化MapReduce job定義的資料處理API
一個控制MapReduce job在Hadoop集群上運行的API
訪問基於Jvm的指令碼語言,比如Jython, Groovy, or JRuby.
與HDFS之外的資料來源的集成,包括Amazon S3,web伺服器
提供MapReduce過程測試的驗證機制
Cascading的關鍵特性是它允許開發者將MapReduce job以流的形式進行組裝,通過將選定的一些pipes連接起來。 因此很適用于將Hadoop集成到一個更大的系統中。 Cascading本身並不提供高級查詢語言,由它而衍生出的一個叫Cascalog的開源專案完成了這項工作。 Cascalog通過使用Clojure JVM語言實現了一個類似于Datalog的查詢語言。 儘管很強大,Cascalog仍然只是一個小範圍內使用的語言,因為它既不像Hive那樣提供一個類SQL的語言,也不像Pig那樣是過程性的。 下面是使用Cascalog完成的wordcout的例子:
(defmapcatop split [sentence]
(seq (.split sentence "\\s+")))
(?<- (stdout) [?word ?count]
(sentence ?s) (split ?s :> ?word)
(c/count ?count))
使用Solr進行搜索
大規模資料系統的一個重要元件就是資料查詢和摘要。 資料庫層比如HBase提供了對資料的簡單訪問,但是並不具備複雜的搜索能力。 為了解決搜索問題。 開源的搜索和索引平臺Solr通常與NoSQL資料庫組合使用。 Solr使用Luence搜索技術提供一個自包含的搜尋伺服器產品。 比如,考慮一個社交網路資料庫,MapReduce可以使用一些合理的參數用來計算個人的影響力,這個數值會被寫回到資料庫。 之後使用Solr進行索引,就允許在這個社交網路上進行一些操作,比如找到最有影響力的人。
最初在CENT開發,現在作為Apache專案的Solr,已經從一個單一的文本搜尋引擎演化為支援導航和結果聚類。 此外,Solr還可以管理存儲在分散式伺服器上的海量資料。 這使得它成為在海量資料上進行搜索的理想解決方案,以及構建商業智慧系統的重要元件。
總結
MapReduce尤其是Hadoop實現提供了在普通伺服器上進行分散式運算的強有力的方式。 再加上分散式存儲以及方便使用的查詢機制,它們形成的SMAQ架構使得海量資料處理通過小型團隊甚至個人開發也能實現。
現在對資料進行深入的分析或者創建依賴于複雜計算的資料產品已經變得很廉價。 其結果已經深遠的影響了資料分析和資料倉儲領域的格局,降低了該領域的進入門檻,培養了新一代的產品,服務和組織方式。 這種趨勢在Mike Loukides的"What is Data Science?" 報告中有更深入的詮釋。
Linux的出現僅僅通過一台擺在桌面上的linux伺服器帶給那些創新的開發者們以力量。 SMAQ擁有同樣大的潛力來提高資料中心的效率,促進組織邊緣的創新,開啟廉價創建資料驅動業務的新時代。