• hive on spark 之通过spark web ui详解数据倾斜及思路历程


     然后我看了一下sql

                       FROM ODSERPDATA.FA_ADDITIONS_B                                FA --
                       JOIN ODSERPDATA.FA_BOOKS                                             FB --
                         ON FB.ASSET_ID = FA.ASSET_ID
                       JOIN DWINTDATA.DW_F_FA_DEPRNS_TMP1                       T-- 这个是临时表
                         ON T.ASSET_ID = FA.ASSET_ID
                        AND T.BOOK_TYPE_CODE = FB.BOOK_TYPE_CODE
                       JOIN ODSERPDATA.FA_BOOK_CONTROLS                           FBC
                         ON FBC.BOOK_TYPE_CODE = FB.BOOK_TYPE_CODE
                       JOIN ODSERPDATA.GL_LEDGERS                                          SOB --  
                         ON SOB.LEDGER_ID = FBC.SET_OF_BOOKS_ID
                       JOIN ODSERPDATA.FA_CATEGORY_BOOKS                         FCB ----
                         ON FCB.BOOK_TYPE_CODE = FB.BOOK_TYPE_CODE
                       JOIN ODSERPDATA.FA_ASSET_HISTORY                               FAH ----
                         ON FAH.CATEGORY_ID = FCB.CATEGORY_ID
                        AND FAH.ASSET_ID = FB.ASSET_ID
                       JOIN ODSERPDATA.GL_CODE_COMBINATIONS                     GCC ---
                         ON GCC.CODE_COMBINATION_ID = T.CODE_COMBINATION_ID
                       JOIN ODSERPDATA.FA_LOCATIONS                                          FL-------
                         ON T.LOCATION_ID = FL.LOCATION_ID

    差不多就是如下 a join b  join c join d  join e join f 一长串。说实话我也难搞,每次就是一长串sql让我找问题 让我优化,我看完sql理解下都要十几分钟。。。

    思路1:任务跑不动可能是数据量太大

    首先肯定是数据量太大, 如果abcdefgh十几个表每个表数据量都是几万,那么就算都join在一块,也不会出现跑不动的情况。。

    那我们就开始找大表。

    select count(1) from DWINTDATA.DW_F_FA_DEPRNS_TMP1   --3492814
    select count(1) from ODSERPDATA.FA_ADDITIONS_B          --7353046
    select count(1) from ODSERPDATA.FA_BOOKS             --9528477
    select count(1) from ODSERPDATA.FA_BOOK_CONTROLS     --558
    select count(1) from ODSERPDATA.GL_LEDGERS              --160
    select count(1) from ODSERPDATA.FA_CATEGORY_BOOKS    --36035
    select count(1) from ODSERPDATA.FA_ASSET_HISTORY     --11585417  --注意这个
    select count(1) from ODSERPDATA.GL_CODE_COMBINATIONS --26958010

    找到了这么几个大表。其实数据也不算多。

    思路二:任务跑不动可能是资源划分太少。

    set spark.driver.memory=6G

    set spark.executor.cores=4;

    set spark.executor.memory=4G;

    set spark.executor.instances=10;

    加了之后发现task 还是会卡住,但是卡的好像少了一个。。等会附图

    思路三:任务跑不动极有可能是数据倾斜(重点!!)

    任务一般会分多个stage,一个stage划分多个task,stage可以看做join,task可以看成任务真正运行的。所以我们看到的卡住的task,如下图473tasks结果就一个失败了,极有可能是数据倾斜了,而且按照跑的时间来看 大概率是倾斜的贼多!!!

     那么怎么分辨哪个表数据倾斜呢?

    1 机缘巧合之下 发现表的数据倾斜

    select count(1) from ODSERPDATA.FA_ASSET_HISTORY     --11585417  --注意这个

    然后我看spark web ui 的时候,这里任务已经开始卡住了

    点进这个stage细看咦这里怎么刚好有个 shuffle writeMax =11585417

     其实这里不是特别明白这个 shuffle write是哪一步了 ,但是这个stage卡住了,刚好这个数字相等,那么总归有点关系的。

    2.最朴素的办法发现数据倾斜。一个个select count(),joinkey group by  joinkey

    倾斜的根本原因就是join 偶尔 group 也有。

    以上表为例ODSERPDATA.FA_ASSET_HISTORY 

    那么我们把这个sql简化为

    select 
    FB.BOOK_TYPE_CODE ,FB.ASSET_ID,
    FCB.BOOK_TYPE_CODE,FCB.CATEGORY_ID,
    FAH.CATEGORY_ID,FAH.ASSET_ID,
    from ODSERPDATA.FA_BOOKS                      FB ----7353046
    JOIN ODSERPDATA.FA_CATEGORY_BOOKS            FCB --9528477
    ON FCB.BOOK_TYPE_CODE = FB.BOOK_TYPE_CODE
    JOIN ODSERPDATA.FA_ASSET_HISTORY             FAH --11585417
    on  FAH.ASSET_ID = FB.ASSET_ID
    AND FAH.CATEGORY_ID = FCB.CATEGORY_ID

    然后查出他们的joinkey的分布情况。 

    ODSERPDATA.FA_BOOKS                      FB.BOOK_TYPE_CODE和 FB.ASSET_ID

    注意这两个key是分别关联的。 所以不要用group by FB.BOOK_TYPE_CODE,FB.ASSET_ID

    上面这个一看就很均匀 

    book_type_code=105_FA_BOOK==7178652=700w就一个  --注意这条数据

    然后10w-20w的有7个,1-10w的有20个。

     上面这个一看,好家伙,这个很明显就是数据倾斜了。 但是也不要确定,因为万一700w的这个数据就是摆设呢?谁也关联不到。

    ODSERPDATA.FA_CATEGORY_BOOKS joinkey BOOK_TYPE_CODE  CATEGORY_ID

     CATEGORY_ID 平平无奇 都是200 199 198

     BOOK_TYPE_CODE 也是平平无奇,但是注意我上面提到的那条700w的数据

    上面的book_type_code=105_FA_BOOK=700w

    这里的book_type_code=105_FA_BOOK=401

    两者join 在不过滤其他的条件的情况下 401*700w=28亿条数据。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。

    所以问题出在哪里?答案就是

    select 
    FB.BOOK_TYPE_CODE ,FB.ASSET_ID,
    FCB.BOOK_TYPE_CODE,FCB.CATEGORY_ID
    from ODSERPDATA.FA_BOOKS                      FB ----7353046
    JOIN ODSERPDATA.FA_CATEGORY_BOOKS            FCB --9528477
    ON FCB.BOOK_TYPE_CODE = FB.BOOK_TYPE_CODE

    就是这个继续简化的sql了。

    我们单独执行这个sql 看下

    45s 473个task 已经完成了470个 有3个卡住了。 

     继续点进去看下 注意右下角有个7179053 我们之前的那个key是105_FA_BOOK= 7178652 看着有点像又有点多了

    7179053-7178652=101 这多的401有没有小伙伴知道哪来的?

    因为105_FA_BOOK 有7178652 ,其余的key有的十万 有的1w 有的100 有的10 有的1 

    如下图 这个字段的key共有263个,其中core因为设置了动态调整,不知道的可以百度spark.dynamicAllocation.enabled=true ,举个例子就是

    105_FA_BOOK +10X_FA_BOOK++10X_FA_BOOK++10X_FA_BOOK=7179053

     解释完了 我们再好好的看下任务

    跑了10分钟 3个顽固分子也倒下了2个 还剩我说的700w那个。我们看看其他的是不是和我说的一一样 

    13.5 GB / 2720441164.4 MB / 726822

     这个 726822 应该是这个69w+其他的几个key了。大概算下

    692584*387=268030008 和上述的272044116也差不多。注意这个输出了13.5G,那我们先前算的28亿差不多就是135G。。。所以啊,为啥任务跑不动,为啥/tmp的磁盘容易被打爆,原因出来了吧。。

    话也说到这里了。那么重头戏来了,怎么解决。其实这种方法大家说了很多了,无非就是小表扩容大表打散。

    select FB.BOOK_TYPE_CODE,
           FB.ASSET_ID,
           FB.book_type_code_random,
           FCB.BOOK_TYPE_CODE,
           FCB.CATEGORY_ID,
           FCB.book_type_code_random
    from (
             select FB.BOOK_TYPE_CODE,
                    FB.ASSET_ID,
                    case book_type_code
                        when '105_FA_BOOK' then concat(book_type_code, "_", floor(RAND() * 10)) --大表随机1-9
                        else book_type_code
                        end as book_type_code_random
             from ODSERPDATA.FA_BOOKS FB) FB ----7353046
             JOIN (
        select concat(book_type_code, random) book_type_code_random, BOOK_TYPE_CODE, CATEGORY_ID
        from (
                 select case book_type_code
                            when '105_FA_BOOK' then concat_ws('_', '1', '2', '3', '4', '5', '6', '7', '8', '9')
                            else ""
                            end as repeat_number,
                        BOOK_TYPE_CODE,
                        CATEGORY_ID
                 from ODSERPDATA.FA_CATEGORY_BOOKS -- 小表扩容1-9 增加了八倍
             ) t lateral view explode(split(repeat_number, "_")) table_tmp as random
    ) FCB
                  ON FCB.book_type_code_random = FB.book_type_code_random

    花费时间4min 可以接受

     看右边都是70w-80w 就是我们700w数据打散后的数据

    多说两句这个的核心思想其实就是

    700w*400=28亿变成了

    400*10扩容十倍   700w打散十份

    400*70w+400*80w+400*60w+400*70w+400*70w+400*70w....=400*(700w)=28亿

    重要的是小表等额扩容。 不要扩容成 400 398 402这种了。

    大表随机打散打的不是太散不会影响结果的。

  • 相关阅读:
    猿创征文|【算法】一文吃透常见排序算法
    二、【React-Router5】路由的基本使用
    架火炬市场现状及未来发展趋势分析
    【预测模型-BP分类】基于人工蜂群算法优化BP神经网络实现数据分类附matlab代码
    ubuntu深度学习配置
    React项目中Antd组件库 Tab选项卡 defaultActiveKey 不生效解决方案
    Springboot 解决linux服务器下获取不到项目Resources下资源
    Java基础篇(简单语法的一些细节介绍)
    2386: [余姚2015] 幸运数字(luck)
    巧妙实现防止按钮重复点击
  • 原文地址:https://blog.csdn.net/cclovezbf/article/details/127419794