日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

hive大数据倾斜总结

發(fā)布時(shí)間:2024/1/17 编程问答 24 豆豆
生活随笔 收集整理的這篇文章主要介紹了 hive大数据倾斜总结 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

在做Shuffle階段的優(yōu)化過程中,遇到了數(shù)據(jù)傾斜的問題,造成了對一些情況下優(yōu)化效果不明顯。主要是因?yàn)樵贘ob完成后的所得到的Counters是整個(gè)Job的總和,優(yōu)化是基于這些Counters得出的平均值,而由于數(shù)據(jù)傾斜的原因造成map處理數(shù)據(jù)量的差異過大,使得這些平均值能代表的價(jià)值降低。Hive的執(zhí)行是分階段的,map處理數(shù)據(jù)量的差異取決于上一個(gè)stage的reduce輸出,所以如何將數(shù)據(jù)均勻的分配到各個(gè)reduce中,就是解決數(shù)據(jù)傾斜的根本所在。規(guī)避錯(cuò)誤來更好的運(yùn)行比解決錯(cuò)誤更高效。在查看了一些資料后,總結(jié)如下。

1數(shù)據(jù)傾斜的原因

1.1操作:

關(guān)鍵詞

情形

后果

Join

其中一個(gè)表較小,

但是key集中

分發(fā)到某一個(gè)或幾個(gè)Reduce上的數(shù)據(jù)遠(yuǎn)高于平均值

大表與大表,但是分桶的判斷字段0值或空值過多

這些空值都由一個(gè)reduce處理,灰常慢

group by

group by 維度過小,

某值的數(shù)量過多

處理某值的reduce灰常耗時(shí)

Count Distinct

某特殊值過多

處理此特殊值的reduce耗時(shí)

1.2原因:

1)、key分布不均勻

2)、業(yè)務(wù)數(shù)據(jù)本身的特性

3)、建表時(shí)考慮不周

4)、某些SQL語句本身就有數(shù)據(jù)傾斜

?

1.3表現(xiàn):

任務(wù)進(jìn)度長時(shí)間維持在99%(或100%),查看任務(wù)監(jiān)控頁面,發(fā)現(xiàn)只有少量(1個(gè)或幾個(gè))reduce子任務(wù)未完成。因?yàn)槠涮幚淼臄?shù)據(jù)量和其他reduce差異過大。

單一reduce的記錄數(shù)與平均記錄數(shù)差異過大,通常可能達(dá)到3倍甚至更多。 最長時(shí)長遠(yuǎn)大于平均時(shí)長。

?

2數(shù)據(jù)傾斜的解決方案

2.1參數(shù)調(diào)節(jié):

hive.map.aggr=true

Map 端部分聚合,相當(dāng)于Combiner

hive.groupby.skewindata=true

有數(shù)據(jù)傾斜的時(shí)候進(jìn)行負(fù)載均衡,當(dāng)選項(xiàng)設(shè)定為 true,生成的查詢計(jì)劃會(huì)有兩個(gè) MR Job。第一個(gè) MR Job 中,Map 的輸出結(jié)果集合會(huì)隨機(jī)分布到 Reduce 中,每個(gè) Reduce 做部分聚合操作,并輸出結(jié)果,這樣處理的結(jié)果是相同的 Group By Key 有可能被分發(fā)到不同的 Reduce 中,從而達(dá)到負(fù)載均衡的目的;第二個(gè) MR Job 再根據(jù)預(yù)處理的數(shù)據(jù)結(jié)果按照 Group By Key 分布到 Reduce 中(這個(gè)過程可以保證相同的 Group By Key 被分布到同一個(gè) Reduce 中),最后完成最終的聚合操作。

?

2.2 SQL語句調(diào)節(jié):

如何Join:

關(guān)于驅(qū)動(dòng)表的選取,選用join key分布最均勻的表作為驅(qū)動(dòng)表

做好列裁剪和filter操作,以達(dá)到兩表做join的時(shí)候,數(shù)據(jù)量相對變小的效果。

大小表Join:

使用map join讓小的維度表(1000條以下的記錄條數(shù)) 先進(jìn)內(nèi)存。在map端完成reduce.

大表Join大表:

把空值的key變成一個(gè)字符串加上隨機(jī)數(shù),把傾斜的數(shù)據(jù)分到不同的reduce上,由于null值關(guān)聯(lián)不上,處理后并不影響最終結(jié)果。

count distinct大量相同特殊值

count distinct時(shí),將值為空的情況單獨(dú)處理,如果是計(jì)算count distinct,可以不用處理,直接過濾,在最后結(jié)果中加1。如果還有其他計(jì)算,需要進(jìn)行g(shù)roup by,可以先將值為空的記錄單獨(dú)處理,再和其他計(jì)算結(jié)果進(jìn)行union。

group by維度過小:

采用sum() group by的方式來替換count(distinct)完成計(jì)算。

特殊情況特殊處理:

