介绍
数据倾斜是统计术语,反应在数据集中的值分布情况。当数据是高度倾斜时,表示一些列值拥有更多的行,而一些拥有更少的行。值没有平均分配,这样在分布式系统中会造成性能问题。
join多张拥有数据倾斜问题的表
在Spark中join多张拥有数据倾斜问题的表,可能会出现卡在最后的stage(399/400),当超过一定时间后,会报Caused by: org.apache.spark.shuffle.FetchFailedException: Too large frame: 7498008366错误。
例子如下:
-- Sample query where we are joining on highly null columns
select *
from order_tbl orders left join customer_tbl customer
on orders.customer_id = customer.customer_id
left join delivery_tbl delivery
on orders.delivery_id = delivery.delivery_id
表统计如下:
解决数据倾斜问题
因为order_tbl表拥有NULL值,但是我们不能过滤NULL值,我们需要order_tbl中的所有记录。我们注意到199个任务相当快,但是卡在最后一个任务。
产生的原因是:当Spark join两个DataFrames时,内部spark会做默认的shuffle hash join操作,在这个过程中,spark hash join的列,排序它。然后保持拥有相同hash的记录到相同executor的partitions,因此NULL值的记录会到同一个executor,spark进入到一个持续的shuffling和垃圾回收,最终导致执行不成功。
解决
需要切割表为两部分,第一部分是不包含NULL值的记录,第二部分是包含NULL值的记录。
CREATE TABLE order_tbl_customer_id_not_null as select * from order_tbl where customer_id is not null;
CREATE TABLE order_tbl_customer_id_null as select * from order_tbl where customer_id is null;
需要修改ETL逻辑,与非NULL值的表做left join,仅仅union拥有NULL值的表,这样可以避免shuffle和GC Pause问题。
--Rewrite query
select orders.customer_id
from order_tbl_customer_id_not_null orders left join customer_tbl customer
on orders.customer_id = customer.customer_id
union all
select ord.customer_id from order_tbl_customer_id_null ord;