《Spark大數據分析:核心概念、技術及實踐》大數據技術一覽
大數據技術一覽
我們正處在大數據時代。數據不僅是任何組織的命脈,而且在指數級增長。今天所產生的數據比過去幾年所產生的數據大好幾個數量級。挑戰在於如何從數據中獲取商業價值。這就是大數據相關技術想要解決的問題。因此,大數據已成為過去幾年最熱門的技術趨勢之一。一些非常活躍的開源項目都與大數據有關,而且這類項目的數量在迅速增長。聚焦在大數據方向的創業公司在近年來呈爆發式增長。很多知名公司在大數據技術方麵投入了大筆資金。
盡管“大數據”這個詞很火,但是它的定義是比較模煳的。人們從不同方麵來定義“大數據”。一種定義與數據容量相關,另一種則與數據的豐富度有關。有些人把大數據定義為傳統標準下“過於大”的數據,而另一些人則把大數據定義為捕捉了所描繪實體更多細節的數據。前者的例子之一就是超過數拍字節(PB)或太字節(TB)大小的數據集,如果這樣的數據存儲在傳統的關係數據庫(RDBMS)表中,將會有數十億行。後者的一個例子是有極寬行的數據集,這樣的數據存儲在RDBMS中,將會有數千列。另一種流行的大數據定義是由3個V(volume、velocity和variety,即容量、速度和多樣性)所表征的數據。我剛才討論了容量。速度指的是數據以極快的速率產生,多樣性則指的是數據可以是非結構化、半結構化或多結構的。
標準的關係數據庫無法輕易處理大數據。這些數據庫的核心技術在數十年前所設計,當時極少有組織擁有拍字節級甚至太字節級的數據。現在對一些組織來說,每天產生數太字節的數據也很正常。數據的容量和產生速度都呈爆發式增長。因此,迫切需要新的技術:能快速處理和分析大規模數據。
其他推動大數據技術的因素包括:可擴展性、高可用性和低成本下的容錯性。長期以來,處理和分析大數據集的技術被廣泛研究並以專有商業產品的形式被使用。例如,MPP(大規模並行處理)數據庫已經誕生有段時間了。MPP數據庫使用一種“無共享”架構,數據在集群的各個節點進行存儲和處理。每一個節點有自己的CPU、內存和硬盤,節點之間通過網絡互聯來通信。數據分割在集群的各個節點,而節點之間不存在競爭,所以每個節點可以並行處理數據。這種數據庫的例子包括Teradata、Netezza、Greenplum、ParAccel和Vertica。Teradata發明於20世紀70年代末,在20世紀90年代前,它就能夠處理太字節級別的數據了。但是,專有的MPP數據庫非常昂貴,不是所有人能負擔得起的。
本章介紹一些開源的大數據相關技術。本章涉及的技術看起來好像隨意挑選的,實際上它們由共同的主題而連接:它們和Spark一起使用,或者Spark可以取代其中一些技術。當你開始使用Spark時,你可能會涉及這些技術。而且,熟悉這些技術會幫你更好地理解Spark(這將在第3章介紹)。
1.1 Hadoop
Hadoop是最早流行的開源大數據技術之一。這是一個可擴展、可容錯的係統,用來處理跨越集群(包含多台商用服務器)的大數據集。它利用跨集群的可用資源,為大規模數據處理提供了一個簡單的編程框架。Hadoop受啟發於Google發明的一個係統(用來給它的搜索產品創建反向索引)。Jeffrey Dean和Sanjay Ghemawat在2004年發表的論文中描述了這個他們為Google而創造的係統。第一篇的標題為“MapReduce:大集群上簡化的數據處理”,參見research.google.com/archive/mapreduce.html;第二篇的標題為“Google文件係統”,參見research.google.com/archive/gfs.html。受啟發於這些論文,Doug Cutting和Mike Cafarella開發了一個開源的實現,就是後來的Hadoop。
很多組織都用Hadoop替換掉昂貴的商業產品來處理大數據集。一個原因就是成本。Hadoop是開源的,並可以運行在商用硬件的集群上。可以通過增加廉價的服務器來輕鬆地擴展。Hadoop提供了高可用性和容錯性,所以你不需要購買昂貴的硬件。另外,它對於特定類型的數據處理任務非常合適,比如對於大規模數據的批處理和ETL(Extract、transform、load,提取、轉換、加載)。
Hadoop基於幾個重要的概念。第一,使用商用服務器集群來同時存儲和處理大量數據比使用高端的強勁服務器更便宜。換句話說,Hadoop使用橫向擴展(scale-out)架構,而不是縱向擴展(scale-up)架構。
第二,以軟件形式來實現容錯比通過硬件實現更便宜。容錯服務器很貴,而Hadoop不依賴於容錯服務器,它假設服務器會出錯,並透明地處理服務器錯誤。應用開發者不需要操心處理硬件錯誤,那些繁雜的細節可以交給Hadoop來處理。
第三,通過網絡把代碼從一台計算機轉到另一台比通過相同的網絡移動大數據集更有效、更快速。舉個例子,假設你有一個100台計算機組成的集群,每台計算機上有1TB的數據。要處理這些數據,一個選擇是:把數據轉移到一台能夠處理100TB數據的超級計算機。然而,轉移100TB的數據將花費極長時間,即使是在高速網絡上。另外,通過這種方式處理數據將需要非常昂貴的硬件。另一個選擇是:把處理數據的代碼轉移到具有100個節點的集群中的每台計算機。這比第一種選擇更快、更高效。而且,你不需要高端、昂貴的服務器。
第四,把核心數據處理邏輯和分布式計算邏輯分開的方式,使得編寫一個分布式應用更加簡單。開發一個利用計算機集群中資源的應用比開發一個運行在單台計算機上的應用更加困難。能寫出運行在單台機器上的應用的開發者數量比能寫分布式應用的開發者多好幾個數量級。Hadoop提供了一個框架,隱藏了編寫分布式應用的複雜性,使得各個組織有更多可用的應用開發者。
盡管人們以一個單一產品來討論Hadoop,但是實際上它並不是一個單一產品。它由三個關鍵組件組成:集群管理器、分布式計算引擎和分布式文件係統(見圖1-1)。
2.0版本以前,Hadoop的架構一直是單一整體的,所有組件緊密耦合並綁定在一起。從2.0版本開始,Hadoop應用了一個模塊化的架構,可以混合Hadoop組件和非Hadoop技術。
圖1-1中所示的三個概念組件具體實現為:HDFS、MapReduce和YARN(見圖1-2)。
HDFS和MapReduce在本章討論,YARN將在第11章介紹。
1.1.1 HDFS
正如其名,HDFS(Hadoop Distributed File System)是一個分布式文件係統,它在商用服務器集群中存儲文件,用來存儲和快速訪問大文件與大數據集。這是一個可擴展、可容錯的係統。
HDFS是一個塊結構的文件係統。正像Linux文件係統那樣,HDFS把文件分成固定大小的塊,通常叫作分塊或分片。默認的塊大小為128MB,但是可以配置。從這個塊的大小可清楚地看到,HDFS不是用來存儲小文件的。如果可能,HDFS會把一個文件的各個塊分布在不同機器上。因此,應用可以並行文件級別的讀和寫操作,使得讀寫跨越不同計算機、分布在大量硬盤中的大HDFS文件比讀寫存儲在單一硬盤上的大文件更迅速。
把一個文件分布到多台機器上會增加集群中某台機器宕機時文件不可用的風險。HDFS通過複製每個文件塊到多台機器來降低這個風險。默認的複製因子是3。這樣一來,即使一兩台機器宕機,文件也照樣可讀。HDFS基於通常機器可能宕機這個假設而設計,所以可以處理集群中一台或多台機器的宕機問題。
一個HDFS集群包含兩種類型的節點:NameNode和DataNode(見圖1-3)。Name-Node管理文件係統的命名空間,存儲一個文件的所有元數據。比如,它追蹤文件名、權限和文件塊位置。為了更快地訪問元數據,NameNode把所有元數據都存儲在內存中。一個DataNode以文件塊的形式存儲實際的文件內容。
圖1-3 HDFS架構
NameNode周期性接收來自HDFS集群中DataNode的兩種類型的消息,分別叫作心跳消息和塊報告消息。DataNode發送一個心跳消息來告知NameNode工作正常。塊報告消息包含一個DataNode上所有數據塊的列表。
當一個客戶端應用想要讀取一個文件時,它首先應該訪問NameNode。NameNode以組成文件的所有文件塊的位置來響應。塊的位置標識了持有對應文件塊數據的DataNode。客戶端緊接著直接向DataNode發送讀請求,以獲取每個文件塊。NameNode不參與從Data-Node到客戶端的實際數據傳輸過程。
同樣地,當客戶端應用想要寫數據到HDFS文件時,它首先訪問NameNode並要求它在HDFS命名空間中創建一個新的條目。NameNode會檢查同名文件是否已存在以及客戶端是否有權限來創建新文件。接下來,客戶端應用請求NameNode為文件的第一個塊選擇DataNode。它會在所有持有塊的複製節點之間創建一個管道,並把數據塊發送到管道中的第一個DataNode。第一個DataNode在本地存儲數據塊,然後把它轉發給第二個Data-Node。第二個DataNode也本地存儲相應數據塊,並把它轉發給第三個DataNode。在所有委派的DataNode上都存儲第一個文件塊之後,客戶端請求NameNode為第二個塊來分配DataNode。這個過程持續進行,直到所有文件塊都已在DataNode上存儲。最後,客戶端告知NameNode文件寫操作已完成。
1.1.2 MapReduce
MapReduce是Hadoop提供的分布式計算引擎。HDFS提供的是存儲大數據集的分布式文件係統,MapReduce則提供集群中並行處理大數據集的計算框架。它抽象了集群計算,提供了編寫分布式數據處理應用的高級結構,使得沒有編寫分布式或並行應用的程序員也可以編寫運行在商用計算機集群上的應用。
MapReduce框架自動在集群中各計算機上調度應用的執行。它會處理負載均衡、節點宕機和複雜的節點內通信。它處理分布式計算的繁雜細節,使得程序員可以關注於數據處理的邏輯本身。
MapReduce應用的基本組成塊是兩個函數:map和reduce,名稱借鑒於函數式編程。MapReduce中所有的數據處理作業都用這兩個函數來表達。map函數以鍵值對作為輸入,輸出中間產物鍵值對。MapReduce框架對輸入數據集中每一個鍵值對調用map函數。接下來,對map函數的輸出進行排序,並根據值進行分組,作為輸入傳給reduce函數。reduce函數聚合這些值,輸出最終的聚合值。
第3章將介紹的Spark被視為MapReduce的繼承者,相比MapReduce,它有諸多優勢。這將在第3章詳細討論。
1.1.3 Hive
Hive是一個數據倉庫軟件,它提供了類SQL語言來處理和分析存儲在HDFS或其他兼容Hadoop的存儲係統(如Cassandra和Amazon S3)中的數據。盡管Hadoop使得編寫可利用集群中計算機資源的數據處理應用更加簡單,但是能寫出這樣應用的程序員相對於了解SQL的人來說依然少得多。
SQL是廣泛使用的數據處理語言,是一種描述性語言。它看似簡單,實則功能強大。SQL比Java和其他用來編寫MapReduce應用的編程語言更易學易用。Hive把SQL的簡潔性引入到Hadoop中,讓更多人可用。
Hive提供一種類SQL的查詢語言,叫作Hive查詢語言(HiveQL),來處理和分析存儲在任何兼容Hadoop的存儲係統中的數據。它提供了一種機製把對應結構映射到存儲在HDFS中的數據上,並用HiveQL來查詢。在底層,它會把HiveQL查詢轉換成MapReduce作業。它也支持UDF(用戶定義函數)和UDAF(用戶定義聚合函數),二者用來進行無法用HiveQL有效表達的複雜數據處理。
第7章討論的Spark SQL被視為Hive的繼承者。然而,Spark SQL提供的不僅是SQL接口,它還做了更多工作。這將在第7章詳細講述。
1.2 數據序列化
數據有自己的生命周期,獨立於創建或使用它的程序。大多數情況下,數據比創建它的應用存活得更久。一般來說,數據保存在硬盤上。有時,也會通過網絡把數據從一個應用發送給另一個應用。
在硬盤上存儲或通過網絡發送的數據格式與數據在內存中的格式是不一樣的。把內存中的數據轉換為可在硬盤上存儲或通過網絡發送的過程叫作序列化,而把硬盤或網絡中的數據讀取到內存的過程叫作反序列化。
數據可以用多種不同的格式進行序列化,比如CSV、XML、JSON和各種二進製格式。每種格式各有優缺點。比如,像CSV、XML和JSON這樣的文本格式對人類友好,但在存儲空間或解析時間方麵並不十分高效。另一方麵,二進製格式更加緊湊,在解析上比文本格式更快,但可讀性較差。
在數據集較小時,文本和二進製格式之間的序列化/反序列化時間和存儲空間差異不是什麼大問題。因此,人們通常首選文本格式來處理小數據集,因為它更容易管理。然而,對於大數據集,文本和二進製格式之間的序列化/反序列化時間和存儲空間差異將是極大的。因此,首選二進製格式來存儲大數據集。
本節講述一些常用的用來序列化大數據的二進製格式。
1.2.1 Avro
Avro提供了一個簡潔的且獨立於語言的二進製格式,用來數據序列化。它可用來存儲數據到文件或通過網絡發送數據。它支持多種數據結構,包括嵌套數據。
Avro使用一種自描述的二進製格式。使用Avro序列化數據時,模式與數據同時存儲。這樣一來,稍後Avro文件可以被任何應用讀取。另外,因為模式與數據同時存儲,所以寫數據時沒有關於值的間接開銷,使得序列化快速、緊實。使用Avro通過網絡交換數據時,發送端和接收端在初始化連接握手時交換模式。Avro模式使用JSON描述。
Avro自動處理字段的添加和刪除、前向和後向兼容性,這些都不需應用來負責。
1.2.2 Thrift
Thrift是一個獨立於語言的數據序列化框架,主要提供工具來完成不同編程語言所寫的應用之間通過網絡進行的數據交換序列化。它支持多種語言,包括:C++、Java、Python、PHP、Ruby、Erlang、Perl、Haskell、C#、Cocoa、JavaScript、Node.js、Smalltalk、OCaml、Delphi和其他語言。
Thrift提供一個代碼生成工具和一組用於序列化數據並通過網絡傳輸的庫。它抽象了序列化數據和通過網絡傳輸數據的機製。因此,它使得應用開發者可以集中精力於核心的應用邏輯,而不用擔心如何序列化數據和可靠、有效地傳輸數據。
通過Thrift,應用開發者在一個語言中立的接口定義文件中定義數據類型和服務接口。在接口定義文件中定義的服務由服務器端應用提供,並由客戶端應用使用。Thrift編譯器編譯這個文件,並生成開發者用來快速構建客戶端和服務器端應用的代碼。
基於Thrift的服務器和客戶端可以在相同計算機或網絡上的不同計算機上運行。同樣地,服務器端和客戶端應用可以使用同一種編程語言來開發,也可以用不同編程語言來開發。
1.2.3 Protocol Buffers
Protocol Buffers是Google開發的開源數據序列化框架。類似於Thrift和Avro,它也是語言中立的。Google內部用Protocol Buffers作為主要的文件格式,也將其用來進行應用間的數據交換。
Protocol Buffers與Thrift類似,前者提供一個編譯器和一組庫來幫助開發者序列化數據。開發者在一個文件中定義數據集的結構或模式,然後用Protocol Buffers編譯器進行編譯,由此生成可用來輕鬆讀寫數據的代碼。
相對Thrift而言,Protocol Buffers支持較少的編程語言。目前,它支持C++、Java和Python。另外,不像Thrift那樣同時提供數據序列化和構建遠程服務的工具,Protocol Buffers主要是一種數據序列化格式,可以用來定義遠程服務,但並未限定到任何RPC(遠程過程調用)協議。
1.2.4 SequenceFile
SequenceFile是一種用於存儲鍵值對的二進製文件格式。它通常作為Hadoop的輸入和輸出文件格式。MapReduce也用SequenceFile來存儲map函數返回的臨時輸出。
SequenceFile有三種不同的格式:未壓縮格式、記錄壓縮格式和塊壓縮格式。在記錄壓縮格式的SequenceFile中,隻有記錄中的值才壓縮;而在塊壓縮格式的SequenceFile中,鍵和值都壓縮。
1.3 列存儲
數據可以麵向行或麵向列的格式來存儲。在麵向行格式中,一行的所有列或字段存儲在一起。這裏的一行,可以是CSV文件中的一行,或者是數據庫表中的一條記錄。當數據以麵向行格式保存時,第一行後麵是第二行,接著是第三行,以此類推。麵向行存儲對於主要執行數據的CRUD(創建、讀取、更新、刪除)操作的應用來說是完美的。這些應用一次操作數據中的一行。
然而,麵向行存儲對於分析類應用來說不夠高效。這樣的應用要對數據集的列進行操作。更重要的是,這些應用隻讀取和分析跨越多行的列的一個小子集。因此,讀取所有列是對內存、CPU周期和硬盤I/O的浪費,這是一個昂貴的操作。
麵向行存儲的另一個缺點是數據無法高效地壓縮。一條記錄可能由多種不同數據類型的列構成,一行的熵就會很高。壓縮算法不適用於壓縮多樣化數據。因此,使用麵向行格式存儲在硬盤上的一個表格比用列存儲格式所生成的文件更大。更大的文件不僅要耗費更多的硬盤空間,還會影響應用的性能,因為硬盤I/O與文件大小成正比,而硬盤I/O是一個昂貴的操作。
麵向列存儲係統以列的形式在硬盤上存儲數據。列中的所有單元保存在一起,或者連續地保存。比如,當以列格式在硬盤上保存一個表格時,所有行的第一列首先保存,然後是所有行的第二列,接著是第三列,以此類推。列存儲在分析類應用方麵比麵向行存儲更加高效,使分析更加迅速,而所需硬盤空間更小。
下一節討論Hadoop生態係統中3種常用的列存儲文件格式。
1.3.1 RCFile
RCFile(列式記錄文件)是一種構建於HDFS之上用來存儲Hive表格的列存儲格式。它實現了一種混合的列存儲格式。RCFile首先把表格分割成行組(row group),然後以列格式保存每一個行組。所有行組分布在整個集群上。
RCFile使得我們可以同時利用列存儲和Hadoop MapReduce的優勢。因為行組分布在整個集群上,所以它們可以並行處理。一個節點上,行的列存儲有助於高效的壓縮和更快的分析。
1.3.2 ORC
ORC(Optimized Row Columnar)是另一種高效存儲結構化數據的列存儲文件格式。相對RCFile,它有很多優勢。比如,它保存行索引,使得查詢中可以快速搜索一個指定行。因為它基於數據類型采用塊模式的壓縮,所以它能提供更好的壓縮效果。另外,可以用zlib或Snappy在基於數據類型的列級別的壓縮之上進行通用壓縮。
和RCFile類似,ORC文件格式把表格分割成可配置大小的條帶(見圖1-4)。默認的條帶大小為250MB。一個條帶類似於RCFile中的一個行組,但是每個條帶不僅包含行數據,還包括索引數據和條帶腳部。條帶腳部含有流位置的目錄。索引數據包括每一列的最小值和最大值以及行索引。ORC文件格式在一個條帶中為每10000行保存一個索引。在每個條帶內部,ORC文件格式使用特定數據類型的編碼技術來壓縮列,如:針對整型列的行程編碼和針對字符串列的字典編碼。還可以使用zlib或Snappy之類的通用壓縮編解碼器來進一步壓縮列。
所有條帶之後是文件腳部,其中包含文件中條帶的列表、條帶中的行數和各個列的數據類型,還包括每一列的統計數據,比如:數目、最小值、最大值和總數。文件腳部之後是附錄(postscript)部分,其中包含壓縮參數和壓縮的腳部大小。
ORC文件格式不僅高效存儲數據,還有助於高效查詢。應用在一次查詢中可以隻請求所需的列。同樣地,應用可以使用謂詞下推來跳躍讀取整個行集。
1.3.3 Parquet
Parquet是為Hadoop生態係統而設計的另一個列存儲格式。它可以被任何數據處理框架所使用,包括Hadoop MapReduce和Spark。它用來支持複雜的嵌套數據結構。另外,它不僅支持多種數據編碼和壓縮技術,還可以按列來指定壓縮方案。
Parquet實現了一個三層的層次結構來在文件中存儲數據(見圖1-5)。首先,和RCFile和ORC類似,它在水平方向把表格分割為行組。行組分布在整個集群上,因此可以用任何集群計算框架來並行處理。其次,在每個行組內部,它把列分割為列塊。Parquet用術語“列塊”來表示行組中一列的數據。一個列塊在硬盤上連續存儲。層次結構中的第三級是頁麵。Parquet把列塊分割為多個頁麵。一個頁麵是編碼和壓縮的最小單元。一個列塊可以包含多個不同類型的交錯頁麵。因此,一個Parquet文件由行組構成,行組中包含列塊,而列塊中包含一個或多個頁麵。
1.4 消息係統
數據通常從一個應用流向另一個。一個應用產生數據,而後被一個或多個其他應用使用。一般來講,生成或發送數據的應用叫作生產者,接收數據的則叫作消費者。
有時候,產生數據的應用數量和使用數據的應用數量會出現不對稱。比如,一個應用可以產生數據,而後被多個消費者使用。同樣地,一個應用也可以使用來自多個生產者的數據。
有時候應用產生數據的速率和另一個應用使用數據的速率也會出現不對稱。一個應用可能產生數據的速率快於消費者使用數據的速率。
圖1-5 Parquet文件結構(圖片來源:parquet.apache.org)
從一個應用向另一個應用發送數據的簡單方法就是把它們直接互連。然而,當生產者和消費者數量或數據生成速率和使用速率之間存在不對稱時,這個方法就行不通了。另一個挑戰是生產者和消費者之間的強耦合要求它們同時運行,或實現一個複雜的緩衝機製。因此,生產者和消費者之間直連無法擴展。
一個靈活且可擴展的解決方法是用一個消息代理或消息係統。應用無須直接互聯,而是連接到消息代理或消息係統。這樣的架構使在數據管道上添加生產者或消費者變得容易,也允許應用以不同速率來生成和使用數據。
本節討論幾個大數據應用廣泛使用的消息係統。
1.4.1 Kafka
Kafka是一個分布式的消息係統或消息代理。準確來講,它是一個分布式的、分塊的、重複的提交日誌服務,可以用來作為發布-訂閱式消息係統。
Kafka的關鍵特性包括:高吞吐量、可擴展性和持久性。單個代理可以處理來自數以千計應用的每秒幾百兆字節的讀和寫。可以通過向集群中增加更多節點來輕鬆擴容。關於持久性,它在硬盤上保存消息。
基於Kafka的架構中的關鍵實體包括:代理、生產者、消費者、主題和消息(見圖1-6)。Kafka作為節點的集群來運行,每個節點叫作代理。通過Kafka發送的消息屬於主題。把消息發布到Kafka主題的應用叫作生產者。消費者指的是訂閱Kafka主題並處理消息的應用。
圖1-6 Kafka中的消息流
Kafka把一個主題分割為多個分塊。每個分塊是消息的一個有序而不可變的序列。新消息被追加到一個分塊。給一個分塊中的每一條消息指定一個唯一的連續標識符(叫作偏移量)。各個分塊分布在Kafka集群的各個節點。另外,也複製它們以提供容錯功能。主題的分割有助於擴展性和並行性。一個主題不需要限製於單台機器,它可以增長到任意大小。主題大小的增長可以通過向Kafka集群中添加更多節點來解決。
發布到Kafka集群的消息中,一個重要的屬性是:它在一個可配置的周期內保留所有消息。即使消費者使用了一條消息,在所配置的間隔內消息依然可以獲取它。更重要的是,Kafka的性能對於數據大小實際上保持恒定。
Kafka使用一個叫作消費者組的機製來同時支持隊列和發布-訂閱消息模型。把發布到一個主題的每條消息發送到每一個訂閱的消費者組內的一個消費者。因此,如果訂閱一個主題的所有消費者屬於同一個消費者組,則Kafka作為一個隊列消息係統而工作,每條消息隻發送到一個消費者。另一方麵,如果訂閱一個主題的每一個消費者屬於不同的消費者組,則Kafka作為一個發布-訂閱消息係統而工作,把每條消息都廣播到所有訂閱某主題的消費者。
1.4.2 ZeroMQ
ZeroMQ是一個輕量級的高性能消息庫。它用來實現消息隊列和構建可擴展的並發和分布式消息驅動的應用。它沒有利用以代理為中心的架構,盡管根據需要也可以用它來構建一個消息代理。它支持大多數現代語言和操作係統。
ZeroMQ的API仿效了標準的UNIX Socket API。應用之間通過套接字互相通信。不像標準的套接字,它支持N對N連接。一個ZeroMQ套接字代表一個異步的消息隊列。它用一個簡單的框架在線纜上傳輸離散消息。消息長度可以是0字節到數吉字節。
ZeroMQ不會對消息強加任何格式,而將消息當作二進製大對象blob。可以通過序列化協議來結合它,比如用Google的Protocol Buffers來發送和接收複雜的對象。
ZeroMQ在後台線程中異步實現I/O。它會自動處理物理連接設置、重連、消息傳送重試和連接清除。另外,如果接收者不可達,它會將消息排隊。當隊列滿額時,可以將其配置為阻止發送者或丟棄消息。因此,ZeroMQ提供了一個比標準套接字更高級的抽象來發送和接收消息,使創建消息分發應用更加簡單,也使得應用間發送和接收消息的鬆耦合成為可能。
ZeroMQ庫支持多個傳輸協議來進行線程間、進程間和跨網絡的消息傳遞。對於相同進程內線程間的消息傳遞,它支持一種不涉及任何I/O的基於內存的消息傳遞機製。對於運行在相同機器上的進程之間的消息傳統,它使用UNIX域或IPC套接字。這種情況下,所有通信都在操作係統內核中發生,而不會使用任何網絡協議。ZeroMQ支持TCP協議來實現應用間通過網絡進行通信。最後,它還支持PGM來多播消息。
ZeroMQ可用來實現不同的消息傳遞模式,包括:請求-應答、Router-Dealer、客戶端-服務器、發布-訂閱和管道。比如,可以用ZeroMQ創建一個發布-訂閱模式的消息傳遞係統來從多個發布者發送數據到多個訂閱者(見圖1-7)。要實現這個模式,發布者應用會創建一個ZMQ_PUB類型的套接字。在這樣的套接字上發送的消息以扇出(fan-out)的方式分布到所有已連接的訂閱者。訂閱者應用創建一個ZMQ_SUB類型的套接字來訂閱來自發布者的數據,可以指定一個過濾器來獲取想要的消息。同樣地,也可以用ZeroMQ創建一個管道模式來分發數據到管道上排列的各個節點。應用創建ZMQ_PUSH類型的套接字來發送消息到下遊應用,下遊應用則需創建ZMQ_PULL類型的套接字。
圖1-7 使用ZeroMQ的發布-訂閱
1.5 NoSQL
NoSQL這個術語用於非關係型的現代數據庫。起初,NoSQL指的是“不支持SQL”,因為這些數據庫不支持SQL。而現在,它指的是“不止SQL”,因為其中一些數據庫支持SQL命令的一個子集。相對RDBMS數據庫來說,NoSQL數據庫有不同的設計目標。一個關係數據庫保證了ACID(原子性、一致性、獨立性和持久性)。而NoSQL數據庫則權衡ACID對線性擴展性、性能、高可用性、靈活的模式和其他特性的兼容性。
本節討論一些廣泛使用的NoSQL數據庫。
1.5.1 Cassandra
Cassandra是一個分布式、可擴展、容錯的NoSQL數據庫,用於存儲大數據集。它是一個分塊的、可調節一致性的行存儲。其關鍵特性是動態模式,每一行可以存儲不同的列,而不像關係數據庫那樣每行有完全相同的列。另外,Cassandra對寫操作做了優化,所以插入操作是高性能的。
Cassandra是一個無主的分布式架構。因此,它沒有單點故障的問題。另外,它實現了各行在集群中的自動分布。讀寫數據的客戶端應用可以連接Cassandra集群中的任意節點。
Cassandra通過內部對數據複製的支持來提供高可用性。保存的副本數量可以配置,每個副本在集群中不同的節點上存儲。如果複製因子是3,即使一或兩個節點宕機,整個集群依然可用。
Cassandra中數據通過鍵空間(keyspace)、表、行和列形成的層級結構來建模。鍵空間在概念上類似於RDBMS中的數據庫或模式。它是表的邏輯集合,代表一個命名空間,用來控製一組表的數據複製。表(也稱為“列族”)在概念上類似於RDBMS中的表。一個列族由分塊的行的集合構成。每一行由分塊的鍵和一組列構成。特別要注意的是,盡管Cassandra中的鍵空間、表、行和列看起來分別和關係型數據庫中的模式、表、行和列很類似,但是它們的實現和物理存儲是不同的。
在Cassandra中查詢模式驅動數據模型。Cassandra中的一個列族或一個表基本上就是一個物化視圖。不像關係數據庫那樣,Cassandra不支持連接(join),這意味著相同的數據可能需要在多個列族中複製。
1.5.2 HBase
HBase也是一個分布式、可擴展、容錯的NoSQL數據存儲,用於存儲大數據集。它運行在HDFS之上。它和Cassandra有相似的特點,二者均受啟發於Bigtable(一個由Google發明的數據存儲係統)。
Bigtable是一個由Google創造的分布式存儲係統,用來處理跨越上千台商用服務器中拍字節級別的結構化數據。它不支持關係數據模型;相反,它提供了一種簡單的數據模型,賦予客戶端應用對數據存儲的動態控製權。
HBase把數據存在表中。表由行組成,行由列族組成,列族由列組成。然而,HBase中的表和列與關係數據庫中的表和列有很大不同。一個HBase表本質上是一個稀疏的、分布式、持久化、多維且有序的Map。
Map是一個被大多數編程語言所支持的數據結構。這是一個用於存儲鍵值對的容器。對於通過鍵查找值來說,它是一種非常高效的數據結構。一般來說,鍵的順序是未定義的,應用也不關心鍵的順序:它提供一個鍵給Map,然後獲取這個鍵所對應的值。注意,不要把Map數據結構和Hadoop MapReduce中的map函數弄混了。map函數是一個函數式編程語言的概念,用於轉換數據。
Map數據結構在不同的編程語言中有不同的名字。比如,在PHP中叫作關聯數組,在Python中叫作字典,在Ruby中它稱為哈希,而在Java和Scala中則為映射。
HBase表是一個有序的多維或多層級的Map。第一層鍵是行鍵,它使應用能快速從數以億計的行中讀取其中一行。第二層鍵是列族。第三層鍵是列名,也稱為列標識符。第四層鍵是時間戳。行鍵、列族、列名和時間戳組合起來,就唯一標識了一個單元(cell),其中包含值。值是一個未解析的字節數組。
HBase表中的行是稀疏的。不像關係數據庫中的行,HBase中的每一行不必須有同樣的列。每一行有同樣的列族集,但一行中的某些列族可能沒有存儲任何內容。一個空單元不占用任何存儲空間。
1.6 分布式SQL查詢引擎
如前所述,SQL是最常用來查詢和分析數據的語言之一。它易學且有群眾基礎(了解SQL的人遠比了解編程語言如Java的人多)。基本上,Hive就是因此而誕生。不過,Hive依賴於MapReduce,因為它把HiveQL查詢轉換成MapReduce的作業任務。
MapReduce是一個強大的框架。然而,它用於處理批量數據,它有大吞吐量和高延遲。對於數據轉換或者ETL(提取、轉換、加載)作業來說,它的表現非常棒,但在交互式查詢或實時分析方麵則不是一個完美的平台。Hive繼承了MapReduce的限製。這促進了使用不同架構的低延遲查詢引擎的誕生。
本節討論了幾個沒有使用MapReduce的開源且低延遲的分布式SQL查詢引擎。Spark SQL也可以作為分布式查詢引擎,但此處暫不涉及,第7章會詳細討論。
1.6.1 Impala
Impala是一個開源的數據分析軟件。它提供了SQL接口來分析存儲在HDFS和HBase中的大數據集,支持HiveQL以及Hive支持的類SQL語言,可用於批處理和實時查詢。
Impala沒有使用MapReduce。相反,它使用了一種專業的分布式查詢引擎來避免高延遲。它的架構和商用數據庫MPP(大規模並行處理)類似。帶來的好處就是:它提供了比Hive快一個數量級的響應時間。
1.6.2 Presto
Presto也是一個用於分析大數據集的開源分布式SQL查詢引擎。目前,它提供的SQL接口可以分析HDFS、Cassandra和關係數據庫中的數據。它支持太字節和拍字節級數據的交互式分析查詢。另外,它還支持組合多數據源進行查詢。
Presto在架構上與Impala類似,沒有用MapReduce來分析HDFS數據,而是實現了MPP架構。
1.6.3 Apache Drill
Apache Drill是另一個用於分析存儲在HDFS或NoSQL數據庫中大數據集的開源分布式SQL查詢引擎,其靈感來源於Google的Dremel。它可以用來對拍字節級數據執行快速的交互式即席查詢。和Presto與Impala類似,它實現了一個集群式的MPP架構。它支持ANSI SQL和JDBC/ODBC接口,所以可以使用在任何支持JDBC/ODBC的BI或數據可視化應用中。
Apache Drill的主要特性包括:動態模式發現,靈活的數據模型,去中心化的元數據和可擴展性。使用Drill查詢數據集時,模式規範並不是必需的。它使用自描述的格式(如Avro、JSON、Parquet和NoSQL)所提供的信息來決定數據集的模式。它也能處理查詢中模式的更改。
Drill支持層級式的數據模型來查詢複雜數據。它可以查詢複雜的嵌套數據結構。比如,它可以用來查詢存儲在JSON或Parquet中的嵌套數據而不用“鋪平”它們。
在Drill中,中心化的元數據也不是必需的。它通過數據源的存儲插件獲取元數據。因為不依賴中心化的元數據,所以Drill可以用來從多個數據源中立即查詢數據,比如,Hive、HBase和文件。因此,它可以用作一個數據可視化平台。
Dirll兼容Hive。可以在Hive環境中使用Drill來實現對現有Hive表的快速、交互式的即席查詢。它支持Hive的元數據、UDF(用戶定義的函數)和文件格式。
1.7 總結
近年來數據的指數級增長給許多大數據技術帶來了機會。傳統的專有產品要麼無法處理大數據,要麼代價太昂貴。這就為開源大數據技術打開了一扇門。僅僅在過去幾年裏,這個領域的快速創新已經催生出很多新產品。大數據領域如此之大,以至於可以寫一本書專門來介紹各種各樣的大數據技術。
本章僅討論了幾項與Spark相關的大數據技術,也介紹了Hadoop及其生態係統中的關鍵技術。Spark也是這個生態係統中的一部分。
Spark將在第3章介紹。第2章會先討論Scala,一種集函數式編程和麵向對象編程於一體的編程語言。理解Scala非常重要,因為本書中所有示例代碼都用Scala編寫。另外,Spark本身用Scala所寫,但也支持其他語言,如Java、Python和R。
最後更新:2017-05-19 16:38:04