hadoop mr + hive數據傾斜解決

數據傾斜是進行大數據計算時常見的問題。主要分爲map端傾斜和reduce端傾斜,map端傾斜主要是因爲輸入文件大小不均勻導致,reduce端主要是partition不均勻導致。

在hive中遇到數據傾斜的解決辦法:

一、傾斜原因:map端緩慢,輸入數據文件多,大小不均勻

當出現小文件過多,需要合併小文件。可以通過set hive.merge.mapfiles=true來解決。

set hive.map.aggr=true; //map端部分聚合,相當於Combiner,可以減小壓力(默認開啓)

set hive.groupby.skewindata=true(默認關閉);//有數據傾斜的時候進行負載均衡,當選項設定爲 true,生成的查詢計劃會有兩個 MR Job。第一個 MR Job 中,Map 的輸出結果集合會隨機分佈到 Reduce 中,每個 Reduce 做部分聚合操作,並輸出結果,這樣處理的結果是相同的 Group By Key 有可能被分發到不同的 Reduce 中,從而達到負載均衡的目的;第二個 MR Job 再根據預處理的數據結果按照 Group By Key 分佈到 Reduce 中(這個過程可以保證相同的 Group By Key 被分佈到同一個 Reduce 中),最後完成最終的聚合操作。

單個文件大小稍稍大於配置的block塊的大寫,此時需要適當增加map的個數。解決方法:set mapred.map.tasks個數

文件大小適中,但map端計算量非常大,如select id,count(*),sum(case when...),sum(case when...)...需要增加map個數。解決方法:set mapred.map.tasks個數,set mapred.reduce.tasks個數

二、當遇到一個大表和一個小表進行join操作時

解決方法:小表在join左側,大表在右側,或使用mapjoin 將小表加載到內存中。然後再對比較大的表進行map操作。

join就發生在map操作的時候,這裏的join並不會涉及reduce操作。map端join的優勢就是在於沒有shuffle,

如:select /*+ MAPJOIN(a) */ 

a.c1, b.c1 ,b.c2 from a join b 

where a.c1 = b.c1; 

三、遇到需要進行join的但是關聯字段有數據爲null,如表一的id需要和表二的id進行關聯,null值的reduce就會落到一個節點上

解決方法1:子查詢中過濾掉null值,id爲空的不參與關聯

解決方法2:用case when給空值分配隨機的key值(字符串+rand())

四、不同數據類型關聯產生數據傾斜

場景:一張表s8的日誌,每個商品一條記錄,要和商品表關聯。但關聯卻碰到傾斜的問題。s8的日誌中有字符串商品id,也有數字的商品id,類型是string的,但商品中的數字id是bigint的。猜測問題的原因是把s8的商品id轉成數字id做hash來分配reduce,所以字符串id的s8日誌,都到一個reduce上了,解決的方法驗證了這個猜測。

解決方法:把數字類型轉換成字符串類型

Select * from s8_log a

Left outer join r_auction_auctions b

On a.auction_id = cast(b.auction_id as string);

五、當HiveQL中包含count(distinct)時

如果數據量非常大,執行如select a,count(distinct b) from t group by a;類型的SQL時,會出現數據傾斜的問題。

解決方法:使用sum...group by代替。如select a,sum(1) from (select a, b from t group by a,b) group by a;

六、join和Group的優化 
2.1 對於普通的join操作,會在map端根據key的hash值,shuffle到某一個reduce上去,在reduce端做join連接操作,內存中緩存join左邊的表,遍歷右邊的表,一次做join操作。所以在做join操作時候,將數據量多的表放在join的右邊。 
當數據量比較大,並且key分佈不均勻,大量的key都shuffle到一個reduce上了,就出現了數據的傾斜。 

在map端產生join

         mapJoin的主要意思就是,當鏈接的兩個表是一個比較小的表和一個特別大的表的時候,我們把比較小的table直接放到內存中去,然後再對比較大的表格進行map操作。join就發生在map操作的時候,每當掃描一個大的table中的數據,就要去去查看小表的數據,哪條與之相符,繼而進行連接。這裏的join並不會涉及reduce操作。map端join的優勢就是在於沒有shuffle,


