问题
近日处理一些大数据时老是出现OutOfMemoryError: Direct buffer memory
的问题,一开始以为是数据倾斜问题,然后使用拆分倾斜key分别join再union的方法处理数据倾斜。后来测试发现,反而是非倾斜部分的数据进行join时出现了此问题。
实验过程
我做了些实验:
- 大表
column1
中-
和notset
字符串的量分别为8.5亿和2.8亿,占了大约总量的二分之一。 - 这两张表中个表我只取
column1
这个字段,并且根据column1
groupby 之后cont()为num,再将这两张表的结果进行join,并且增加列为表1的num乘以
表2的num的结果,即为两张原始表join后的数量。结果发现前三数量最大的为16780380,255084,147246,无-
或是字符串notset
。 - 小表table1中没有
column1
为-
或是字符串notset
, 同样这两个字符串也不会再步骤2中出现。也就是-
和字符串notset
在left join中起不到任何作用,只会在shuffle是占用大量空间。 - 通过观察web ui 中的sql 标签页,发现都是大表与大表的“SortMergeJoin”。
- 因为左连接左小表table1的
column1
中没有-
和字符串notset
,在读取右大表直接过滤掉column1
中含-
和字符串notset
的列,至此实验通过,不再报OutOfMemoryError: Direct buffer memory
的问题。
原因分析
根据“SortMergeJoin”原理,我认为是:
虽然小表table1中没有-
或是字符串notset
,但是仍会将大表table2中的-
和字符串notset
shuffle到某些分区中,因为量大这样可能导致内存溢出。
所以好的优化方法是:
- 左关联中,将左表中没有的key,但是在右表中量又是特别大的提前从右表中剔除掉。
一个新的分析数据的技巧:
对某一些key join之后再根据数量排序,可以参考实验步骤1。这样可以减少占用的数据占用内存的空间。
处理数据倾斜demo
下面是处理数据倾斜的代码,具体使用说明可参考另一篇文章spark sql 调优。
1 | day_before_ystd = '2019-04-02' |