溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

hive的數(shù)據(jù)傾斜以及常用的優(yōu)化方法

發(fā)布時間:2021-09-14 03:33:52 來源:億速云 閱讀:143 作者:chen 欄目:大數(shù)據(jù)

這篇文章主要介紹“hive的數(shù)據(jù)傾斜以及常用的優(yōu)化方法”,在日常操作中,相信很多人在hive的數(shù)據(jù)傾斜以及常用的優(yōu)化方法問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”hive的數(shù)據(jù)傾斜以及常用的優(yōu)化方法”的疑惑有所幫助!接下來,請跟著小編一起來學(xué)習(xí)吧!

1. hive的數(shù)據(jù)傾斜

 介紹:只要在分布式一定有shuffle,避免不了出現(xiàn)數(shù)據(jù)傾斜,在混淆數(shù)據(jù)的過程中出現(xiàn)數(shù)據(jù)分布不均勻。比如:在MR編程中reducetask階中的數(shù)據(jù)的大小不一致,即很多的數(shù)據(jù)集中到了一個reducetask中,hive的數(shù)據(jù)傾斜就是mapreduce的數(shù)據(jù)傾斜  maptask  reducetask最后就是reducetask階段的數(shù)據(jù)傾斜。
  不會產(chǎn)生數(shù)據(jù)傾斜的場景
   - 不執(zhí)行MapReduce程序,在hive中hive.fetch.task.conversion一共有三個可選值:
    - none:表示所有的語句都執(zhí)行MR,這個參數(shù)不可用
    - minimal :表示select *、where 字段為分區(qū)字段、limit時不執(zhí)行MR
    - more :select 、filter /where 、limit不執(zhí)行MR
   - 聚合函數(shù)和group by一起使用的時候,在聚合函數(shù)和group by一起使用的時候,默認(rèn)的MR底層在map端執(zhí)行combiner,所以不會數(shù)據(jù)傾斜
  會產(chǎn)生數(shù)據(jù)傾斜的場景
   - 聚合函數(shù)不和group by連用
   - count(distinct)
   -  join  主要是reduce join會產(chǎn)生數(shù)據(jù)傾斜

具體場景分析:

1)join時null值過多

 以log日志為例,其中有一個字段為userid,但是userid的null值太多,在使用userid進(jìn)行join時,所有的userid=null的數(shù)據(jù)都會到一個reduce中,這個reducetask數(shù)據(jù)量很大,就會產(chǎn)生數(shù)據(jù)傾斜。
  解決方法1

#null值不參與連接
select field1,field2,field3…
from log a left join user b on a.userid is not null and a.userid=b.
userid
union select field1,field2,field3 from log where userid is null;

  解決方法2
#將null值進(jìn)行散列

select 
    * 
    from log a left join user b on 
    case when a.userid is null then concat("null",rand()) 
    else a.userid end=b.userid;
2)連接的時候兩個表連接的列的類型不統(tǒng)一

user userid string  表一
log userid int       表二
select * from log a left join user b on a.userid=b.userid;
默認(rèn)情況下,將string轉(zhuǎn)化為int類型,如果string類型的userid中是無法轉(zhuǎn)化為int類型,那么返回了大量的null,然后大量的null, 又會分配到同一個reducetask中,造成數(shù)據(jù)傾斜。只要確定能將string轉(zhuǎn)化為int類型,就可以避免數(shù)據(jù)傾斜。

3)join端產(chǎn)生數(shù)據(jù)傾斜

大小表連接:大表和小表進(jìn)行關(guān)聯(lián)的時候,使用map端的join,在map  join 時是沒有數(shù)據(jù)傾斜的。其中有兩個參數(shù):
   - hive.auto.convert.join   #開啟map join,默認(rèn)是開啟的
   - hive.smalltable.filesize #在進(jìn)行mapjoin時對小表大小的限制,默認(rèn)是25000000byte,大概25M
大小表連接,但是小表數(shù)據(jù)量較大
  這個小表不是很大,但是超過了25000000byte;此時默認(rèn)執(zhí)行reducejoin,此時如果執(zhí)行了reduce join就容易產(chǎn)生數(shù)據(jù)傾斜,如果這時小表的大小不是很大不超過100M,那么可以強(qiáng)制執(zhí)行map join:

#強(qiáng)制執(zhí)行map join
select
/*+mapjoin(表名)*/       #將小表強(qiáng)制放入內(nèi)存
* from t1 join t2 on t1.field1=t2.field;

