1、数据倾斜

  1.1 数据倾斜的现象

    现象一:大部分的task都能快速执行完,剩下几个task执行非常慢

    现象二:大部分的task都能快速执行完,但总是执行到某个task时就会报OOM,JVM out of Memory,task faild,task lost,resubmitting task等错误

  1.2 出现的原因

    大部分task分配的数据很少(某个可以对应的values只有几个),但某几个task分配的数据非常多(某个key对应的values非常多)

2、数据倾斜解决方案

  2.1 聚合源数据

    方案一:直接在生成hive表的hive etl中,对数据进行聚合处理

      例如:在hive etl操作时,将key对应的values,全部使用一种特殊的格式进行拼接到字符串中(“key=sessionid, value: action_seq=1|user_id=1|search_keyword=火锅|category_id=001;action_seq=2|user_id=1|search_keyword=涮肉|category_id=001”),对可以进行groupby,那么在spark中直接获取到的是<key,values>,就有可能不需要shuffle操作,就可能避免数据倾斜。

    方案二:使用更小维度进行聚合处理

      例如:每个key对应的10万数据,但是这10万数据中如果按不同的城市、天数等维度进行聚合,可能每个key就对应1万数据,就可以避免数据倾斜

  2.2 过滤导致倾斜的key

    如果业务和需求可以接受的话,在使用spark sql查询hive表中的数据时,通过where语句将导致数据倾斜的key直接过滤掉

    例如:有2个key对应的数据有10万,而其他的key都只有几百的数据,那么如果业务和需求允许的话,可以直接将那两个key过滤掉,自然就不会发生数据倾斜

  2.3 提高shuffle操作reduce的并行度

    reduce并行度增加后,可以让reduce task分配到的数据减少,有可能缓解或基本解决数据倾斜的问题

    可以在shuffle算子中传入第二个参数设置reduce端的并行度

  2.4 使用随机key实现双重聚合

    先将一样的key通过随机数进行拼接为新的不同的key进行局部聚合,然后将添加的随机数去掉后重新进行局部聚合(对groupByKey、reduceByKey有比较好的效果)

    

        /**
* 使用随机key实现双重聚合
* 处理sessionRowPairRdd..groupByKey()数据倾斜
*/
final Random random=new Random();
//将相同的key进行随机打散后聚合
sessionRowPairRdd.mapToPair(new PairFunction<Tuple2<String,Row>, String, Row>() {
private static final long serialVersionUID = 1L;
@Override
public Tuple2<String, Row> call(Tuple2<String, Row> tuple2) throws Exception {
return new Tuple2<String, Row>(random.nextInt()+"_"+tuple2._1, tuple2._2);
}
}).groupByKey() //将打散后的key还原后再次进行聚合
.mapToPair(new PairFunction<Tuple2<String,Iterable<Row>>, String, Iterable<Row>>() {
private static final long serialVersionUID = 1L;
@Override
public Tuple2<String, Iterable<Row>> call(Tuple2<String, Iterable<Row>> tuple2)
throws Exception {
String key = tuple2._1;
return new Tuple2<String, Iterable<Row>>(key.split("_")[], tuple2._2);
}
}).groupByKey();
/**
* 使用随机key实现双重聚合 结束
*/

  2.5 将reduce join转换为map join

    如果两个Rdd需要进行join操作,并且一个Rdd比较小,可以通过broadcast把小的Rdd广播出去

      

        /**
* 使用map join 替换reduce join
* 处理 userIdPartAggrInfoPairRdd.join(userIdInfoPairRdd)导致的数据倾斜
*/
//将小的Rdd userIdInfoPairRdd 作为广播变量
final Broadcast<Map<Long, Row>> broadcastUserIdInfoPairMap=javaSparkContext.broadcast(userIdInfoPairRdd.collectAsMap()); //使用map方式代替reduce join
userIdJoinRdd=userIdPartAggrInfoPairRdd.mapToPair(new PairFunction<Tuple2<Long,String>, Long, Tuple2<String, Row>>() {
private static final long serialVersionUID = 1L;
@Override
public Tuple2<Long, Tuple2<String, Row>> call(Tuple2<Long, String> tuple2)
throws Exception {
return new Tuple2<Long, Tuple2<String,Row>>(tuple2._1, new Tuple2<String, Row>(tuple2._2, broadcastUserIdInfoPairMap.value().get(tuple2._1)));
}
});
/**
* 使用map join 替换reduce join 结束
*/

  2.6 sample采样倾斜key进行两次join

    如果两个Rdd需要进行join操作,并且两个Rdd都比较大,不太适合使用2.5进行处理,但只有几个key会导致数据倾斜,可以先通过sample采样找出导致数据倾斜的key,然后根据找出导致数据倾斜的key将Rdd分为两个Rdd,用分成的两个Rdd分别于另一个Rdd经join后使用union进行合并为最后的Rdd

    

        /**
* 使用sample采样倾斜key进行两次join
* 处理userIdPartAggrInfoPairRdd.join(userIdInfoPairRdd)导致的数据倾斜
*/
//userIdPartAggrInfoPairRdd sample采样查找数据倾斜的sessionId
final Long skewUserId=
//进行sample采样
userIdPartAggrInfoPairRdd.sample(false, 0.1, )
//将采样的数据映射为<userId,1>
.mapToPair(new PairFunction<Tuple2<Long,String>, Long, Long>() {
private static final long serialVersionUID = 1L;
@Override
public Tuple2<Long, Long> call(Tuple2<Long, String> tuple2) throws Exception {
return new Tuple2<Long, Long>(tuple2._1, 1l);
} //按userId进行统计<userId,count>
}).reduceByKey(new Function2<Long, Long, Long>() {
private static final long serialVersionUID = 1L;
@Override
public Long call(Long v1, Long v2) throws Exception {
return v1+v2;
} //将统计结果映射为<count,userId>
}).mapToPair(new PairFunction<Tuple2<Long,Long>, Long, Long>() {
private static final long serialVersionUID = 1L;
@Override
public Tuple2<Long, Long> call(Tuple2<Long, Long> tuple2) throws Exception {
return new Tuple2<Long, Long>(tuple2._2, tuple2._1);
} //按个数降序排列,并获取最大的userId
}).sortByKey(false).take().get()._2; //将导致数据倾斜的userId过滤出来后与userIdInfoPairRdd进行join
JavaPairRDD<Long, Tuple2<String, Row>> skewUserIdJoinRdd = userIdPartAggrInfoPairRdd.filter(new Function<Tuple2<Long,String>, Boolean>() {
private static final long serialVersionUID = 1L;
@Override
public Boolean call(Tuple2<Long, String> tuple2) throws Exception {
return tuple2._1.longValue()==skewUserId;
}
}).join(userIdInfoPairRdd); //将正常的userId过滤出来后与userIdInfoPairRdd进行join
JavaPairRDD<Long, Tuple2<String, Row>> commonUserIdJoinRdd = userIdPartAggrInfoPairRdd.filter(new Function<Tuple2<Long,String>, Boolean>() {
private static final long serialVersionUID = 1L;
@Override
public Boolean call(Tuple2<Long, String> tuple2) throws Exception {
return tuple2._1.longValue()!=skewUserId;
}
}).join(userIdInfoPairRdd); //将导致数据倾斜的userId join后的rdd和正常的userId join后的rdd合并为最终的rdd
userIdJoinRdd=skewUserIdJoinRdd.union(commonUserIdJoinRdd);
/**
* 使用sample采样倾斜key进行两次join结束
*/

  2.7 使用随机数以及扩容表进行join

    

  

  

