hive 總結三(壓縮)

本文參考:黑澤君相關博客
本文是我總結日常工作中遇到的坑,結合黑澤君相關博客,選取、補充了部分內容。
開啓 map 輸出階段壓縮可以減少 job 中 map 和 Reduce task 間數據傳輸量。

查看配置命令如下,對應的設置只要加上相關值即可,如下

是否開啓hive中間傳輸數據壓縮功能?
hive> set hive.exec.compress.intermediate;
hive.exec.compress.intermediate=false

開啓hive中間傳輸數據壓縮功能
hive>  set hive.exec.compress.intermediate=true;
是否開啓mapreduce中map輸出壓縮功能
hive> set mapreduce.map.output.compress;
mapreduce.map.output.compress=true
是否設置mapreduce中map輸出數據的壓縮方式
hive> set mapreduce.map.output.compress;
mapreduce.map.output.compress=true

當 Hive 將輸出寫入到表中時,輸出內容同樣可以進行壓縮。屬性 hive.exec.compress.output 控制着這個功能。
用戶可能需要保持默認設置文件中的默認值 false,這樣默認的輸出就是非壓縮的純文本文件了。用戶可以通過在查詢語句或執行腳本中設置這個值爲 true,來開啓輸出結果壓縮功能。

查看配置命令如下,對應的設置只要加上相關值即可,如下

是否開啓hive最終輸出數據壓縮功能
hive> set hive.exec.compress.output;
hive.exec.compress.output=false
是否開啓mapreduce最終輸出數據壓縮
hive> set hive.exec.compress.output;
hive.exec.compress.output=false
是否設置mapreduce最終數據輸出壓縮方式
hive> set mapreduce.output.fileoutputformat.compress.codec;
mapreduce.output.fileoutputformat.compress.codec=org.apache.hadoop.io.compress.DefaultCodec

設置爲SnappyCodec 壓縮
hive> set mapreduce.output.fileoutputformat.compress.codec=org.apache.hadoop.io.compress.SnappyCodec ;
是否設置mapreduce最終數據輸出壓縮爲塊壓縮(默認是行壓縮RECORD)
hive> set mapreduce.output.fileoutputformat.compress.type;
mapreduce.output.fileoutputformat.compress.type=BLOCK

文件存儲格式

Hive支持的存儲數的格式主要有:TEXTFILE 、SEQUENCEFILE、ORC、PARQUET。

TextFile格式

默認格式,數據不做壓縮,磁盤開銷大,數據解析開銷大。
可結合Gzip、Bzip2使用。
但使用Gzip這種方式,hive不會對數據進行切分,從而無法對數據進行並行操作。

Orc格式

Orc (Optimized Row Columnar)是Hive 0.11版裏引入的新的存儲格式。

Index Data
Index Data 包括每一列的最小值和最大值,以及每一列中的行位置。(也可以包含bit field or bloom filter ) 行索引項提供了偏移量,使您能夠在解壓縮塊中查找正確的壓縮塊和字節。
注意,ORC索引僅用於選擇stripes 和 row groups,而不用於回答查詢。
擁有相對頻繁的行索引項可以在stripe 內跳過行,以便快速讀取,儘管stripe 很大。默認情況下,可以跳過每10,000行。

Row Data
存的是具體的數據,先取部分行,然後對這些行按列進行存儲。對每個列進行了編碼,分成多個Stream來存儲。

Stripe Footer
存的是各個Stream的類型,長度等信息。

File Footer
每個文件有一個File Footer,這裏面存的是每個Stripe的行數,每個Column的數據類型信息等;

PostScript
每個文件的尾部是一個PostScript,這裏面記錄了整個文件的壓縮類型以及FileFooter的長度信息等。

在讀取文件時,會seek到文件尾部讀PostScript,從裏面解析到File Footer長度,再讀FileFooter,從裏面解析到各個Stripe信息,再讀各個Stripe,即從後往前讀。

Orc格式 結構.png

示例:
數據量:19017003
hive> CREATE TABLE tmp.orcTest stored AS ORC 
    > TBLPROPERTIES
    > ('orc.compress'='SNAPPY',
    > 'orc.create.index'='true',
    > 'orc.bloom.filter.fpp'='0.05',
    > 'orc.stripe.size'='10485760',
    > 'orc.row.index.stride'='10000') 
    > AS 
    > SELECT 
    > *
    > FROM tmp.textFileTest
Stage-Stage-1: Map: 16  Reduce: 62   Cumulative CPU: 1350.32 sec   HDFS Read: 4140450145 HDFS Write: 250057437 SUCCESS