2.2 對於Group操作,首先在map端聚合,最後在reduce端坐聚合,hive默認是這樣的,以下是相關的參數 
· hive.map.aggr = true是否在 Map 端進行聚合,默認爲 True 
· hive.groupby.mapaggr.checkinterval = 100000在 Map 端進行聚合操作的條目數目

 

自己總結:

1 map join 開啓配置參數

set hive.auto.convert.join = true  設置自動選擇mapjoin

set hive.mapjoin.smalltable.filesize = 25000000  大表小標的閾值設置,默認是25m

2 map 預聚合 ( count group by經常用到) 

set hive.map.aggr = true;  設置默認在map端進行聚合;

hive.groupby.mapaggr.checkinterval = 100000; 在map端進行聚合操作的條目數目;

hive.groupby.skewindata = true; 有數據傾斜時在map端進行負載均衡,默認false, 本質是提交了兩個job, 第一個job的mr進行負載均衡預處理;

 

hadoop mr過程優化

1 數據輸入

1) 合併小文件:在執行mr任務之前將小文件進行合併,大量的小文件會產生大量的map任務,增到map任務裝載次數,任務裝載比較耗時。

2) 採用CombineTextInputFormat來作爲輸入,解決輸入端大量小文件的場景。

2 map階段

1)減少溢寫spill次數:通過調整環形緩衝區io.sort.mb和sort.spill.percent參數值,增大觸發spill內存上限,減少spill次數,從而減少磁盤io。

2)減少合併merge次數:通過調整io.sort.factor參數,增大merge文件數目,減少merge次數,從而縮短mr時間。

3)能應用combine的儘量應用,減少io。應用場景是聚合sum等計算,但如果是求平均值等就不合適了。

3 reduce階段

1)合理設置map reduce數量: 兩個不能太少也不能太多。太少會導致task等待,延長處理時間;太多,會導致map reduce間競爭資源,造成處理超時等錯誤。

2)設置map reduce共存:調整slowstart.completedmaps參數,使map運行到一定程度之後,reduce也開始運行,減少reduce等待時間。

3)規避使用reduce:因爲reduce在用於連接數據集時會產生大量的網絡消耗。

4)合理設置reduce端的buffer:默認情況下,當數據大於一定閾值的時候,buffer中的數據會寫入磁盤,然後reduce會從磁盤中讀取數據,有大量的磁盤IO。既然有這個弊端,可以參數設置,使得buffer中的數據直接輸送到reduce, 從而減少IO開銷。設置mapred.job.reduce.input.buffer.percent,默認爲0.0。當值大於0的時候,會保留制定比例的內存讀取buffer數據直接拿給reduce使用。這樣一來,設置buffer、讀取數據、reduce計算都需要內存,所以需要根據作業運行情況進行設置。

4 IO傳輸

1)採用數據壓縮方式,減少io時間:snappy/lzo壓縮編碼器。

2)使用sequenceFile二進制文件。

5 數據傾斜問題

1)抽樣和範圍分區:

通過對原始數據進行抽樣得到的結果集來預設分區邊界值。

2)自定義分區:根據具體業務中鍵值的業務背景來自定義分區。

3)Combine:相當於在map端進行reduce,預聚合,儘量減少輸出,應用場景是聚合sum等計算,但如果是求平均值等就不合適了。

4)採用map join,避免採用reduce join。

6 常用參數調優

hadoop 小文件優化

1)hadoop Archive

一種文件存檔工具,對內依然是多個文件,對外namenode而言只佔用一個文件的150byte存儲,減少了namenode內存使用。

2) sequence file

由一系列二進制key/value組成,如果key爲文件名,value爲文件內容,可以將大批小文件合併成一個大文件。

3)CombineFileInputFormat

是一種新的InputFormat,用於將多個文件合併成一個單獨的file split, 另外會考慮數據的存儲位置。

4) 開啓jvm重用

對於大量的小文件job, 開啓重用可以減少45%時間。

一個map task運行在一個jvm上,開啓重用的話,該map在jvm上運行完畢之後,jvm會繼續運行其他map task。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

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