【Hive】Hive数据倾斜以及解决方案

什么是数据倾斜:

数据倾斜就是我们在计算数据的时候,数据的分散度不够,导致大量的数据集中到了一台或者几台机器上计算,这些数据的计算速度远远低于平均计算速度,导致整个计算过程过慢。

例如以下情况:

  • 用Hive算数据的时候reduce阶段卡在99.99%
  • 用SparkStreaming做实时算法时候,一直会有executor出现OOM的错误,但是其余的executor内存使用率却很低。  
  •   数据倾斜有一个关键因素是数据量大,可以达到千亿级。

1. 优化数据源,从源头避免

如果导致数据倾斜的表时Hive表,而Hive表中数据的分布很不均匀,而业务需要频繁的对Hive表执行某个分析操作,那么我们可以尝试使用Hive ETL预处理数据(按key进行聚合,或预先和其他表join)。 之后所有操作针对的数据源就不是原来的Hive表了,而是预处理之后的Hive表。 不过需要注意的是,因为数据本身存在分布不均匀的问题,所以在Hive ETL过程中还是会存在数据倾斜,导致Hive ETL速度很慢。我们只是把数据倾斜的发生提前到了Hive ETL中。 方案优点:执行起来简单便捷,效果还很好。 方案缺点:Hive ETL过程中还是会发生数据倾斜。

2. 增加并行度

手动的对shuffle算子传入一个参数,该参数设定了shuffle算子执行时shuffle read task的数量,通过增大这个数量,将原本需要分配到1个task上的key,被分配给了多个task,那么每个task的执行时间自然就短了。 方案优点:实现起来比较简单,可以有效缓解数据倾斜的影响。 方案缺点:只是缓解了数据倾斜而已,并没有在根本上解决数据倾斜的问题。

3. Mapjoin(BroadcastJoin) 替代 Shuffle based Join

适合于在进行join类操作时,其中一个表或RDD的数据量比较小。 普通的join是会走shuffle过程的,而一旦shuffle,就相当于会将相同key的数据拉取到同一个task中进行join。 但是如果其中一个表或RDD比较小,可以采用广播小RDD全量数据+map算子来实现与join同样的效果,此时不会发生shuffle操作,自然也不会发生数据倾斜。 方案优点:因为不会发生shuffle,也就根本不会发生数据倾斜。 方案缺点:仅适用于一个大表和一个小表的情况,且会消耗一定内存资源。

4.局部聚合 + 全局聚合

适合于group by语句或reduceByKey等聚合类shuffle算子进行分组聚合时使用。 其核心思路就是进行两阶段聚合。 首先,将原本相同的key通过附加随机前缀的方式,变成多个不同的key,就可以使原本被一个task处理的数据分散到多个task上去做局部聚合,从而解决单个task处理数据量过多的问题。 接着去掉随机前缀,再进行一次全局聚合,就可以得到最终的结果。 方案优点:对于聚合类的shuffle操作导致的数据倾斜效果很好。 方案缺点:适用范围较窄,仅仅适用于聚合类的shuffle操作。

5.基表增加随机前缀 小表膨胀

如果在进行join操作时,RDD有大量的key导致数据倾斜,便可以考虑使用以下的方法。 将大表的key通过附加n以内的随机前缀,变成"不一样"的key,将其分散到多个task中进行处理,而不是让一个task处理大量的相同的key。 同时对小表进行扩容,每条数据都扩容成n条数据,扩容出来的每条数据都依次打上0~n的前缀。 然后将两个处理后的结果进行join。 方案优点:对join类型的数据倾斜都可以处理,效果比较明显。 方案缺点:需要对小表进行扩容,对内存资源要求很高。

6. 自定义 hash 算法

对key做一层hash,先将数据打散让它的并行度变大,再汇集,使其尽量均匀分布。

7. 过滤掉null部分

若key值存在大量空字段,会hash到同一reduce,造成reduce长尾,此时需要将null值过滤掉。 举例: select user_id from logs where statdate = '20170815' where user_id is not null;

8. 通过设置skew join参数解决hive join倾斜

可以手动传入一个参数,设置join的键对应的记录的最大值,如果超过这个值,新的值会被发送给那些还没有达到的reduce。 set hive.optimize.skewjoin=true;--如果是join 过程出现倾斜 应该设置为true set hive.skewjoin.key=100000; --这个是join的键对应的记录条数超过100000则会进行分拆,值可以根据具体数据量设置

9. 通过设置skew参数解决hive groupby distinct 倾斜

设置为true之后,会有2轮MR过程,第一轮在做reduce操作时,拿到的key并不是所有相同值给同一个reduce,而是随机分发,然后在reduce阶段做聚合。 在聚合之后,再进行一轮MR任务,拿前面聚合过的数据再算记过,虽然多了一轮MR任务,但是可以有效地减少数据倾斜带来的危险。 set hive.groupby.skewindata=true; - -如果是group by过程出现倾斜 应该设置为true set hive.groupby.mapaggr.checkinterval=100000 ; --group的键对应的记录条数超过这个值则会进行优化。

需要注意的是,当启用set hive.groupby.skewindata=ture时,能够解决数据倾斜问题,但如果在查询语句中对多个字段进行去重统计时会报错。

举例:

hive> set hive.groupby.skewindata=true; hive> select count(distinct id),count(distinct x) from test; FAILED: SemanticException [Error 10022]: DISTINCT on different columns not supported with skew in data

你可能感兴趣的:(大数据问题处理集锦,大数据,hive,hadoop)