如何在HDFS中進行資料壓縮以實現高效儲存?
在上一節,我們介紹了在HDFS中組織資料的規則和方法。本節作為《Hadoop從入門到精通》專題的第四章第二節,將主要介紹如何在HDFS中進行資料壓縮,有哪些可選的資料壓縮方法等內容。資料壓縮是一種將資料簡化為更緊湊形式的機制,以節省儲存空間並提高資料傳輸效率。
4.2 透過資料壓縮實現高效儲存
資料壓縮是檔案處理的重要方面,在處理Hadoop支援的資料大小時,這一點變得更加重要。大部分企業在使用Hadoop時,目標都是儘可能高效得進行資料處理,選擇合適的壓縮編解碼器將使作業執行更快,並允許在叢集中儲存更多資料。
為資料選擇正確的壓縮編解碼器
在HDFS上使用壓縮並不像在ZFS等檔案系統上那樣透明,特別是在處理可拆分的壓縮檔案時(本章稍後將詳細介紹)。使用Avro和SequenceFile等檔案格式的優點是內建壓縮支援,使壓縮幾乎對使用者完全透明。但是在使用文字等格式時,就會失去這種支援。
問題
評估並確定用於資料壓縮的最佳編解碼器。
解決方案
谷歌的壓縮編解碼器Snappy提供壓縮大小和讀/寫執行時間的最佳組合。但是,當使用必須支援可拆分性的大型壓縮檔案時,LZOP是最好的編解碼器。
討論
首先,快速瀏覽可用於Hadoop的壓縮編解碼器,如表4.1所示。
表4.1壓縮編解碼器
要正確評估編解碼器,首先需要確定評估標準,該標準應基於功能和效能特徵。對於壓縮,你的標準可能包括以下內容:
-
空間/時間權衡——通常,計算成本越高的壓縮編解碼器可以產生更好的壓縮比,從而產生更小的壓縮輸出。
-
可拆分性——可以拆分壓縮檔案以供多個mapper使用。如果無法拆分壓縮檔案,則只能使用一個mapper。如果該檔案跨越多個塊,則會丟失資料區域性性,因為map可能必須從遠端DataNode讀取塊,從而導致網路I/O開銷。
-
本機壓縮支援——是否存在執行壓縮和解壓縮的本地庫?這通常勝過用Java編寫的壓縮編解碼器,沒有底層的本機庫支援。
表4.2 壓縮編解碼器比較
Native vs Java bzip2
Hadoop新增了對bzip2的原生支援(從版本2.0和1.1.0開始)。本機bzip2支援是預設的,但不支援可拆分性。如果需要可拆分性,就需要啟用Java bzip2,可以透過將io.compression .codec.bzip2.library設定為java-builtin來指定。
接下來,我們來了解編解碼器在空間和時間上是如何平衡的。此處使用100 MB(10 ^ 8)的XML檔案(來自的enwik8.zip)來比較編解碼器執行時間及其壓縮大小,具體測試結果見表4.3。
表4.3 100 MB文字檔案上壓縮編解碼器的效能比較
執行測試
當進行評估時,我建議使用自己的資料進行測試,最好是在類似於生產節點的主機上執行測試,這樣就可以很好地理解編解碼器的預期壓縮和執行時間。
要確保叢集已啟用本機編解碼器,你可以透過執行以下命令來檢查:
$ hadoop checknative -a
空間和時間的結果說明了什麼?如果將盡可能多的資料壓入叢集是首要任務,並且允許較長的壓縮時間,那麼bzip2可能是適合的編解碼器。如果要壓縮資料但要求在讀取和寫入壓縮檔案時引入最少的CPU開銷,則應該考慮LZ4。任何尋求壓縮和執行時間之間平衡的企業都不會考慮bzip2的Java版本。
拆分壓縮檔案很重要,但必須在bzip2和LZOP之間進行選擇。原生bzip2編解碼器不支援拆分,Java bzip2 time可能會讓大多數人放棄。bzip2優於LZOP的唯一優勢是其Hadoop整合比LZOP更容易使用。
圖4.4 單個100 MB文字檔案的壓縮大小(較小的值更好)
圖4.5單個100 MB文字檔案的壓縮和解壓縮時間(較小的值更好)
雖然LZOP似乎看起來是最優的選擇,但還是需要做一些改進,正如下文所述。
總結
最適合的編解碼器取決於你的需求和標準。如果不關心拆分檔案,LZ4是最有前途的編解碼器,如果想要拆分檔案,LZOP就是最應該關注的。
此外,我們還需要考慮資料是否需要長期儲存。如果長時間儲存資料,你可能希望最大限度地壓縮檔案,我建議使用基於zlib的編解碼器(例如gzip)。但是,由於gzip不可拆分,因此將它與基於塊的檔案格式(如Avro或Parquet)結合使用是明智的,這樣資料仍然可以拆分,或者調整輸出大小使其在HDFS中佔用一個塊,這樣就不需要考慮是否可拆分。
請記住,壓縮大小將根據檔案是文字還是二進位制而有所不同,具體取決於其內容。要獲得準確的數字,需要針對自己的資料執行類似的測試。
對HDFS中的資料進行壓縮有許多好處,包括減小檔案大小和更快的MapReduce作業執行時。許多壓縮編解碼器可用於Hadoop,我根據功能和效能對它們進行了評估。接下來,讓我們看看如何壓縮檔案並透過MapReduce,Pig和Hive等工具使用它們。
使用HDFS,MapReduce,Pig和Hive進行壓縮
由於HDFS不提供內建的壓縮支援,因此在Hadoop中使用壓縮可能是一項挑戰。此外,可拆分壓縮不適合技術水平不高的初學者,因為它並不是Hadoop開箱即用的功能。如果正在處理壓縮到接近HDFS塊大小的中型檔案,以下方法將是在Hadoop中壓縮優勢最明顯和最簡單的方法。
問題
希望在HDFS中讀取和寫入壓縮檔案,並將其與MapReduce,Pig和Hive一起使用。
解決方案
在MapReduce中使用壓縮檔案涉及更新MapReduce配置檔案mapred-site.xml並註冊正在使用的壓縮編解碼器。執行此操作後,在MapReduce中使用壓縮輸入檔案不需要額外的步驟,並且生成壓縮的MapReduce輸出是設定mapred.output.compress和mapred.output.compression.codec MapReduce屬性的問題。
討論
第一步是弄清楚如何使用本章前面評估的編解碼器來讀取和寫入檔案。本章詳細介紹的所有編解碼器都與Hadoop捆綁在一起,但LZO / LZOP和Snappy除外,如果想使用這三種編解碼器,需要自己下載並構建。
要使用壓縮編解碼器,首先需要知道它們的類名,如表4.4所示。
表4.4 編解碼器類
在HDFS中使用壓縮
如何使用上表中提到的任何一種編解碼器壓縮HDFS中的現有檔案?以下程式碼支援這樣做:
編解碼器快取使用壓縮編解碼器的一個開銷是建立成本很高。當使用Hadoop ReflectionUtils類時,與建立例項相關的一些開銷將快取在ReflectionUtils中,這將加速後續建立編解碼器。更好的選擇是使用CompressionCodecFactory,它本身提供編解碼器快取。
讀取此壓縮檔案就像編寫一樣簡單:
超級簡單。既然可以建立壓縮檔案,那麼讓我們看看如何在MapReduce中使用。
在MapReduce中使用壓縮
要在MapReduce中使用壓縮檔案,需要為作業設定一些配置選項。為簡潔起見,我們假設在此示例中使用了identity mapper和reducer:
使用未壓縮I/O與壓縮I/O的MapReduce作業之間的唯一區別是前面示例中的三個帶註釋的行。
不僅可以壓縮作業的輸入和輸出,而且中間map輸出也可以壓縮,因為它首先輸出到磁碟,最終透過網路輸出到reducer。map輸出的壓縮有效性最終取決於發出的資料型別,但一般情況下,我們可以透過進行此更改來加速某些作業程式。
為什麼不必在前面的程式碼中為輸入檔案指定壓縮編解碼器?預設情況下,FileInputFormat類使用CompressionCodecFactory來確定輸入副檔名是否與已註冊的編解碼器匹配。如果找到與該副檔名相關聯的編解碼器,會自動使用該編解碼器解壓縮輸入檔案。
MapReduce如何知道要使用哪些編解碼器?需要在mapred-site.xml中指定編解碼器。 以下程式碼顯示瞭如何註冊上述提到的所有編解碼器。請記住,除了gzip,Deflate和bzip2之外,所有壓縮編解碼器都需要構建並在叢集上可用,然後才能註冊:
現在,你已經使用MapReduce掌握了壓縮,是時候瞭解Hadoop堆疊資訊了。因為壓縮也可以與Pig和Hive一起使用,讓我們看看如何使用Pig和Hive映象完成MapReduce壓縮。
在Pig中使用壓縮
如果你正在使用Pig,那麼使用壓縮輸入檔案不需要額外的工作,需要做的就是確保副檔名map到相應的壓縮編解碼器(參見表4.4)。以下示例是gzips本地加密檔案載入到Pig,並轉儲使用者名稱的過程:
寫gzip壓縮檔案是一樣的,都要確保指定壓縮編解碼器的副檔名。以下示例將Pig關係B的結果儲存在HDFS檔案中,然後將它們複製到本地檔案系統以檢查內容:
在Hive中使用壓縮
與Pig一樣,我們需要做的就是在定義檔名時指定編解碼器擴充套件:
前面的示例將一個gzip壓縮檔案載入到Hive中。在這種情況下,Hive將正在載入的檔案移動到資料倉儲目錄,並繼續使用原始檔案作為表的儲存。
如果要建立另一個表並指定需要被壓縮該怎麼辦?下面的示例透過一些Hive配置來啟用MapReduce壓縮實現這一點(因為將執行MapReduce作業以在最後一個語句中載入新表):
我們可以透過在HDFS中檢視來驗證Hive是否確實壓縮了新apachelog_backup表的儲存:
應該注意的是,Hive建議使用SequenceFile作為表的輸出格式,因為SequenceFile塊可以單獨壓縮。
總結
此技術提供了一種在Hadoop中執行壓縮的快速簡便方法,這適用於不太大的檔案,因為它提供了一種相對透明的壓縮方式。如果壓縮檔案遠大於HDFS塊大小,請考慮以下方法。
可拆分LZOP,帶有MapReduce,Hive和Pig
如果你正在使用大型文字檔案,即使在壓縮時,這也會比HDFS塊大小大很多倍。為避免讓一個map任務處理整個大型壓縮檔案,你需要選擇一個可支援拆分該檔案的壓縮編解碼器。
LZOP符合要求,但使用它比上文示例更復雜,因為LZOP本身不可拆分。因為LZOP是基於塊的,不可能隨機搜尋LZOP檔案並確定下一個塊的起點,這是該方法面臨的挑戰。
問題
希望使用壓縮編解碼器,以允許MapReduce在單個壓縮檔案上並行工作。
解決方案
在MapReduce中,拆分大型LZOP壓縮輸入檔案需要使用LZOP特定的輸入格式類,例如LzoInputFormat。在Pig和Hive中使用LZOP壓縮的輸入檔案時,同樣的原則也適用。
討論
LZOP壓縮編解碼器是僅有的允許拆分壓縮檔案的兩個編解碼器之一,因此多個Reducer可並行處理。另一個編解碼器bzip2受到壓縮時間的影響導致執行很慢,可能會導致編解碼器無法使用,LZOP提供了壓縮和速度之間的良好權衡。
LZO和LZOP有什麼區別?LZO和LZOP編解碼器都可用於Hadoop。LZO是一個基於流的壓縮儲存,沒有塊或頭的概念。LZOP具有塊(已校驗和)的概念,因此是要使用的編解碼器,尤其是在希望壓縮輸出可拆分的情況下。令人困惑的是,Hadoop編解碼器預設情況下將以.lzo副檔名結尾的檔案處理為LZOP編碼,以.lzo_deflate副檔名結尾的檔案處理為LZO編碼。此外,許多文件似乎可以互換使用LZO和LZOP。
不幸的是,由於許可原因,Hadoop並未不捆綁LZOP。在叢集上編譯和安裝LZOP非常費力,要編譯本文程式碼,還請先行安裝配置LZOP。
在HDFS中讀寫LZOP檔案
如果要使用LZOP讀寫壓縮檔案,我們需要在程式碼中指定LZOP編解碼器:
程式碼4.3在HDFS中讀寫LZOP檔案的方法
讓我們編寫並讀取LZOP檔案,確保LZOP實用程式可以使用生成的檔案(將$ HADOOP_CONF_HOME替換為Hadoop配置目錄的位置):
以上程式碼將在HDFS中生成core-site.xml.lzo檔案。
現在確保可以將此LZOP檔案與lzop二進位制檔案一起使用。在主機上安裝lzop二進位制檔案將LZOP檔案從HDFS複製到本地磁碟,使用本機lzop二進位制檔案解壓縮,並將其與原始檔案進行比較:
diff驗證了使用LZOP編解碼器壓縮的檔案可以使用lzop二進位制檔案解壓縮。
既然已經擁有了LZOP檔案,我們需要對其進行索引以便可以拆分。
為LZOP檔案建立索引
LZOP檔案本身不可拆分,雖然其具有塊的概念,但缺少塊分隔同步標記意味著無法隨機搜尋LZOP檔案並開始讀取。但是因為在內部確實使用了塊,所以只需要做一些預處理即可,它可以生成一個包含塊偏移的索引檔案。
完整讀取LZOP檔案,並在讀取發生時將塊偏移寫入索引檔案。索引檔案格式(如圖4.6所示)是一個二進位制檔案,包含一系列連續的64-bit數字,表示LZOP檔案中每個塊的位元組偏移量。
你可以使用以下兩種方式建立索引檔案,如果要為單個LZOP檔案建立索引檔案,只需要進行一個簡單的庫呼叫即可,如下:
shell$ hadoop com.hadoop.compression.lzo.LzoIndexer core-site.xml.lzo
如果有大量LZOP檔案並且需要更有效的方法來生成索引檔案,索引器執行MapReduce作業以建立索引檔案,支援檔案和目錄(以遞迴方式掃描LZOP檔案):
圖4.6中描述的兩種方法都將在與LZOP檔案相同的目錄中生成索引檔案。索引檔名是以.index為字尾的原始LZOP檔名。執行以前的命令將生成檔名core-site.xml.lzo.index。
接下來,我們來看看如何在Java程式碼中使用LzoIndexer。以下程式碼(來自LzoIndexer的主方法)將導致同步建立索引檔案:
使用DistributedLzoIndexer,MapReduce作業將啟動並執行N個mapper,每個.lzo檔案一個。沒有執行reducer,因此(identity)mapper透過自定義LzoSplitInputFormat和LzoIndexOutputFormat直接寫入索引檔案。
如果要從自己的Java程式碼執行MapReduce作業,可以使用DistributedLzoIndexer程式碼。
需要LZOP索引檔案,以便可以在MapReduce,Pig和Hive作業中拆分LZOP檔案。既然已經擁有了上述LZOP索引檔案,讓我們看一下如何將它們與MapReduce一起使用。
MapReduce和LZOP
在為LZOP檔案建立索引檔案之後,就可以開始將LZOP檔案與MapReduce一起使用了。不幸的是,這給我們帶來了下一個挑戰:現有的基於Hadoop檔案的內建輸入格式都不適用於可拆分LZOP,因為它們需要專門的邏輯來處理使用LZOP索引檔案的輸入拆分。我們需要特定的輸入格式類才能使用可拆分LZOP。
LZOP庫為面向行的LZOP壓縮文字檔案提供了LzoTextInputFormat實現,並附帶索引檔案。
以下程式碼顯示了配置MapReduce作業以使用LZOP所需的步驟。 我們將對具有文字LZOP輸入和輸出的MapReduce作業執行以下步驟:
壓縮中間map輸出還將減少MapReduce作業的總體執行時間:
可以透過編輯hdfs-site.xml輕鬆配置叢集以始終壓縮map輸出:
每個LZOP檔案的拆分數量是檔案佔用的LZOP塊數量的函式,而不是檔案佔用的HDFS塊數量函式。
Pig和Hive
Elephant Bird,一個包含與LZOP一起工作的實用程式的Twitter專案,提供了許多有用的MapReduce和Pig類。Elephant Bird有一個LzoPigStorage類,可以在Pig中使用基於文字的LZOP壓縮資料。
透過使用LZO庫中的com.hadoop.mapred .DeprecatedLzoTextInputFormat輸入格式類,Hive可以使用LZOP壓縮的文字檔案。
總結
在Hadoop中使用可拆分壓縮是很棘手的。如果有幸能夠將資料儲存在Avro或Parquet中就會省心不少,因為它們提供了最簡單的方法來處理可輕鬆壓縮和拆分的檔案。如果想壓縮其他檔案格式並進行拆分,LZOP是唯一的候選者。
正如之前提到的,Elephant Bird專案提供了一些有用的LZOP輸入格式,可以使用LZOP壓縮檔案格式,如XML和純文字。如果需要使用Todd Lipcon的LZO專案或Elephant Bird不支援的LZOP壓縮檔案格式,則必須編寫自己的輸入格式。這對開發人員來說是一個很大的挑戰。現在,不少開發者都對Hadoop進行了改進,使其能夠支援具有自定義拆分邏輯的壓縮檔案,終端使用者不必編寫自己的壓縮輸入格式。
對於資源總是稀缺的生產環境而言,壓縮可能是一項很艱鉅的任務。壓縮還允許更快的作業執行時間,因此它是儲存的一個引人注目的方面。本節主要介紹了評估和選擇最適合資料的編解碼器,以及如何使用HDFS,MapReduce,Pig和Hive進行壓縮等內容,希望對各位有所幫助。
本章和前一章致力於研究如何選擇正確的檔案格式,並有效處理MapReduce和HDFS中的大資料。第五章將著手實踐應用這些理論知識,看看如何將資料移入和移出Hadoop。
相關文章:
1、《第一章:Hadoop生態系統及執行MapReduce任務介紹!》連結: http://blog.itpub.net/31077337/viewspace-2213549/
2、《學習Hadoop生態第一步:Yarn基本原理和資源排程解析!》連結: http://blog.itpub.net/31077337/viewspace-2213602/
3、《MapReduce如何作為Yarn應用程式執行?》連結: http://blog.itpub.net/31077337/viewspace-2213676/
4、《Hadoop生態系統各元件與Yarn的相容性如何?》連結: http://blog.itpub.net/31077337/viewspace-2213960/
5、《MapReduce資料序列化讀寫概念淺析!》連結: http://blog.itpub.net/31077337/viewspace-2214151/
6、《MapReuce中對大資料處理最合適的資料格式是什麼?》連結: http://blog.itpub.net/31077337/viewspace-2214325/
7、《如何在MapReduce中使用SequenceFile資料格式?》連結: http://blog.itpub.net/31077337/viewspace-2214505/
8、《如何在MapReduce中使用Avro資料格式?》連結: http://blog.itpub.net/31077337/viewspace-2214709/
9、《企業自有資料格式雜亂,MapReduce如何搞定?》連結:http://blog.itpub.net/31077337/viewspace-2214826/
10、《企業使用Hadoop的重大挑戰:如何在HDFS中組織和使用資料?》連結: http://blog.itpub.net/31545816/viewspace-2215158/
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/31545816/viewspace-2215281/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- Java實現壓縮資料夾Java
- 浪潮線上壓縮,為資料儲存降本增效
- Impala之儲存和壓縮
- 從 RAID 到 Hadoop Hdfs 『大資料儲存的進化史』AIHadoop大資料
- 8-字串的壓縮儲存字串
- Kafka-之資料日誌儲存(格式變化與壓縮)Kafka
- 大資料檔案儲存系統HDFS大資料
- Python實現壓縮和解壓縮Python
- 使用Java API進行tar.gz檔案及資料夾壓縮解壓縮JavaAPI
- 高效的資料壓縮編碼方式 Protobuf
- Redis儲存優化--小物件壓縮Redis優化物件
- 物件儲存服務的壓縮特性物件
- 儲存卡變為RAW,如何進行儲存卡資料救援
- 資料儲存:FMDB-模型進行存取模型
- Hdfs儲存策略
- 使用java API進行zip遞迴壓縮資料夾以及解壓JavaAPI遞迴
- 分散式檔案系統HDFS,大資料儲存實戰(一)分散式大資料
- 初級:如何在 Linux 中 zip 壓縮檔案和資料夾Linux
- 監控影片儲存壓縮解決方案
- Java實現解壓縮檔案和資料夾Java
- HDFS分散式儲存分散式
- 使用 .NET 整合 MinIO 實現高效物件儲存物件
- Hive的壓縮儲存和簡單優化Hive優化
- 實現報表資料分庫儲存
- MySQL如何實現萬億級資料儲存?MySql
- 壓縮Word,一鍵實現Word文件壓縮
- 如何在資料庫中高效實現訂座功能?資料庫
- linux 高效壓縮工具之xz的壓縮解壓使用Linux
- layui中實現上傳圖片壓縮UI
- 2、JSP實現資料傳遞和儲存JS
- 如何利用區塊鏈技術進行資料儲存?區塊鏈
- 如何使用表格儲存控制檯進行資料監控
- 如何在資料庫中儲存小數:FLOAT、DECIMAL還是BIGINT?資料庫Decimal
- 資料如何在一個區塊鏈中儲存和保護?區塊鏈
- 雲上大資料儲存:探究 JuiceFS 與 HDFS 的異同大資料UI
- Android中的資料儲存之檔案儲存Android
- 50億海量資料如何高效儲存和分析?
- 【Node.js】使用mongoose連線資料庫以及進行資料儲存Node.jsGo資料庫