向表中加載數據(不能使用load方式加載數據,需要insert into方式或者上述方式,即一定要通過MapReduce任務加載數據)
orc:不使用索引
hive> set hive.optimize.index.filter=false;
hive> select * from tmp.orcTest where userid ='02012138';
Query ID = hdfs_20190716114646_cb74ab6e-3d7f-42a8-b1e8-703abd89c420
Total jobs = 1
Launching Job 1 out of 1
.
.
.
Stage-Stage-1: Map: 5   Cumulative CPU: 32.88 sec   HDFS Read: 250016639 HDFS Write: 175 SUCCESS
Total MapReduce CPU Time Spent: 32 seconds 880 msec
OK
02012138     2019-06-16 00:21:03.000000000   10000                           0       20190616
Time taken: 13.935 seconds, Fetched: 1 row(s)
很明顯,掃描了所有記錄。再使用索引查詢:
orc:使用索引
hive> set hive.optimize.index.filter=true;
hive> select * from tmp.orcTest where userid ='02012138';
Query ID = hdfs_20190716114747_dd02a4a3-7a25-424b-84d8-a314e918464f
Total jobs = 1
Launching Job 1 out of 1
.
.
.
Stage-Stage-1: Map: 5   Cumulative CPU: 24.77 sec   HDFS Read: 58144301 HDFS Write: 175 SUCCESS
Total MapReduce CPU Time Spent: 24 seconds 770 msec
OK
02012138     2019-06-16 00:21:03.000000000   10000
Time taken: 12.916 seconds, Fetched: 1 row(s)

可以看到,只掃描了部分記錄,即根據Row Group Index中的min/max跳過了WHERE條件中不包含的stripes,索引有效果。
TeXtFile
hive> select * from tmp.tb_tmp_tms_stb_errorcode where userid ='02012138';
Query ID = hdfs_20190716114747_ac4b272c-4317-4b47-9726-91f297fc1af8
Total jobs = 1
Launching Job 1 out of 1
.
.
.
Stage-Stage-1: Map: 16   Cumulative CPU: 112.89 sec   HDFS Read: 4140148821 HDFS Write: 175 SUCCESS
Total MapReduce CPU Time Spent: 1 minutes 52 seconds 890 msec
OK
02012138     2019-06-16 00:21:03.000000000   10000
Time taken: 17.072 seconds, Fetched: 1 row(s)

數據未經過壓縮,讀取全集數據
注:我看一些文檔說,Orc列存儲,如果用 =,> 之類 篩選列不會觸發 mapReduce,經過測試,還是觸發了,而且查詢時間整體上比TextFile 短。  
關於mapReduce的後續再找找答案,或者有知道的道友分享下。

ORC格式會將其轉換成如下的樹狀結構.png


Parquet格式

這個東東我用的少,瞭解不多,在這裏就僅僅標記一下

Parquet文件是以二進制方式存儲的,所以是不可以直接讀取的,文件中包括該文件的數據和元數據,因此Parquet格式文件是自解析的。

通常情況下,在存儲Parquet數據的時候會按照Block大小設置行組的大小,由於一般情況下每一個Mapper任務處理數據的最小單位是一個Block,這樣可以把每一個行組由一個Mapper任務處理,增大任務執行並行度。Parquet文件的格式如下圖所示。

Parquet文件 格式.png

各種存儲文件的查詢速度總結:經過驗證,查詢速度相近, orc、parquet有時候會比TextFile稍微快一丟丟。

小結:在實際的項目開發當中,hive表的數據存儲格式一般選擇:orc或parquet。壓縮方式一般選擇snappy或lzo。(使用壓縮後可大量節省空間)


存儲和壓縮結合

  • 查看hadoop支持的壓縮方式
[hdfs@tmpe2e02 tmp_lillcol]$ hadoop checknative
19/07/16 14:21:20 INFO bzip2.Bzip2Factory: Successfully loaded & initialized native-bzip2 library system-native
19/07/16 14:21:20 INFO zlib.ZlibFactory: Successfully loaded & initialized native-zlib library
Native library checking:
hadoop:  true /opt/cloudera/parcels/CDH-5.7.2-1.cdh5.7.2.p0.18/lib/hadoop/lib/native/libhadoop.so.1.0.0
zlib:    true /lib64/libz.so.1
snappy:  true /opt/cloudera/parcels/CDH-5.7.2-1.cdh5.7.2.p0.18/lib/hadoop/lib/native/libsnappy.so.1
lz4:     true revision:10301
bzip2:   true /lib64/libbz2.so.1
openssl: true /usr/local/ssl/lib/libcrypto.so
  • HiveQL語句指定ORC文件格式配置
配置 默認值 備註
orc.compress ZLIB 高級壓縮(one of NONE, ZLIB, SNAPPY)
orc.compress.size 262,144 每個壓縮塊中的字節數
orc.stripe.size 67,108,864 每條stripe中的字節數
orc.row.index.stride 10,000 索引條目之間的行數(必須是>= 1000)
orc.create.index true 是否創建行索引
orc.bloom.filter.columns "" 逗號分隔的列名列表,應該爲其創建bloom過濾器
orc.bloom.filter.fpp 0.05 bloom過濾器的誤報概率(必須是>0.0和<1.0)
案例:
CREATE TABLE tmp.orcTest stored AS ORC 
TBLPROPERTIES
('orc.compress'='SNAPPY',
'orc.create.index'='true',
'orc.bloom.filter.fpp'='0.05',
'orc.stripe.size'='10485760',
'orc.row.index.stride'='10000') 
AS 
SELECT 
*
FROM tmp.orcTextFile
DISTRIBUTE BY userid sort BY userid;

