<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          實(shí)操 | Hive 數(shù)據(jù)傾斜問(wèn)題定位排查及解決

          共 5945字,需瀏覽 12分鐘

           ·

          2021-08-11 15:17

          大家好,我是寶器!

          多數(shù)介紹數(shù)據(jù)傾斜的文章都是以大篇幅的理論為主,并沒(méi)有給出具體的數(shù)據(jù)傾斜案例。當(dāng)工作中遇到了傾斜問(wèn)題,這些理論很難直接應(yīng)用,導(dǎo)致我們面對(duì)傾斜時(shí)還是不知所措。

          今天我們不扯大篇理論,直接以例子來(lái)實(shí)踐,排查是否出現(xiàn)了數(shù)據(jù)傾斜,具體是哪段代碼導(dǎo)致的傾斜,怎么解決這段代碼的傾斜。

          當(dāng)執(zhí)行過(guò)程中任務(wù)卡在 99%,大概率是出現(xiàn)了數(shù)據(jù)傾斜,但是通常我們的 SQL 很大,需要判斷出是哪段代碼導(dǎo)致的傾斜,才能利于我們解決傾斜。通過(guò)下面這個(gè)非常簡(jiǎn)單的例子來(lái)看下如何定位產(chǎn)生數(shù)據(jù)傾斜的代碼。

          表結(jié)構(gòu)描述

          先來(lái)了解下這些表中我們需要用的字段及數(shù)據(jù)量:

          表的字段非常多,此處僅列出我們需要的字段

          第一張表:user_info (用戶信息表,用戶粒度)

          字段名字段含義字段描述
          userkey用戶 key用戶標(biāo)識(shí)
          idno用戶的身份證號(hào)用戶實(shí)名認(rèn)證時(shí)獲取
          phone用戶的手機(jī)號(hào)用戶注冊(cè)時(shí)的手機(jī)號(hào)
          name用戶的姓名用戶的姓名

          user_info 表的數(shù)據(jù)量:1.02 億,大?。?3.9G,所占空間:41.7G(HDFS三副本)

          第二張表:user_active (用戶活躍表,用戶粒度)

          字段名字段含義字段描述
          userkey用戶 key用戶沒(méi)有注冊(cè)會(huì)分配一個(gè) key
          user_active_at用戶的最后活躍日期從埋點(diǎn)日志表中獲取用戶的最后活躍日期

          user_active 表的數(shù)據(jù)量:1.1 億

          第三張表:user_intend(用戶意向表,此處只取近六個(gè)月的數(shù)據(jù),用戶粒度)

          字段名字段含義字段描述
          phone用戶的手機(jī)號(hào)有意向的用戶必須是手機(jī)號(hào)注冊(cè)的用戶
          intend_commodity用戶意向次數(shù)最多的商品客戶對(duì)某件商品意向次數(shù)最多
          intend_rank用戶意向等級(jí)用戶的購(gòu)買意愿等級(jí),級(jí)數(shù)越高,意向越大

          user_intend 表的數(shù)據(jù)量:800 萬(wàn)

          第四張表:user_order(用戶訂單表,此處只取近六個(gè)月的訂單數(shù)據(jù),用戶粒度)

          字段名字段含義字段描述
          idno用戶的身份證號(hào)下訂單的用戶都是實(shí)名認(rèn)證的
          order_num用戶的訂單次數(shù)用戶近六個(gè)月下單次數(shù)
          order_amount用戶的訂單總金額用戶近六個(gè)月下單總金額

          user_order 表的數(shù)據(jù)量:640 萬(wàn)

          1. 需求

          需求非常簡(jiǎn)單,就是將以上四張表關(guān)聯(lián)組成一張大寬表,大寬表中包含用戶的基本信息,活躍情況,購(gòu)買意向及此用戶下訂單情況。

          2. 代碼

          根據(jù)以上需求,我們以 user_info 表為基礎(chǔ)表,將其余表關(guān)聯(lián)為一個(gè)寬表,代碼如下:

          select
            a.userkey,
            a.idno,
            a.phone,
            a.name,
            b.user_active_at,
            c.intend_commodity,
            c.intend_rank,
            d.order_num,
            d.order_amount
          from user_info a
          left join user_active b on a.userkey = b.userkey
          left join user_intend c on a.phone = c.phone
          left join user_order d on a.idno = d.idno;

          執(zhí)行上述語(yǔ)句,在執(zhí)行到某個(gè) job 時(shí)任務(wù)卡在 99%:

          這時(shí)我們就應(yīng)該考慮出現(xiàn)數(shù)據(jù)傾斜了。其實(shí)還有一種情況可能是數(shù)據(jù)傾斜,就是任務(wù)超時(shí)被殺掉,Reduce 處理的數(shù)據(jù)量巨大,在做 full gc 的時(shí)候,stop the world。導(dǎo)致響應(yīng)超時(shí),超出默認(rèn)的 600 秒,任務(wù)被殺掉。報(bào)錯(cuò)信息一般如下:

          AttemptID:attempt_1624419433039_1569885_r_000000 Timed outafter 600 secs Container killed by the ApplicationMaster. Container killed onrequest. Exit code is 143 Container exited with a non-zero exit code 143

          3. 傾斜問(wèn)題排查

          數(shù)據(jù)傾斜大多數(shù)都是大 key 問(wèn)題導(dǎo)致的。

          如何判斷是大 key 導(dǎo)致的問(wèn)題,可以通過(guò)下面方法:

          1. 通過(guò)時(shí)間判斷

          如果某個(gè) reduce 的時(shí)間比其他 reduce 時(shí)間長(zhǎng)的多,如下圖,大部分 task 在 1 分鐘之內(nèi)完成,只有 r_000000 這個(gè) task 執(zhí)行 20 多分鐘了還沒(méi)完成。

          注意:要排除兩種情況:

          1. 如果每個(gè) reduce 執(zhí)行時(shí)間差不多,都特別長(zhǎng),不一定是數(shù)據(jù)傾斜導(dǎo)致的,可能是 reduce 設(shè)置過(guò)少導(dǎo)致的。

          2. 有時(shí)候,某個(gè) task 執(zhí)行的節(jié)點(diǎn)可能有問(wèn)題,導(dǎo)致任務(wù)跑的特別慢。這個(gè)時(shí)候,mapreduce 的推測(cè)執(zhí)行,會(huì)重啟一個(gè)任務(wù)。如果新的任務(wù)在很短時(shí)間內(nèi)能完成,通常則是由于 task 執(zhí)行節(jié)點(diǎn)問(wèn)題導(dǎo)致的個(gè)別 task 慢。但是如果推測(cè)執(zhí)行后的 task 執(zhí)行任務(wù)也特別慢,那更說(shuō)明該 task 可能會(huì)有傾斜問(wèn)題。

          2. 通過(guò)任務(wù) Counter 判斷

          Counter 會(huì)記錄整個(gè) job 以及每個(gè) task 的統(tǒng)計(jì)信息。counter 的 url 一般類似:

          http://bd001:8088/proxy/application_1624419433039_1569885/mapreduce/singletaskcounter/task_1624419433039_1569885_r_000000/org.apache.hadoop.mapreduce.FileSystemCounter

          通過(guò)輸入記錄數(shù),普通的 task counter 如下,輸入的記錄數(shù)是 13 億多:

          而 task=000000 的 counter 如下,其輸入記錄數(shù)是 230 多億。是其他任務(wù)的 100 多倍:

          4. 定位 SQL 代碼

          1. 確定任務(wù)卡住的 stage

          • 通過(guò) jobname 確定 stage:

            一般 Hive 默認(rèn)的 jobname 名稱會(huì)帶上 stage 階段,如下通過(guò) jobname 看到任務(wù)卡住的為 Stage-4:

          • 如果 jobname 是自定義的,那可能沒(méi)法通過(guò) jobname 判斷 stage。需要借助于任務(wù)日志:

            找到執(zhí)行特別慢的那個(gè) task,然后 Ctrl+F 搜索 “CommonJoinOperator: JOIN struct” 。Hive 在 join 的時(shí)候,會(huì)把 join 的 key 打印到日志中。如下:

          上圖中的關(guān)鍵信息是:struct<_col0:string, _col1:string, _col3:string>

          這時(shí)候,需要參考該 SQL 的執(zhí)行計(jì)劃。通過(guò)參考執(zhí)行計(jì)劃,可以斷定該階段為 Stage-4 階段:

          2. 確定 SQL 執(zhí)行代碼

          確定了執(zhí)行階段,即 stage。通過(guò)執(zhí)行計(jì)劃,則可以判斷出是執(zhí)行哪段代碼時(shí)出現(xiàn)了傾斜。還是從此圖,這個(gè) stage 中進(jìn)行連接操作的表別名是 d:

          就可以推測(cè)出是在執(zhí)行下面紅框中代碼時(shí)出現(xiàn)了數(shù)據(jù)傾斜,因?yàn)檫@行的表的別名是 d:

          5. 解決傾斜

          我們知道了哪段代碼引起的數(shù)據(jù)傾斜,就針對(duì)這段代碼查看傾斜原因,看下這段代碼的表中數(shù)據(jù)是否有異常。

          傾斜原因:

          本文的示例數(shù)據(jù)中 user_info 和 user_order 通過(guò)身份證號(hào)關(guān)聯(lián),檢查發(fā)現(xiàn) user_info 表中身份證號(hào)為空的有 7000 多萬(wàn),原因就是這 7000 多萬(wàn)數(shù)據(jù)都分配到一個(gè) reduce 去執(zhí)行,導(dǎo)致數(shù)據(jù)傾斜。

          解決方法

          1. 可以先把身份證號(hào)為空的去除之后再關(guān)聯(lián),最后按照 userkey 連接,因?yàn)?userkey 全部都是有值的:
          with t1 as(
          select
          u.userkey,
          o.*
          from user_info u
          left join user_order o
          on u.idno = o.idno
          where u.idno is not null
          --是可以把where條件寫在后面的,hive會(huì)進(jìn)行謂詞下推,先執(zhí)行where條件在執(zhí)行 left join
          )

          select
            a.userkey,
            a.idno,
            a.phone,
            a.name,
            b.user_active_at,
            c.intend_commodity,
            c.intend_rank,
            d.order_num,
            d.order_amount
          from user_info a
          left join user_active b on a.userkey = b.userkey
          left join user_intend c on a.phone = c.phone
          left join t1 d on a.userkey = d.userkey;
          1. 也可以這樣,給身份證為空的數(shù)據(jù)賦個(gè)隨機(jī)值,但是要注意隨機(jī)值不能和表中的身份證號(hào)有重復(fù):
          select
            a.userkey,
            a.idno,
            a.phone,
            a.name,
            b.user_active_at,
            c.intend_commodity,
            c.intend_rank,
            d.order_num,
            d.order_amount
          from user_info a
          left join user_active b on a.userkey = b.userkey
          left join user_intend c on a.phone = c.phone
          left join user_order d on nvl(a.idno,concat(rand(),'idnumber')) = d.idno;

          其他的解決數(shù)據(jù)傾斜的方法

          1. 過(guò)濾掉臟數(shù)據(jù)

          如果大 key 是無(wú)意義的臟數(shù)據(jù),直接過(guò)濾掉。本場(chǎng)景中大 key 有實(shí)際意義,不能直接過(guò)濾掉。

          2. 數(shù)據(jù)預(yù)處理

          數(shù)據(jù)做一下預(yù)處理(如上面例子,對(duì) null 值賦一個(gè)隨機(jī)值),盡量保證 join 的時(shí)候,同一個(gè) key 對(duì)應(yīng)的記錄不要有太多。

          3. 增加 reduce 個(gè)數(shù)

          如果數(shù)據(jù)中出現(xiàn)了多個(gè)大 key,增加 reduce 個(gè)數(shù),可以讓這些大 key 落到同一個(gè) reduce 的概率小很多。

          配置 reduce 個(gè)數(shù):

          set mapred.reduce.tasks = 15;

          4. 轉(zhuǎn)換為 mapjoin

          如果兩個(gè)表 join 的時(shí)候,一個(gè)表為小表,可以用 mapjoin 做。

          配置 mapjoin:

          set hive.auto.convert.join = true;  是否開(kāi)啟自動(dòng)mapjoin,默認(rèn)是true

          set hive.mapjoin.smalltable.filesize=100000000;   mapjoin的表size大小

          5. 啟用傾斜連接優(yōu)化

          hive 中可以設(shè)置 hive.optimize.skewjoin 將一個(gè) join sql 分為兩個(gè) job。同時(shí)可以設(shè)置下 hive.skewjoin.key,此參數(shù)表示 join 連接的 key 的行數(shù)超過(guò)指定的行數(shù),就認(rèn)為該鍵是偏斜連接鍵,就對(duì) join 啟用傾斜連接優(yōu)化。默認(rèn) key 的行數(shù)是 100000。

          配置傾斜連接優(yōu)化:

          set hive.optimize.skewjoin=true; 啟用傾斜連接優(yōu)化

          set hive.skewjoin.key=200000; 超過(guò)20萬(wàn)行就認(rèn)為該鍵是偏斜連接鍵

          6. 調(diào)整內(nèi)存設(shè)置

          適用于那些由于內(nèi)存超限任務(wù)被 kill 掉的場(chǎng)景。通過(guò)加大內(nèi)存起碼能讓任務(wù)跑起來(lái),不至于被殺掉。該參數(shù)不一定會(huì)明顯降低任務(wù)執(zhí)行時(shí)間。

          配置內(nèi)存:

          set mapreduce.reduce.memory.mb=5120; 設(shè)置reduce內(nèi)存大小

          set mapreduce.reduce.java.opts=-Xmx5000m -XX:MaxPermSize=128m;

          附:Hive 配置屬性官方鏈接:https://cwiki.apache.org/confluence/display/Hive/Configuration+Properties

          ·················END·················

          推薦閱讀

          1. 我在字節(jié)做了哪些事

          2. 寫給所有數(shù)據(jù)人。

          3. 從留存率業(yè)務(wù)案例談0-1的數(shù)據(jù)指標(biāo)體系

          4. 數(shù)據(jù)分析師的一周

          5. 超級(jí)菜鳥(niǎo)如何入門數(shù)據(jù)分析?


          歡迎長(zhǎng)按掃碼關(guān)注「數(shù)據(jù)管道」

          瀏覽 33
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  91在线精品秘 一区二区 | 高清五码一区二区三区 | 国产黄色免费 | 麻豆成人久久精品二区三区91 | 亚洲A∨剧情中文 |