在業(yè)務(wù)邏輯優(yōu)化效果的不大情況下,有些時(shí)候是可以將傾斜的數(shù)據(jù)單獨(dú)拿出來處理。最后union回去。

?

3典型的業(yè)務(wù)場景

3.1空值產(chǎn)生的數(shù)據(jù)傾斜

場景:如日志中,常會(huì)有信息丟失的問題,比如日志中的 user_id,如果取其中的 user_id 和 用戶表中的user_id 關(guān)聯(lián),會(huì)碰到數(shù)據(jù)傾斜的問題。

解決方法1:?user_id為空的不參與關(guān)聯(lián)(紅色字體為修改后)

?

?
  • select * from log a

  • join users b

  • on a.user_id is not null

  • and a.user_id = b.user_id

  • union all

  • select * from log a

  • where a.user_id is null;

  • ?

    解決方法2?:賦與空值分新的key值

    ?

    ?
  • select *

  • from log a

  • left outer join users b

  • on case when a.user_id is null then concat(‘hive’,rand() ) else a.user_id end = b.user_id;

  • ?

    結(jié)論:方法2比方法1效率更好,不但io少了,而且作業(yè)數(shù)也少了。解決方法1中 log讀取兩次,jobs是2。解決方法2 job數(shù)是1 。這個(gè)優(yōu)化適合無效 id (比如 -99 , ’’, null 等) 產(chǎn)生的傾斜問題。把空值的 key 變成一個(gè)字符串加上隨機(jī)數(shù),就能把傾斜的數(shù)據(jù)分到不同的reduce上 ,解決數(shù)據(jù)傾斜問題。

    ?

    3.2不同數(shù)據(jù)類型關(guān)聯(lián)產(chǎn)生數(shù)據(jù)傾斜

    場景:用戶表中user_id字段為int,log表中user_id字段既有string類型也有int類型。當(dāng)按照user_id進(jìn)行兩個(gè)表的Join操作時(shí),默認(rèn)的Hash操作會(huì)按int型的id來進(jìn)行分配,這樣會(huì)導(dǎo)致所有string類型id的記錄都分配到一個(gè)Reducer中。

    解決方法:把數(shù)字類型轉(zhuǎn)換成字符串類型

    ?

    ?
  • select * from users a

  • left outer join logs b

  • on a.usr_id = cast(b.user_id as string)

  • ?

    3.3小表不小不大,怎么用 map join 解決傾斜問題

    使用 map join 解決小表(記錄數(shù)少)關(guān)聯(lián)大表的數(shù)據(jù)傾斜問題,這個(gè)方法使用的頻率非常高,但如果小表很大,大到map join會(huì)出現(xiàn)bug或異常,這時(shí)就需要特別的處理。?以下例子:

    ?

    ?
  • select * from log a

  • left outer join users b

  • on a.user_id = b.user_id;

  • ?

    users 表有 600w+ 的記錄,把 users 分發(fā)到所有的 map 上也是個(gè)不小的開銷,而且 map join 不支持這么大的小表。如果用普通的 join,又會(huì)碰到數(shù)據(jù)傾斜的問題。

    解決方法:

    ?

    ?
  • select /*+mapjoin(x)*/* from log a

  • left outer join (

  • select /*+mapjoin(c)*/d.*

  • from ( select distinct user_id from log ) c

  • join users d

  • on c.user_id = d.user_id

  • ) x

  • on a.user_id = b.user_id;

  • ?

    假如,log里user_id有上百萬個(gè),這就又回到原來map join問題。所幸,每日的會(huì)員uv不會(huì)太多,有交易的會(huì)員不會(huì)太多,有點(diǎn)擊的會(huì)員不會(huì)太多,有傭金的會(huì)員不會(huì)太多等等。所以這個(gè)方法能解決很多場景下的數(shù)據(jù)傾斜問題。

    ?

    3.4大表join大表,業(yè)務(wù)場景如何優(yōu)化

    用戶軌跡工程的性能瓶頸一直是etract_track_info,其中耗時(shí)大戶主要在于trackinfo與pm_info進(jìn)行左關(guān)聯(lián)的環(huán)節(jié),trackinfo與pm_info兩張表均為GB級別,左關(guān)聯(lián)代碼塊如下:

    ?
  • from trackinfo a

  • left outer join pm_info b

  • on (a.ext_field7 = b.id)

  • 使用以上代碼塊需要耗時(shí)1.5小時(shí)。


    優(yōu)化流程
    第一次優(yōu)化

    考慮到pm_info表的id是bigint類型,trackinfo表的ext_field7是string類型,其關(guān)聯(lián)時(shí)數(shù)據(jù)類型不一致,默認(rèn)的hash操作會(huì)按bigint型的id進(jìn)行分配,這樣會(huì)導(dǎo)致所有string類型的ext_field7集中到一個(gè)reduce里面,因此,改為如下:

    ?
  • from trackinfo a

  • left outer join pm_info b

  • on (cast(a.ext_field7as bigint) = b.id)

  • 改動(dòng)為上面代碼后,效果仍然不理想,耗時(shí)為1.5小時(shí)。

    第二次優(yōu)化

    考慮到trackinfo表的ext_field7字段缺失率很高(為空、字段長度為零、字段填充了非整數(shù))情況,做進(jìn)行左關(guān)聯(lián)時(shí)空字段的關(guān)聯(lián)操作實(shí)際上沒有意義,因此,如果左表關(guān)聯(lián)字段ext_field7為無效字段,則不需要關(guān)聯(lián),因此,改為如下:

    ?
  • from trackinfo a

  • left outer join pm_info b

  • on (a.ext_field7 is not null

  • and length(a.ext_field7) > 0

  • and a.ext_field7 rlike'^[0-9]+$'

  • and a.ext_field7 = b.id)

  • 上面代碼塊的作用是,如果左表關(guān)聯(lián)字段ext_field7為無效字段時(shí)(為空、字段長度為零、字段填充了非整數(shù)),不去關(guān)聯(lián)右表,由于空字段左關(guān)聯(lián)以后取到的右表字段仍然為null,所以不會(huì)影響結(jié)果。
    改動(dòng)為上面代碼后,效果仍然不理想,耗時(shí)為50分鐘。
    第三次優(yōu)化
    想了很久,第二次優(yōu)化效果效果不理想的原因,其實(shí)是在左關(guān)聯(lián)中,雖然設(shè)置了左表關(guān)聯(lián)字段為空不去關(guān)聯(lián)右表,但是這樣做,左表中未關(guān)聯(lián)的記錄(ext_field7為空)將會(huì)全部聚集在一個(gè)reduce中進(jìn)行處理,體現(xiàn)為reduce進(jìn)度長時(shí)間處在99%。
    換一種思路,解決辦法的突破點(diǎn)就在于如何把左表的未關(guān)聯(lián)記錄的key盡可能打散,因此可以這么做:若左表關(guān)聯(lián)字段無效(為空、字段長度為零、字段填充了非整數(shù)),則在關(guān)聯(lián)前將左表關(guān)聯(lián)字段設(shè)置為一個(gè)隨機(jī)數(shù),再去關(guān)聯(lián)右表,這么做的目的是即使是左表的未關(guān)聯(lián)記錄,它的key也分布得十分均勻

    ?
  • from trackinfo a

  • left outer join pm_info b

  • on (

  • casewhen (a.ext_field7 is not null

  • andlength(a.ext_field7) > 0

  • anda.ext_field7 rlike '^[0-9]+$')

  • then

  • cast(a.ext_field7as bigint)

  • else

  • cast(ceiling(rand() * -65535)as bigint)

  • end= b.id

  • )

  • 第三次改動(dòng)后,耗時(shí)從50分鐘降為了1分鐘32秒,效果顯著!

    4總結(jié)

    使map的輸出數(shù)據(jù)更均勻的分布到reduce中去,是我們的最終目標(biāo)。由于Hash算法的局限性,按key Hash會(huì)或多或少的造成數(shù)據(jù)傾斜。大量經(jīng)驗(yàn)表明數(shù)據(jù)傾斜的原因是人為的建表疏忽或業(yè)務(wù)邏輯可以規(guī)避的。在此給出較為通用的步驟:

    1、采樣log表,哪些user_id比較傾斜,得到一個(gè)結(jié)果表tmp1。由于對計(jì)算框架來說,所有的數(shù)據(jù)過來,他都是不知道數(shù)據(jù)分布情況的,所以采樣是并不可少的。

    2、數(shù)據(jù)的分布符合社會(huì)學(xué)統(tǒng)計(jì)規(guī)則,貧富不均。傾斜的key不會(huì)太多,就像一個(gè)社會(huì)的富人不多,奇特的人不多一樣。所以tmp1記錄數(shù)會(huì)很少。把tmp1和users做map join生成tmp2,把tmp2讀到distribute file cache。這是一個(gè)map過程。

    3、map讀入users和log,假如記錄來自log,則檢查user_id是否在tmp2里,如果是,輸出到本地文件a,否則生成<user_id,value>的key,value對,假如記錄來自member,生成<user_id,value>的key,value對,進(jìn)入reduce階段。

    4、最終把a(bǔ)文件,把Stage3 reduce階段輸出的文件合并起寫到hdfs。

    ?

    如果確認(rèn)業(yè)務(wù)需要這樣傾斜的邏輯,考慮以下的優(yōu)化方案:

    1、對于join,在判斷小表不大于1G的情況下,使用map join

    2、對于group by或distinct,設(shè)定?hive.groupby.skewindata=true

    3、盡量使用上述的SQL語句調(diào)節(jié)進(jìn)行優(yōu)化

    總結(jié)

    以上是生活随笔為你收集整理的hive大数据倾斜总结的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。