Hive 之 壓縮和存儲

一、 壓縮

1.1 MR 支持的壓縮編碼

壓縮格式 工具 算法 文件擴展名 是否可切分
DEFAULT DEFAULT .deflate
Gzip gzip DEFAULT .gz
bzip2 bzip2 bzip2 .bz2
LZO lzop LZO .lzo
Snappy Snappy .snappy

爲了支持多種壓縮/解壓縮算法, Hadoop 引入了編碼/解碼器,如下表所示:

壓縮格式 對應的編碼/解碼器
DEFLATE org.apache.hadoop.io.compress.DefaultCodec
gzip org.apache.hadoop.io.compress.GzipCodec
bzip2 org.apache.hadoop.io.compress.BZip2Codec
LZO com.hadoop.compression.lzo.LzopCodec
Snappy org.apache.hadoop.io.compress.SnappyCodec

壓縮性能比較:

壓縮算法 原始文件大小 壓縮文件大小 壓縮速度 解壓速度
gzip 8.3GB 1.8GB 17.5MB/s 58MB/s
bzip2 8.3GB 1.1GB 2.4MB/s 9.5MB/s
LZO 8.3GB 2.9GB 49.3MB/s 74.6MB/s

http://google.github.io/snappy/
On a single core of a Core i7 processor in 64-bit mode, Snappy compresses at about 250 MB/sec or more and decompresses at about 500 MB/sec or more

1.2 壓縮參數配置

參數 默認值 階段 建議
io.compression.codecs (在 core-site.xml 中配置) org.apache.hadoop.io.compress.DefaultCodec,
org.apache.hadoop.io.compress.GzipCodec,
org.apache.hadoop.io.compress.BZip2Codec,
org.apache.hadoop.io.compress.Lz4Codec
輸入壓縮 Hadoop 使用文件擴展名判斷是否支持某種編解碼器
mapreduce.map.output.compress false mapper 輸出 這個參數設爲 true 啓用壓縮
mapreduce.map.output.compress.codec org.apache.hadoop.io.compress.DefaultCodec mapper 輸出 使用 LZO、LZ4 或 snappy 編解碼器在此階段壓縮數據
mapreduce.output.fileoutputformat.compress false reducer 輸出 這個參數設爲 true 啓用壓縮
mapreduce.output.fileoutputformat.compress.codec org.apache.hadoop.io.compress.DefaultCodec reducer 輸出 使用標準工具或者編解碼器,如 gzip 和 bzip2
mapreduce.output.fileoutputformat.compress.type RECORD reducer 輸出 SequenceFile 輸出使用的壓縮類型:NONE 和 BLOCK

1.3 開啓 Map 輸出階段壓縮

開啓 map 輸出階段壓縮可以減少 job 中 map 和 Reduce task 間數據傳輸量。具體配置如下:

案例實操:

1.開啓 hive 中間傳輸數據壓縮功能

hive(default)>set hive.exec.compress.intermediate=true;

2.開啓 mapreduce 中 map 輸出壓縮功能

hive (default)>set mapreduce.map.output.compress=true;

3.設置 mapreduce 中 map 輸出數據的壓縮方式

hive (default)>set mapreduce.map.output.compress.codec=org.apache.hadoop.io.compress.SnappyCodec;

4.執行查詢語句

hive (default)> select count(ename) name from emp;

1.4 開啓 Reduce 輸出階段壓縮

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

1.開啓 hive 最終輸出數據壓縮功能

hive (default)>set hive.exec.compress.output=true;

2.開啓 mapreduce 最終輸出數據壓縮

hive (default)>set mapreduce.output.fileoutputformat.compress=true;

3.設置 mapreduce 最終數據輸出壓縮方式

hive (default)> set mapreduce.output.fileoutputformat.compress.codec = org.apache.hadoop.io.compress.SnappyCodec;

4.設置 mapreduce 最終數據輸出壓縮爲塊壓縮

hive (default)> set mapreduce.output.fileoutputformat.compress.type=BLOCK;

5.測試一下輸出結果是否是壓縮文件

hive (default)> insert overwrite local directory 
			  > '/opt/module/data/snappy-result' 
			  > select * from emp distribute by deptno sort by empno desc;
  1. 查看結果
[root@hadoop102 snappy-result]# cd /opt/module/data/snappy-result/

[root@hadoop102 snappy-result]# ll
總用量 4
-rw-r--r--. 1 root root 446 4月  12 16:54 000000_2.snappy

