http://spark.apache.org/docs/1.6.2/tuning.html
http://blog.csdn.net/anzhsoft/article/details/42417533
1、算子优化、filter + coalecse
filter不进行重新分区,coalecse是进行重新分区的算子
数据在经过过滤后在不同的分区上存在数据倾斜问题,需要进行重新分区
repartition 和coalecse的区别
coalecse 是用来减少分区的shuffle= false ; repartition是用来增加分区的默认的shuffle= true
2、foreachpartation
foreach 和foreachpartation
map 和 mapPartation
map--》一条数据一条数据处理
mapPartation 一个一个分区处理
foreach 和foreachPartation 和上面的类似 ,foreachPartation 是将数据拿到一个节点上计算有可能存在内存溢出的问
3、reduce和reduceByKey reduceByKey 自带map端的combiner
并行度、分区 : 从文件中读取数据、创建数据、分区数
1、放参数、决定分区数 设置 spark.default.parallelism 默认分区个数:官方推荐默认是cpu个数的2--3倍,这个配置对于读取文件是不生效的,读取的文件是按照文件block分区的,要使用repartation进行重新分区;
sparksql的分区默认是200 不受spark.default.parallelism的设置 spark.sql.shuffle.partations=200
可以在spark-submit 后加参数
0814、性能调优
第一课、rdd持久化、广播变量持久化、序列化
1、RDD的持久化,用完之后要释放unpersist
2、广播大的变量,Broadcast
reduce和reduceByKey reduceByKey 自带map端的combiner
final Broadcast<Map<String, Map<String, IntList>>> dateHourExtractMapBroadcast =
sc.broadcast(fastutilDateHourExtractMap);
默认情况下,task执行的算子中,使用了外部的变量,每个task都会获取一份变量的副本,要网络通信,或网卡流量积针
广播变量,初始的时候,就在Drvier上有一份副本。
task在运行的时候,想要使用广播变量中的数据,此时首先会在自己本地的Executor对应的BlockManager中,
尝试获取变量副本;如果本地没有,那么就从Driver远程拉取变量副本,并保存在本地的BlockManager中;
此后这个executor上的task,都会直接使用本地的BlockManager中的副本。
executor的BlockManager除了从driver上拉取,也可能从其他节点的BlockManager上拉取变量副本,
距离越近越好。
3、序列化、kryo序列化,spark默认的序列化是java序列化,kryo序列化是java序列化的2-10倍,减少序列化对象的数据量
conf.set(" spark.serializer","org.apache.spark.serializer.KryoSerializer")
或者
.set("spark.serializer", "org.apache.spark.serializer.KryoSerializer")
.registerKryoClasses(new Class[]{CategorySortKey.class})
第二课、
1、数据本地性,优先计算本节点数据
进程本地化:PROCESS_LOCAL:进程本地化,代码和数据在同一个进程中,也就是在同一个executor中;
节点本地化:NODE_LOCAL:节点本地化,代码和数据在同一个节点中;
机架:RACK_LOCAL:机架本地化,数据和task在一个机架的两个节点上;
ANY:数据和task可能在集群中的任何地方,而且不在一个机架中,性能最差
这个东西是调节不了的,和数据分布任务分派有关
配置:spark.locality.wait,默认是3s ,尽量数据本地化时间
new SparkConf()
.set("spark.locality.wait", "10")
2、使用高性能的库fastutil
fastutil是扩展了Java标准集合框架(Map、List、Set;HashMap、ArrayList、HashSet)的类库,
提供了特殊类型的map、set、list和queue;
fastutil能够提供更小的内存占用,更快的存取速度;我们使用fastutil提供的集合类,
来替代自己平时使用的JDK的原生的Map、List、Set,好处在于,fastutil集合类,可以减小内存的占用,
并且在进行集合的遍历、根据索引(或者key)获取元素的值和设置元素的值的时候,提供更快的存取速度;
3、java虚拟机的调优
spark.storage.memoryFraction,0.6(默认) -> 0.5 -> 0.4 -> 0.2 用来给cache的内存,剩下的spark跑程序的内存和总的内存占比
第三课、优化
shuffe优化是一对多的优化,而一对一、和多对一是逻辑上数据放在一起了。
堆外内存:java虚拟机以外的内存 ----》spark底层shuffle使用netty传输,所以使用了堆外内存!1.2之前是NIO就是socket,之后默认使用netty
有时候,如果你的spark作业处理的数据量特别特别大,几亿数据量;然后spark作业一运行,时不时的报错,由于底层通信传输数据的内存不够
shuffle file cannot find,executor、task lost,out of memory(内存溢出);
调整堆外内存:
conf spark.yarn.executor.memoryOverhead=2048(两个g)
--conf spark.core.connection.ack.wait.timeout=300 (调整通信等待时长,默认300毫秒)
处于垃圾回收过程中,所有的工作线程全部停止;相当于只要一旦进行垃圾回收,
spark / executor停止工作,无法提供响应
此时呢,就会没有响应,无法建立网络连接;会卡住;ok,spark默认的网络连接的超时时长,是60s;
如果卡住60s都无法建立连接的话,那么就宣告失败了。
碰到一种情况,
uuid(dsfsfd-2342vs--sdf--sdfsd)。not found。file lost。
这种情况下,很有可能是有那份数据的executor在jvm gc。所以拉取数据的时候,建立不了连接。
然后超过默认60s以后,直接宣告失败。
报错几次,几次都拉取不到数据的话,可能会导致spark作业的崩溃。也可能会导致DAGScheduler,
反复提交几次stage。TaskScheduler,反复提交几次task。大大延长我们的spark作业的运行时间。
可以考虑调节连接的超时时长。
--conf spark.core.connection.ack.wait.timeout=300
spark-submit脚本,切记,不是在new SparkConf().set()这种方式来设置的。
spark.core.connection.ack.wait.timeout(spark core,connection,连接,ack,wait timeout,
建立不上连接的时候,超时等待时长)
spark中shuffle的种类
hash:HashShuffleManager
sort:SortShuffleManager
tungsten-sort:UnsafeShuffleManager
默认是sort
spark.shuffle.manager hash M*R 个小文件
spark.shuffle.manager sort
conf.set("spark.shuffle.manager","hash");
hash-based 的洗牌方式要配置:不进行排序的洗牌
new SparkConf().set("spark.shuffle.consolidateFiles", "true")
开启shuffle map端输出文件合并的机制,按照cpu core合并;默认情况下,是不开启的,就是会发生如上所述的大量map端输出文件的操作,严重影响性能。
注:如果不开启文件合并的功能,就会形成海量数据传输问题,上游task数* 下游task数 例如1000*1000 =1000000,开启了文件合并,一个cup core 产生一个文件
sort-based 的洗牌自动进行文件的合并:进行排序的洗白,默认使用
第四课、
1、shuffle map端内存缓冲reduce端内存占比
spark.shuffle.file.buffer,默认32k :map缓存数据的大小
spark.shuffle.memoryFraction,0.2:reduce端的缓存数据占用excutor内存的占比
2、解决算子函数返回null导致的问题
对null做特殊标记,之后再进行判断
3、shuffle file not found 错误解决
spark.shuffle.io.maxRetries 3 拉去文件的次数
spark.shuffle.io.retryWait 5s 拉取文件间隔时间
4、troubleshooting shuffle reduce 端缓冲大小以避免OOM(内存溢出 ,不是因为reduce端拉取数据拉多了,而是reduce端在计算的时候还要占内存所有内存溢出了)
(MapReduce)reduce端默认buffer大小是48MB,spark的shuffle和MR的shuffle绝对是不一样的!!!
减少reduce的缓存占比大小,可以减小reduce端拉取数据的速度
spark.reducer.maxSizeInFlight,48 还可以增大reduce的计算内存大小
5、troubleshooting 错误的持久化方式以及checkpoint的使用
userrdd=userrdd.cache() 使用这种方式缓存数据
第五课、
1、yarnclient可能会存在网卡流量激增的问题
2、troubleshooting 解决yarn-cluster模式的JVM栈内存溢出(永久带内存溢出)
yarn-client默认永久带内存128M;yarn-cluster默认永久带内存82M
在spark-submit的脚步中配置:
永久带内存配置为128M,最大为 256M
--conf spark.driver.extraJavaOptions="-XX:PermSize=128M -XX:MaxPermSize=256M"
3、什么是数据倾斜
任务分配不均匀;
数据倾斜的表现:spark,可以通过页面查看,hive可以看日志,产生时一般伴随shuffe
第六课、数据倾斜的解决方案
第一个方案:聚合源数据
通过hive对源数据进行提前处理,保证数据没有倾斜
第二个方案:过滤导致倾斜的key
怎样知道哪些key会导致倾斜呢??? --》随机取一部分看哪些key可以导致数据倾斜
将导致倾斜的key过滤掉,如果不是脏数据,把这个key的数据单独处理
第三个方案:提高shuffle操作的reduce的并行度
spark_home/conf/spark-default.conf
spark.default.parallelism
解决数据倾斜:
A方案:使用随机key实现双重聚合
这个需要进行二次处理的。
步骤一:使用随机key实现双重聚合
步骤二:执行第一轮聚不聚和
步骤三:去掉每个key的前缀
步骤四:最后第二轮全局聚合
B方案:将reduce join转换为map join
大文件和小文件进行reduce操作时将小文件广播出去;在mapreduce中使用distrubutedcache
=================================
DistributedCache.addCacheFile(new URI("hdfs://1.1.2.1:9000/user/1M_A/Atest.txt"), comW.getConfiguration());
至此,你已经告诉了hadoop你有个缓存文件叫Atest.txt
然后在map端的setup()函数中:
//从分布式缓存中读取矩阵A
//注意:此处使用的是getCacheFiles(),我不明白网上很多人为什么使用getLocalCacheFile,费解
URI[] caches = DistributedCache.getCacheFiles(con.getConfiguration());
//然后就是正常的输入
FileSystem fs = FileSystem.get(caches[0] , con.getConfiguration());
InputStream in = fs.open(new Path(caches[0]));
Scanner input_A = new Scanner(in);
Atest = input_A.next();
=======================================
spark中使用 broadcast
C方案:sample采用倾斜key单独进行join
D方案:使用随机数以及扩容表进行join
flatmap数据之后,将每条数据的key加上一个随机数
就是将key打撒 和使用随机数差不多
1、总结spark调优
rdd持久化、广播变量持久化、序列化
数据本地性,优先计算本节点数据
java虚拟机的调优
使用高性能的库fastutil
2、总结spark常见的异常处理
3、总结spark总结spark数据倾斜的解决方法