大表*大表:對其中的一個表進(jìn)行過濾,將這個表轉(zhuǎn)化成相對小的表,然后強(qiáng)制執(zhí)行map端join
這里以兩個表為例:
user ----30G(所有用戶)
Log ----5G  (當(dāng)日記錄的日志)

#先對log日志表進(jìn)行userid  過濾:
create table temp_log as 
                    select distinct userid  from log;
#將上面的結(jié)果和user表進(jìn)行關(guān)聯(lián):(獲取userid表中有效的關(guān)聯(lián)數(shù)據(jù))
create table temp_user as   
select filed1, filed2,field3
                        /*+mapjoin(a)*/
                        from temp a join user b on a.userid =b.userid;
#最后,在將上面的表與log進(jìn)行關(guān)聯(lián):
select filed1, filed2,field3
                        /*+mapjoin(a)*/
                    from temp_user a join Log b on a. userid =b. userid;

2. hive的優(yōu)化

(1)常用優(yōu)化手段:

   - 好的設(shè)計模型,在設(shè)計表的時候注意數(shù)據(jù)傾斜
   - 解決數(shù)據(jù)傾斜問題
   - 減少job數(shù)量
   - 設(shè)置合理的reduce task個數(shù)
   - 了解數(shù)據(jù)的分布情況,手動解決數(shù)據(jù)傾斜
   - 在數(shù)據(jù)量比較大的時候,盡量少用全局聚合類的操作
   - 對小文件進(jìn)行合并,減少maptask個數(shù),提高性能

(1)具體的優(yōu)化方案:

   ① 如何正確的選擇排序:
    - cluster by:對同一字段分桶并排序,不能和 sort by 連用
    - distribute by + sort by:分桶,保證同一字段值只存在一個結(jié)果文件當(dāng)中,結(jié)合 sort by 保證 每個 reduceTask 結(jié)果有序
    - sort by:單機(jī)排序,單個 reduce 結(jié)果有序
    - order by:全局排序,缺陷是只能使用一個 reduce task
   ② 怎樣做笛卡爾積:當(dāng) Hive 設(shè)定為嚴(yán)格模式(hive.mapred.mode=strict)時,不允許在 HQL 語句中出現(xiàn)笛卡爾積
解決笛卡爾積問題:https://blog.51cto.com/14048416/2338651
文章中的:6)使用隨機(jī)前綴和擴(kuò)容RDD進(jìn)行join,有細(xì)致講解。
   ③ 怎樣寫好 in/exists:

#使用left semi join.去代替in/exists:
select a.id, a.name from a where a.id in (select b.id from b);
#變化為:
selecet a.id,a.name from a left semi join b on a.id=b.id;

