hive 引數優化記錄
HDFS非常容易儲存大資料檔案,如果Hive中存在過多的小檔案會給namecode帶來巨大的效能壓力。同時小檔案過多會影響JOB的執行,hadoop會將一個job轉換成多個task,即使對於每個小檔案也需要一個task去單獨處理,task作為一個獨立的jvm例項,其開啟和停止的開銷可能會大大超過實際的任務處理時間。
同時我們知道hive輸出最終是mr的輸出,即reducer(或mapper)的輸出,有多少個reducer(mapper)輸出就會生成多少個輸出檔案,根據shuffle/sort的原理,每個檔案按照某個值進行shuffle後的結果。
為了防止生成過多小檔案,hive可以通過配置引數在mr過程中合併小檔案。而且在執行sql之前將小檔案都進行Merge,也會提高程式的效能。我們可以從兩個方面進行優化,其一是map執行之前將小檔案進行合併會提高效能,其二是輸出的時候進行合併壓縮,減少IO壓力。
一、hive引數優化
Map操作之前合併小檔案:
#每個Map最大輸入大小設定為2GB(單位:位元組)
set mapred.max.split.size=2147483648
set hive.hadoop.supports.splittable.combineinputformat=true;
#執行Map前進行小檔案合併
set hive.input.format=org.apache.hadoop.hive.ql.io.CombineHiveInputFormat
輸出時進行合併:
#在Map-only的任務結束時合併小檔案。是否和並 Map輸出檔案,預設為 True, set hive.merge.mapfiles = true #在Map-Reduce的任務結束時合併小檔案 set hive.merge.mapredfiles= true #合併後MR輸出檔案的大小為1GB set hive.merge.size.per.task = 1073741824 #當輸出檔案的平均大小小於1GB時,啟動一個獨立的map-reduce任務進行檔案merge set hive.merge.smallfiles.avgsize=1073741824
二、檔案壓縮
set hive.exec.compress.output=true;
#預設false,是否對輸出結果壓縮
set mapred.output.compression.codec=org.apache.hadoop.io.compress.GzipCodec;
#具體的壓縮演算法的配置引數,要使用的壓縮編碼/解碼器的類名。
set mapred.output.compression.type=BLOCK;
sequencefile有三種壓縮方式:NONE, RECORD, BLOCK。預設是啟用RECORD級(壓縮單獨的記錄)的壓縮的,這種方式的壓縮率是非常低的。BLOCK(壓縮一組記錄)壓縮率最高,一般用BLOCK。
set mapred.output.compression.codec=org.apache.hadoop.io.compress.SnappyCodec;
SnappyCodec比較適合在這種場景中編解碼器,該演算法會帶來很好的壓縮效能和較低的CPU開銷
1、Hive中間資料壓縮Lzo,最終資料壓縮Gzip
set mapred.compress.map.output = true;
set mapred.map.output.compression.codec = org.apache.hadoop.io.compress.LzoCodec;
set mapred.output.compress = true;
set mapred.output.compression.codec = org.apache.hadoop.io.compress.GzipCodec;
set mapred.output.compression.type = BLOCK;
set hive.exec.compress.intermediate = true; #啟用中間資料壓縮
set hive.intermediate.compression.codec = org.apache.hadoop.io.compress.LzoCodec;
set hive.exec.compress.output = true;
三、檔案儲存
hive在建立表時預設儲存格式是textfile,或者顯示自定義的stored as textfile.hive常用的儲存格式有三種,textfile,sequencefile,rcfile。
為什麼hive會有多種儲存格式?因為hive是文字批處理系統,所以就存在一個往hive中匯入資料的問題,首先資料的儲存格式有多種,比如資料來源是二進位制格式, 普通文字格式等等,而hive強大之處不要求資料轉換成特定的格式,而是利用hadoop本身InputFormat API來從不同的資料來源讀取資料,同樣地使用OutputFormat API將資料寫成不同的格式。所以對於不同的資料來源,或者寫出不同的格式就需要不同的對應的InputFormat和Outputformat類的實現。
以stored as textfile(其實這就是下面stored as inputformat -outputformat的縮減寫法)為例,其在底層java API中表現是輸入InputFormat格式:TextInputFormat以及輸出OutputFormat格式:HiveIgnoreKeyTextOutputFormat.這裡InputFormat中定義瞭如何對資料來源文字進行讀取劃分,以及如何將切片分割成記錄存入表中。而Outputformat定義瞭如何將這些切片寫回到檔案裡或者直接在控制檯輸出。
STORED AS INPUTFORMAT
'org.apache.hadoop.mapred.TextInputFormat'
OUTPUTFORMAT
'org.apache.hadoop.hive.ql.io.HiveIgnoreKeyTextOutputFormat'
實際上hive使用一個TextInputFormat物件將輸入流分割成記錄,然後使用一個HiveIgnoreKeyTextOutputFormat物件來將記錄格式化為輸出流(比如查詢的結果),再使用Serde在讀資料時將記錄解析成列。在寫資料時將列編碼成記錄。所以stored as ''只是決定了行級別(記錄級別 )的儲存格式,而實際將記錄解析成列依靠的則是Serde物件,比如hive預設的ROW FORMAT SERDE 'org.apache.hadoop.hive.serde2.lazy.LazySimpleSerDe' 。或者使用者自定義的Serde格式。
textfile,sequencefile和rcfile的三種儲存格式的本質和區別
檔案儲存編碼格式 | 建表時如何指定 | 優點弊端 | |
textfile |
檔案儲存就是正常的文字格式,將表中的資料在hdfs上 以文字的格式儲存 ,下載後可以直接檢視,也可以使用cat命令檢視 |
1.無需指定,預設就是 2.顯示指定stored as textfile 3.顯示指定 STORED AS INPUTFORMAT 'org.apache.hadoop.mapred.TextInputFormat' OUTPUTFORMAT 'org.apache.hadoop.hive.ql.io.HiveIgnoreKeyTextOutputFormat' |
1.行儲存使用textfile儲存檔案預設每一行就是一條記錄, 2.可以使用任意的分隔符進行分割。 3.但無壓縮,所以造成儲存空間大。可結合Gzip、Bzip2、Snappy等使用(系統自動檢查,執行查詢時自動解壓),但使用這種方式,hive不會對資料進行切分,從而無法對資料進行並行操作。 4、 textfile為預設格式,儲存方式為行儲存 |
sequencefile |
在hdfs上將表中的資料以二進位制格式編碼,並且將資料壓縮了,下載資料 以後是二進位制格式,不可以直接檢視,無法視覺化。 |
1.stored as sequecefile 2.或者顯示指定: STORED AS INPUTFORMAT 'org.apache.hadoop.mapred.SequenceFileInputFormat' OUTPUTFORMAT 'org.apache.hadoop.hive.ql.io.HiveSequenceFileOutputFormat' |
1.sequencefile儲存格有壓縮,儲存空間小,有利於優化磁碟和I/O效能 2.同時支援檔案切割分片,提供了三種壓縮方式:none,record,block(塊級別壓縮效率跟高).預設是record(記錄) 3.基於行儲存 |
rcfile | 在hdfs上將表中的資料以二進位制格式編碼,並且支援壓縮。下載後的資料不可以直接視覺化。 |
1.stored as rcfile 2.或者顯示指定: STORED AS INPUTFORMAT 'org.apache.hadoop.hive.ql.io.RCFileInputFormat' OUTPUTFORMAT 'org.apache.hadoop.hive.ql.io.RCFileOutputFormat' |
1.行列混合的儲存格式,基於列儲存。 2.因為基於列儲存,列值重複多,所以壓縮效率高。 3.磁碟儲存空間小,io小。 4.hive/spark都支援這種儲存格式,它儲存的方式是採用資料按照行分塊,每個塊按照列儲存,其中每個塊都儲存有一個索引。特點是資料壓縮率非常高。 |
建立時可以直接指定儲存格式
create table parquet(
...
)
row format delimited fields terminated by '\t'
stored as parquet;
hive中不同儲存格式轉換,需要使用insert ....select
磁碟空間佔用大小比較(較大資料量)
orc<parquet<textfile
四、行列分隔符
CREATE TABLE `dwa_mytable`(
`msisdn` string COMMENT '手機號碼',
`location` string COMMENT '位置'
)
PARTITIONED BY (
`month_id` string,
`day_id` string,
`prov_id` string)
ROW FORMAT SERDE
'org.apache.hadoop.hive.serde2.lazy.LazySimpleSerDe'
WITH SERDEPROPERTIES (
'field.delim'='|',
'serialization.format'='|')
STORED AS INPUTFORMAT
'org.apache.hadoop.mapred.TextInputFormat'
OUTPUTFORMAT
'org.apache.hadoop.hive.ql.io.HiveIgnoreKeyTextOutputFormat'
LOCATION
'hdfs://beh/user/hadoopvip/lf_xx_dwa.db/dwa_mytable'
TBLPROPERTIES (
'last_modified_by'='hadoopvip',
'last_modified_time'='1524300660',
'transient_lastDdlTime'='1524300600')
Time taken: 0.062 seconds, Fetched: 49 row(s)
hive預設的列分割型別為org.apache.hadoop.hive.serde2.lazy.LazySimpleSerDe,而這其實就是^A分隔符,hive中預設使用^A(ctrl+A)作為列分割符,如果使用者需要指定的話,等同於row format delimited fields terminated by '\001',因為^A八進位制編碼體現為'\001'.所以如果使用預設的分隔符,可以什麼都不加,也可以按照上面的指定加‘\001’為列分隔符,效果一樣。
hive預設使用的行分隔符是'\n'分隔符 ,也可以加一句:LINES TERMINATED BY '\n' ,加不加效果一樣。但是區別是hive可以通過row format delimited fields terminated by '\t'這個語句來指定不同的分隔符,但是hive不能夠通過LINES TERMINATED BY '$$'來指定行分隔符,目前為止,hive的預設行分隔符僅支援‘\n’字元。否則報錯。
hive ()> create table fdm_sor.mytest_tm4(
> id int comment'編號',
> name string comment '名字'
> )
> lines terminated by '\t';
FAILED: ParseException line 5:1 missing EOF at 'lines' near ')'
但,可以通過自定義Inputformat和outputformat類來指定特定行分隔符和列分隔符。