大数据计算引擎当中,Spark受到的重视是越来越多的,尤其是对数据处理实时性的要求越来越高,Hadoop原生的MapReduce引擎受到诟病,Spark的性能也需要不断调整优化。今天的大数据入门分享,我们就来讲讲SparkCore开发调优原则。
Spark在大数据领域,能够实现离线批处理、SQL类处理、流式/实时计算、机器学习、图计算等各种不同类型的计算操作,对于企业而言是低成本下的可靠性选择,但是想要真正用好Spark,实现真正的高性能,调优是不可或缺的手段。
SparkCore开发调优原则
1、避免创建重复的RDD
通常来说,我们在开发一个Spark作业时,首先是基于某个数据源(比如Hive表或HDFS文件)创建一个初始的RDD;接着对这个RDD执行某个算子操作,然后得到下一个RDD;以此类推,循环往复,直到计算出最终我们需要的结果。
我们在开发过程中要注意:对于同一份数据,只应该创建一个RDD,不能创建多个RDD来代表同一份数据。否则,我们的Spark作业会进行多次重复计算来创建多个代表相同数据的RDD,进而增加作业的性能开销。
2、尽可能复用同一个RDD
除了要避免在开发过程中对一份完全相同的数据创建多个RDD之外,在对不同的数据执行算子操作时还要尽可能地复用一个RDD。
尤其对于类似这种多个RDD的数据有重叠或者包含的情况,尽量复用一个RDD,这样可以尽可能地减少RDD的数量,从而尽可能减少算子执行的次数。
3、对多次使用的RDD进行持久化
Spark中对于一个RDD执行多次算子的默认原理是这样的:每次你对一个RDD执行一个算子操作时,都会重新从源头处计算一遍,计算出那个RDD来,然后再对这个RDD执行你的算子操作。这种方式的性能是很差的。
而对多次使用的RDD进行持久化,Spark就会根据你的持久化策略,将RDD中的数据保存到内存或者磁盘中。以后每次对这个RDD进行算子操作时,都会直接从内存或磁盘中提取持久化的RDD数据,然后执行算子,而不会从源头处重新计算一遍这个RDD,再执行算子操作。
4、尽量避免使用shuffle类算子
如果有可能的话,要尽量避免使用shuffle类算子。因为Spark作业运行过程中,最消耗性能的地方就是shuffle过程。shuffle过程,简单来说,就是将分布在集群中多个节点上的同一个key,拉取到同一个节点上,进行聚合或join等操作。
比如reduceByKey、join等算子,都会触发shuffle操作。没有shuffle操作或者仅有较少shuffle操作的Spark作业,可以大大减少性能开销。
5、使用map-side预聚合的shuffle操作
如果因为业务需要,一定要使用shuffle操作,无法用map类的算子来替代,那么尽量使用可以map-side预聚合的算子。
所谓的map-side预聚合,说的是在每个节点本地对相同的key进行一次聚合操作,类似于MapReduce中的本地combiner。map-side预聚合之后,每个节点本地就只会有一条相同的key,因为多条相同的key都被聚合起来了。其他节点在拉取所有节点上的相同key时,就会大大减少需要拉取的数据数量,从而也就减少了磁盘IO以及网络传输开销。
6、使用高性能的算子
除了shuffle相关的算子有优化原则之外,其他的算子也都有着相应的优化原则。
比如说使用reduceByKey/aggregateByKey替代groupByKey;使用mapPartitions替代普通map;使用foreachPartitions替代foreach;使用filter之后进行coalesce操作;使用repartitionAndSortWithinPartitions替代repartition与sort类操作等。
7、广播大变量
在开发过程中,有时会遇到需要在算子函数中使用外部变量的场景(尤其是大变量,比如100M以上的大集合),那么此时就应该使用Spark的广播(Broadcast)功能来提升性能。
在算子函数中使用到外部变量时,默认情况下,Spark会将该变量复制多个副本,通过网络传输到task中,此时每个task都有一个变量副本。如果变量本身比较大的话(比如100M,甚至1G),那么大量的变量副本在网络中传输的性能开销,以及在各个节点的Executor中占用过多内存导致的频繁GC,都会极大地影响性能。
8、使用Kryo优化序列化性能
在Spark中,主要有三个地方涉及到了序列化:
在算子函数中使用到外部变量时,该变量会被序列化后进行网络传输。
将自定义的类型作为RDD的泛型类型时(比如JavaRDD,Student是自定义类型),所有自定义类型对象,都会进行序列化。因此这种情况下,也要求自定义的类必须实现Serializable接口。
使用可序列化的持久化策略时(比如MEMORY_ONLY_SER),Spark会将RDD中的每个partition都序列化成一个大的字节数组。
对于这三种出现序列化的地方,我们都可以通过使用Kryo序列化类库,来优化序列化和反序列化的性能。
关于大数据入门,SparkCore开发调优原则,以上就为大家做了简单的介绍了。SparkCore作为Spark的核心部分,要真正掌握Spark框架,那么核心部分一定要吃透。