[root@hadoop102 snappy-result]# cat 000000_2.snappy 
¶󎵹34MILLERCLERK77821982-1-231300.0\N10
7902FORDANALYST75661981-12-330.20.0JAMES698[1	950	Z,30
1-175000,787-51.YL844TURNERSALESMAN]9-8150a^L39KINGPRESIDENT\N
|SCOTTB斷-4-196柲8CLARKMANAGER7q%6-924耝!BLAKEJ.5-128.º$654MARTINV鎲812114A5!JONESJc4-22975){!§521WARDNa
-1$369SMITHMgAK2a5`499ALLER2-2016
               1980A
                    817800.0\N20

可以看到結果已經是採用了 snappy 的方式壓縮過了的、

二、 存儲

2.1 行存儲和列存儲

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

2.1.1 行存儲的特點

查詢滿足條件的一整行數據的時候,列存儲則需要去每個聚集的字段找到對應的每個列的值,行存儲只需要找到其中一個值,其餘的值都在相鄰地方, 所以此時行存儲查詢的速度更快。

TEXTFILE 和 SEQUENCEFILE 的存儲格式都是基於行存儲的;

2.1.2 列存儲的特點

因爲每個字段的數據聚集存儲,在查詢只需要少數幾個字段的時候,能大大減少讀取的數據量;每個字段的數據類型一定是相同的,列式存儲可以針對性的設計更好的設計壓縮算法。

ORC 和 PARQUET 是基於列式存儲的。

2.2 TextFile 格式

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

2.3 Orc 格式

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

所示可以看到每個 Orc 文件由 1 個或多個 stripe 組成,每個 stripe250MB 大小, 這個 Stripe 實際相當於 RowGroup 概念,不過大小由 4MB ~ 250MB, 這樣應該能提升順序讀的吞吐率。每個 Stripe 裏有三部分組成,分別是 Index Data, Row Data, Stripe Footer:

1) Index Data:一個輕量級的 index,【默認是每隔 1W 行】做一個索引。這裏做的索引應該只是記錄某行的各字段在 Row Data 中的 offset。

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

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

每個文件有一個 File Footer,這裏面存的是每個 Stripe 的行數,每個 Column 的數據類型信息等;每個文件的尾部是一個 PostScript,這裏面記錄了整個文件的壓縮類型以及 FileFooter 的長度信息等。在讀取文件時,會 seek 到文件尾部讀 PostScript,從裏面解析到 File Footer 長度,再讀 FileFooter,從裏面解析到各個 Stripe 信息,再讀各個 Stripe,即【從後往前讀】。

嚴格來說, Orc 應該叫做【行列式存儲】。

2.4 Parquet 格式

Parquet 是面向分析型業務的列式存儲格式,由 Twitter 和 Cloudera 合作開發, 2015 年 5 月從 Apache 的孵化器裏畢業成爲 Apache 頂級項目。

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

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

Parquet 的一個文件中可以存儲多個行組,文件的首位都是該文件的 Magic Code,用於校驗它是否是一個 Parquet 文件, Footer length 記錄了文件元數據的大小,通過該值和文件長度可以計算出元數據的偏移量,文件的元數據中包括每一個行組的元數據信息和該文件存儲數據的 Schema 信息。除了文件中每一個行組的元數據,每一頁的開始都會存儲該頁的元數據,在 Parquet 中,有三種類型的頁: 數據頁、字典頁和索引頁。數據頁用於存儲當前行組中該列的值,字典頁存儲該列值的編碼字典,每一個列塊中最多包含一個字典頁,索引頁用來存儲當前行組下該列的索引,目前 Parquet 中還不支持索引頁。

嚴格來說, Parquet 也應該叫做【行列式存儲】。

2.5 主流文件存儲格式對比實驗

從存儲文件的【壓縮比】和【查詢速度】兩個角度對比。

2.5.1 存儲文件的壓縮比測試

  1. TextFile

創建表並導入數據:

hive (default)> create table log_text (
              > track_time string,
              > url string,
              > session_id string,
              > referer string,
              > ip string,
              > end_user_id string,
              > city_id string
              > )
              > row format delimited fields terminated by '\t'
              > stored as textfile;
OK
Time taken: 0.567 seconds

hive (default)> load data local inpath 
              > '/opt/module/data/log.data'
              > into table log_text;
Loading data to table default.log_text
Table default.log_text stats: [numFiles=1, totalSize=19014996]
OK
Time taken: 0.923 seconds

查看大小:

hive (default)> dfs -du -h /user/hive/warehouse/log_text;
18.1 M  /user/hive/warehouse/log_text/log.data
  1. Orc:

創建表並導入數據:

hive (default)> create table log_orc(
              > track_time string,
              > url string,
              > session_id string,
              > referer string,
              > ip string,
              > end_user_id string,
              > city_id string
              > )
              > row format delimited fields terminated by '\t'
              > stored as orc ;
OK
Time taken: 0.156 seconds

hive (default)> insert into log_orc
			  > select * from log_text;

... ...
OK
log_text.track_time	log_text.url	log_text.session_id	log_text.referer	log_text.ip	log_text.end_user_id	log_text.city_id
Time taken: 19.947 seconds

【注】此處就不能使用 load data local inpath 的命令添加數據了, 得使用 insert into table 的命令從 log_text 中查出來數據, 放到 log_orc 表裏面; 使用了 MR 的方式, 纔會存成 Orc 格式;

查看大小:

hive (default)> dfs -du -h /user/hive/warehouse/log_orc;
2.8 M  /user/hive/warehouse/log_orc/000000_0
  1. Parquet:

創建表並導入數據:

hive (default)> create table log_parquet(
              > track_time string,
              > url string,
              > session_id string,
              > referer string,
              > ip string,
              > end_user_id string,
              > city_id string
              > )
              > row format delimited fields terminated by '\t'
              > stored as parquet ;
OK
Time taken: 0.106 seconds

hive (default)> insert into table log_parquet
              > select * from log_text;

... ...
OK
log_text.track_time	log_text.url	log_text.session_id	log_text.referer	log_text.ip	log_text.end_user_id	log_text.city_id
Time taken: 20.882 seconds

【注】同樣使用 insert into 的形式通過 MR 導入數據, 使之存成 Parquet 格式;

查看大小:

hive (default)> dfs -du -h /user/hive/warehouse/log_parquet;
13.1 M  /user/hive/warehouse/log_parquet/000000_0
  1. 總結

存儲文件的壓縮比總結:

ORC > Parquet > textFile

2.5.2 存儲文件的查詢速度測試

  1. TestFile
hive (default)> select count(*) from log_text;

... ...
OK
_c0
100000
Time taken: 16.086 seconds, Fetched: 1 row(s)
  1. Orc:
hive (default)> select count(*) from log_orc;

... ...
OK
_c0
100000
Time taken: 15.88 seconds, Fetched: 1 row(s)
  1. Parquet:
hive (default)> select count(*) from log_parquet;

... ...
OK
_c0
100000
Time taken: 17.375 seconds, Fetched: 1 row(s)
  1. 總結

查詢速度基本相同, 孤例不爲證, 多次試驗基本也相仿;

2.6 總結

基於數據文件的存儲壓縮比和查詢速度的比較, 企業中 Orc 的存儲方式比較受歡迎。

三、 測試壓縮和存儲

3.1 創建一個非壓縮的 Orc 存儲方式

創建表並導入數據:

hive (default)> create table log_orc_none(
              > track_time string,
              > url string,
              > session_id string,
              > referer string,
              > ip string,
              > end_user_id string,
              > city_id string
              > )
              > row format delimited fields terminated by '\t'
              > stored as orc tblproperties ("orc.compress"="NONE");
OK
Time taken: 0.329 seconds

hive (default)> insert into table log_orc_none select * from
              > log_text ;

... ...
OK
log_text.track_time	log_text.url	log_text.session_id	log_text.referer	log_text.ip	log_text.end_user_id	log_text.city_id
Time taken: 13.373 seconds

查看大小:

hive (default)> dfs -du -h /user/hive/warehouse/log_orc_none;
7.7 M  /user/hive/warehouse/log_orc_none/000000_0

3.2 創建一個 Snappy 壓縮的 Orc 存儲方式

創建表並導入數據:

hive (default)> create table log_orc_snappy(
              > track_time string,
              > url string,
              > session_id string,
              > referer string,
              > ip string,
              > end_user_id string,
              > city_id string
              > )
              > row format delimited fields terminated by '\t'
              > stored as orc tblproperties ("orc.compress"="SNAPPY");
OK
Time taken: 0.103 seconds

hive (default)> insert into table log_orc_snappy select * from
              > log_text ;

... ...
OK
log_text.track_time	log_text.url	log_text.session_id	log_text.referer	log_text.ip	log_text.end_user_id	log_text.city_id
Time taken: 12.056 seconds

查看大小:

hive (default)> dfs -du -h /user/hive/warehouse/log_orc_snappy;
3.8 M  /user/hive/warehouse/log_orc_snappy/000000_0

3.3 小總結

在上一節中的 “主流文件存儲格式對比實驗” 中進行的測試時, 壓縮後的 Orc 的表的文件只有 2.8 M, 而即使使用 Snappy 壓縮後的數據依然有 3.8 M, 原因是 Orc 存儲文件默認採用的是 Zlib 壓縮(Orc 自帶的), 比 Snappy 壓縮的還小。

四、 存儲方式和壓縮總結

在實際的項目開發當中, hive 表的數據存儲格式一般選擇: orc 或 parquet。壓縮方式一般選擇 snappy、 lzo。

【注】如果是最終的結果表, 可以使用 Orc 的存儲格式, 因爲佔用的空間小; 如果是中間表, 後續還需要使用它進行計算, 就不能使用 Orc, 因爲 Orc 是列式存儲, 而 Hadoop 讀取數據是按行讀取。

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