orc存儲文件默認採用ZLIB壓縮。ZLIB壓縮率比snappy的高,但是ZLIB解壓縮速率很低。

Fetch抓取

Fetch抓取是指,Hive中對某些情況的查詢可以不必使用MapReduce計算。
例如:SELECT * FROM orcTest; 在這種情況下,Hive可以簡單地讀取orcTest對應的存儲目錄下的文件,然後輸出查詢結果到控制檯。

配置
hive-default.xml.template 中 hive.fetch.task.conversion

<property>
    <name>hive.fetch.task.conversion</name>
    <value>more</value>
    <description>
      可選值 [none, minimal, more].
      一些select查詢可以轉換爲單個獲取任務,從而最小化延遲。
      目前,查詢應該是單一來源的,沒有任何子查詢,也不應該有任何聚合或區別(引起RS)、橫向視圖和連接。
      0. none : 禁用 hive.fetch.task.conversion
      1. minimal : SELECT STAR, FILTER on partition columns, LIMIT only
      2. more  : SELECT, FILTER, LIMIT only (support TABLESAMPLE and virtual columns)
    </description>
</property>
測試:
hive> set hive.fetch.task.conversion; //查詢當前配置
hive.fetch.task.conversion=minimal

hive> set hive.fetch.task.conversion=none;
hive> select userid from tmp.orcTest limit 1;
Query ID = hdfs_20190716151010_29239e97-a06c-47aa-9958-f1964ab8eb17
Total jobs = 1
Launching Job 1 out of 1
.
.
.
Stage-Stage-1: Map: 5   Cumulative CPU: 15.09 sec   HDFS Read: 4155591 HDFS Write: 661 SUCCESS
Total MapReduce CPU Time Spent: 15 seconds 90 msec
OK
02012138
Time taken: 13.908 seconds, Fetched: 10 row(s)

hive> set hive.fetch.task.conversion=more;
hive> select userid from tmp.orcTest limit 10;
OK
02012138
Time taken: 0.025 seconds, Fetched: 10 row(s)

把hive.fetch.task.conversion設置成none,然後執行查詢語句,都會執行MapReduce程序。


本地模式

有時Hive的輸入數據量是非常小的。
在這種情況下,爲查詢觸發執行任務消耗的時間可能會比實際job的執行時間要多的多。
對於大多數這種情況,Hive可以通過本地模式在單臺機器上處理所有的任務。
對於小數據集,執行時間可以明顯被縮短。

// 開啓本地mr模式
hive> set hive.exec.mode.local.auto;
hive.exec.mode.local.auto=false

// 設置local mr的最大輸入數據量,當輸入數據量小於這個值時採用local mr的方式,默認爲134217728,即128M
hive> set hive.exec.mode.local.auto.inputbytes.max;
hive.exec.mode.local.auto.inputbytes.max=134217728

// 設置local mr的最大輸入文件個數,當輸入文件個數小於這個值時採用local mr的方式,默認爲4
hive> set hive.exec.mode.local.auto.input.files.max;
hive.exec.mode.local.auto.input.files.max=4

上面是查看參數值的方法,對應的設置直接改成設置值即可。
創建測表
hive> CREATE TABLE tmp.orclocal stored AS ORC 
    > TBLPROPERTIES
    > ('orc.compress'='SNAPPY',
    > 'orc.create.index'='true',
    > 'orc.bloom.filter.fpp'='0.05',
    > 'orc.stripe.size'='10485760',
    > 'orc.row.index.stride'='10000') 
    > AS 
    > SELECT 
    > *
    > FROM tmp.orcTest 
    > DISTRIBUTE BY userid sort BY userid limit 1000;

查看文件數量:1個 符合配置
hive> !hadoop fs -du -h hdfs://ns1/user/hive/warehouse/tmp.db/orclocal;
22.5 K  45.1 K  hdfs://ns1/user/hive/warehouse/tmp.db/orclocal/000000_0

關閉本地模式,並執行查詢語句
hive> set hive.exec.mode.local.auto=false;
hive> select count(*) from tmp.orclocal;
OK
1000
Time taken: 18.98 seconds, Fetched: 1 row(s)
開啓本地模式,並執行查詢語句
hive> set hive.exec.mode.local.auto=true;
hive> select count(*) from tmp.orclocal;
OK
1000
Time taken: 1.576 seconds, Fetched: 1 row(s)

時間對比有點不真實了....,但是測試幾次,在小文件的情況下開啓本地模式確實優勢很大

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章