然后我看了一下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 / 272044116 | 4.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这种了。
大表随机打散打的不是太散不会影响结果的。