hive的數(shù)據(jù)傾斜以及常用的優(yōu)化方法
博文:https://blog.51cto.com/14048416/2342407  其中的關(guān)于left semi join 的總結(jié)。
   ④ 合理處理maptask個數(shù):
    Maptask個數(shù)太大:每個Maptask都要啟動一個jvm進(jìn)程,啟動時間過長,效率低,Maptask個數(shù)太?。贺?fù)載不均衡,大量作業(yè)時,容易阻塞集群。因此通常有兩種手段來解決問題:
   -     減少M(fèi)aptask個數(shù),通過合并小文件實(shí)現(xiàn),主要針對數(shù)據(jù)源
   -     通過設(shè)置重用jvm進(jìn)程的方式,減少M(fèi)apReduce程序在啟動和關(guān)閉jvm進(jìn)程的時間:(set mapred.job.reuse.jvm.num.tasks=5) 表示map task 重用同一個jvm.
   ⑤ 合理設(shè)置reduce task個數(shù):
     reducer 個數(shù)的設(shè)定極大影響執(zhí)行效率,這使得 Hive 怎樣決定 reducer 個數(shù)成為一個關(guān)鍵問題,默認(rèn)的在hive中只啟動一個reducetask。其中有以下幾個參數(shù)作為調(diào)優(yōu)點(diǎn):
   -     hive.exec.reducers.bytes.per.reducer  #reduceTask的吞吐量
   -     hive.exec.reducers.max  #啟動的reducetask的最大值 經(jīng)驗(yàn)之談:0.95*(集群中 datanode 個數(shù))
   -     mapreduce.job.reduces=  #設(shè)置reducetask的個數(shù)
   ⑥ 小文件合并:
     小文件過多,會給hdfs帶來壓力,并且會影響處理效率,可以通過合并 Map 和 Reduce 的 結(jié)果文件來消除這樣的影響,以下幾個參數(shù)可以作為調(diào)優(yōu)點(diǎn):
   -     set hive.merge.mapfiles = true  在只有maptask時,任務(wù)結(jié)束時進(jìn)行文件合并
   -     set hive.merge.mapredfiles = false  # true 時在 MapReduce 的任務(wù)結(jié)束時合并小文件
   -     set hive.merge.size.per.task = 25610001000  #合并的小文件的大小
   -     set mapred.max.split.size=256000000;  #每個map最大分割數(shù)
   -     set mapred.min.split.size.per.node=1;  #一個節(jié)點(diǎn)上的最小split值
   -     set hive.input.format=org.apache.hadoop.hive.ql.io.CombineHiveInputFormat;,#執(zhí)行map前進(jìn)行小文件合并(默認(rèn)開啟)
   ⑦ 合理的設(shè)置分區(qū):
   Partition 就是分區(qū)。分區(qū)通過在創(chuàng)建表時啟用 partitioned by 實(shí)現(xiàn),為了減少查詢時候的數(shù)據(jù)掃描范圍  提升查詢性能,當(dāng)數(shù)據(jù)兩個比較大的時候,對經(jīng)常按照某一個字段進(jìn)行過濾查詢的時候,就需要按照過濾字段創(chuàng)建分區(qū)表。
   ⑧ 合理的利用存儲格式:
   創(chuàng)建表時,盡量使用 orc、parquet 這些列式存儲格式,因?yàn)榱惺酱鎯Φ谋?,每一列的?shù)據(jù)在物理上是存儲在一起的,Hive 查詢時會只遍歷需要列數(shù)據(jù),大大減少處理的數(shù)據(jù)量。
   ⑨ 并行化處理
   一個hive sql語句可能轉(zhuǎn)化為多個mapreduce Job,每一個job就是一個stage,這些job順序執(zhí)行,在這個client的運(yùn)行日志也可以看到。但是有的時候這些任務(wù)之間并不是相互依賴的,如果集群資源允許,可以讓多個并不相互依賴的stage并發(fā)執(zhí)行。以下有兩個參數(shù)可以調(diào)優(yōu):
    - set hive.exec.parallel=true;  #開啟并行
    - set hive.exec.parallel.thread.number=8; //同一個 sql 允許并行任務(wù)的最大線程數(shù)
   ⑩ 設(shè)置壓縮存儲
    Hive最終是因?yàn)檗D(zhuǎn)為MapReduce程序來執(zhí)行,而MapReduce的性能瓶頸在與網(wǎng)絡(luò)和IO,要解決性能瓶頸,最主要的就是減少數(shù)據(jù)量,對數(shù)據(jù)進(jìn)行壓縮是一個很好的辦法。
hive的數(shù)據(jù)傾斜以及常用的優(yōu)化方法

Job輸出文件按照block以gzip的方式進(jìn)行壓縮:
set mapreduce.output.fileoutputformat.compress=true // 默認(rèn)值是 false 
set mapreduce.output.fileoutputformat.compress.type=BLOCK // 默認(rèn)值是 Record 
set mapreduce.output.fileoutputformat.compress.codec=org.apache.hadoop.io.compress.GzipCodec // 默認(rèn)值是 org.apache.hadoop.io.compress.DefaultCodec

map輸出結(jié)果以gzip進(jìn)行壓縮:
set mapred.map.output.compress=true 
set mapreduce.map.output.compress.codec=org.apache.hadoop.io.compress.GzipCodec // 默認(rèn)值是 org.apache.hadoop.io.compress.DefaultCodec

對hive輸出結(jié)果和中間都進(jìn)行壓縮:
set hive.exec.compress.output=true // 默認(rèn)值是 false,不壓縮 
set hive.exec.compress.intermediate=true // 默認(rèn)值是 false,為 true 時 MR 設(shè)置的壓縮才啟用

到此,關(guān)于“hive的數(shù)據(jù)傾斜以及常用的優(yōu)化方法”的學(xué)習(xí)就結(jié)束了,希望能夠解決大家的疑惑。理論與實(shí)踐的搭配能更好的幫助大家學(xué)習(xí),快去試試吧!若想繼續(xù)學(xué)習(xí)更多相關(guān)知識,請繼續(xù)關(guān)注億速云網(wǎng)站,小編會繼續(xù)努力為大家?guī)砀鄬?shí)用的文章!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI