1. 程式人生 > >hive 引數優化記錄

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類來指定特定行分隔符和列分隔符。