spark性能调优06-数据倾斜处理的更多相关文章

  1. Spark性能调优之解决数据倾斜

    Spark性能调优之解决数据倾斜 数据倾斜七种解决方案 shuffle的过程最容易引起数据倾斜 1.使用Hive ETL预处理数据    • 方案适用场景:如果导致数据倾斜的是Hive表.如果该Hiv ...

  2. spark性能调优 数据倾斜 内存不足 oom解决办法

    [重要] Spark性能调优——扩展篇 : http://blog.csdn.net/zdy0_2004/article/details/51705043

  3. [Spark性能调优] 第一章:性能调优的本质、Spark资源使用原理和调优要点分析

    本課主題 大数据性能调优的本质 Spark 性能调优要点分析 Spark 资源使用原理流程 Spark 资源调优最佳实战 Spark 更高性能的算子 引言 我们谈大数据性能调优,到底在谈什么,它的本质 ...

  4. spark 性能调优(一) 性能调优的本质、spark资源使用原理、调优要点分析

    转载:http://www.cnblogs.com/jcchoiling/p/6440709.html 一.大数据性能调优的本质 编程的时候发现一个惊人的规律,软件是不存在的!所有编程高手级别的人无论 ...

  5. Spark性能调优-基础篇

    前言 在大数据计算领域,Spark已经成为了越来越流行.越来越受欢迎的计算平台之一.Spark的功能涵盖了大数据领域的离线批处理.SQL类处理.流式/实时计算.机器学习.图计算等各种不同类型的计算操作 ...

  6. Spark性能调优之代码方面的优化

    Spark性能调优之代码方面的优化 1.避免创建重复的RDD     对性能没有问题,但会造成代码混乱   2.尽可能复用同一个RDD,减少产生RDD的个数   3.对多次使用的RDD进行持久化(ca ...

  7. Spark性能调优之合理设置并行度

    Spark性能调优之合理设置并行度 1.Spark的并行度指的是什么?     spark作业中,各个stage的task的数量,也就代表了spark作业在各个阶段stage的并行度!     当分配 ...

  8. Spark性能调优之资源分配

    Spark性能调优之资源分配    性能优化王道就是给更多资源!机器更多了,CPU更多了,内存更多了,性能和速度上的提升,是显而易见的.基本上,在一定范围之内,增加资源与性能的提升,是成正比的:写完了 ...

  9. Spark性能调优之Shuffle调优

    Spark性能调优之Shuffle调优    • Spark底层shuffle的传输方式是使用netty传输,netty在进行网络传输的过程会申请堆外内存(netty是零拷贝),所以使用了堆外内存. ...

随机推荐

  1. ps:新建Photoshop图像

    从现在起我们开始正式地接触Photoshop,为了保证大家的快捷键设置与教程内容一致.请确认Photoshop的快捷键设置是默认值.可从菜单[编辑 键盘快捷键]打开快捷键设置,在组选项里面选择“Pho ...

  2. git 操作遇到的问题与解决方法

    一.使用git在本地创建一个项目的过程,Git 上传本地文件到github $ makdir ~/hello-world //创建一个项目hello-world $ cd ~/hello-world ...

  3. 牛客CSP-S提高模拟4 赛后总结

    前言 其实前面已经打了 3 场牛客 3 场计蒜客的比赛,都没有写总结,今天先提一下以前的情况 计蒜客 1 :0+0+0 = 0 (心态崩了,写挂了) 牛客 1: 0+0+0 = 0 (T1博弈论,T2 ...

  4. springboot通过继承OncePerRequestFilter,在拦截器中@Autowired 为null问题

    springboot2版本以上环境 通过继承OncePerRequestFilter类,在重写doFilterInternal方法实现拦截的具体业务逻辑, 在实现的过程中,需要注入service方法, ...

  5. alert(1) to win 15

  6. Typescript + TSLint + webpack 搭建 Typescript 的开发环境

    (1)初始化项目 新建一个文件夹“client-side”,作为项目根目录,进入这个文件夹: 我们先使用 npm 初始化这个项目: 这时我们看到了在根目录下已经创建了一个 package.json 文 ...

  7. 文本框的SelectionDirection属性

    代码实例: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF ...

  8. java程序员必知的 8大排序

    Java常用的八种排序算法与代码实现 排序问题一直是程序员工作与面试的重点,今天特意整理研究下与大家共勉!这里列出8种常见的经典排序,基本涵盖了所有的排序算法. 1.直接插入排序 我们经常会到这样一类 ...

  9. 用于DataLoader的pytorch数据集

    暂时介绍 image-mask型数据集, 以人手分割数据集 EGTEA Gaze+ 为例. 准备数据文件夹 需要将Image和Mask分开存放, 对应文件的文件名必须保持一致. 提醒: Mask 图像 ...

  10. OC + RAC (四) combineLatest和merg

    -(void)_test4{ ///RAC combineLatest和merge // combineLatest只有当两个信号都发送了 订阅者才能收到信息 结果一次收到 结果是数组 // merg ...