spark性能优化

来源:互联网 发布:淘宝手机店铺装修尺寸 编辑:程序博客网 时间:2024/06/16 09:48

熟悉spark内核之后,深刻体会到了spark开发中存在着大量细节左右着计算性能。趁着刚看过大概的流程,先基于目前的感受和相关资料,总结一下可能存在优化空间的地方。

spark优化其实就是将不必要的开销能省就省。

创建RDD是昂贵的,从磁盘读取RDD也是昂贵的,需要大量的IO开销,shuffle是与基于内存相违背的,涉及IO、网络通信等昂贵的操作。。。都是能避免就避免。

有时候会因为极个别的task运行时长严重拖慢系统的计算速度,所以需要针对task的昂贵开销进行优化。

最后,由于集群计算,集群资源的利用也是可以优化的地方。

那么,根据上述性能优化可以从3个方面入手:
(1)代码开发
(2)数据倾斜
(3)资源管理

1 代码开发

RDD频繁创建是昂贵的:

1.1 对于同一数据集只创建一个RDD,重复创建意味着重复计算;即使新产生的数据集是子集等情况,只要可以转换都只用一个RDD。

问题的核心就是尽量避免重复计算。创建之后也要尽可能多的重复利用这个RDD

1.2 对多次使用的RDD进行cache()。对一个RDD进行多次操作时,默认的情况都会短暂地将RDD缓存在内存中,但是为确保万一仍然需要手动缓存,这样RDD就不需要从头开始计算了。

在进行缓存的时候,如果面临大规模数据,内存不够用怎么办?

persist手动选择缓存级别:

内存够用:MEMORY_ONLY,不用序列化,不用写磁盘,很好

内存稍微紧张一点:MEMORY_ONLY_SER,会对RDD进行序列化,减小一些内存的消耗,同时只是多了序列化和反序列化的操作。

内存真的不够:MEMORY_AND_DISK_SER、MEMORY_AND_DISK加载到磁盘

1.3 尽量避免涉及到shuffle的操作

shuffle中的stage分界出会写读磁盘文件,诸如reduceByKey、join、repartition等都涉及,能不用就不用。

避免shuffle操作可以使用map+broadcast代替,当然适用场景只有将小规模的数据集合并到大规模数据集,这样小规模的广播代价不会太大。

另外可以使用map-side的reduce操作:

典型的是reduceByKey和aggregateByKey都会先再本地节点先根据key先局部聚合,这样进行读写和传输的数据将会大大减少。

1.4 高效算子,适合每一个记录都需要连接等资源的情况

mapPartition对一个分区进行操作,如果每个记录需要建立连接等耗费资源的时候,按分区操作就可以节省大量的开销。

类似的还有foreach和foreachPartition

1.5 尽量多使用map侧的算子

特点就是先再本地进行聚合等操作,然后再聚合进行全局聚合。

1.6 算子参数partition

一个stage由若干partition并行执行,决定了并行度,对于每个算子根据具体的数据量进行设置。

2 数据倾斜

2.1 定位task

数据分布不均匀,会造成每个task要处理的数据量有极大的差异,由于需要同步完成,所以所有的task都需要等其他都完成才算完成。

由于数据倾斜是因为极个别task的拖后腿行为,所以首要问题是找出task。

在spark Web UI上查看各个stage中各个task分配的数据量。一般都在于shuffle算子有关的地方,找到后就可以使用countByKey统计一下key的分布。

2.2 解决方法

2.2.1 提高并行度

提高并行度有两个方面:

一个是在数据预处理的时候,通过分析查看某几个数量格外大的feature,将feature进行编号,比如feature1等,人工将数据的并行度提高,再去掉后缀或者前缀进行全局聚合。

另一个则是在进行计算的时候,提高partitions的数量,这样可以增加shuffle操作的并行度,可以减轻数据倾斜的影响。

2.2.2 数据预处理

查看key的分布,如果只是几个影响不大的key不均匀,可以直接过滤掉。

3 资源管理

资源管理参数在spark-submit中进行设置。资源的分配主要是集群管理器来进行。

资源主要是两个方面:一个是CPU核心数量,一个是内存大小。

由于task是以线程运行的,所以核心的数量决定了一个Executor钟的task执行速度。

内存包括了业务代码所占内存,task对shuffleMapOut的输出结果进行计算所需内存,还有RDD的持久化策略所保持在内存中的RDD。

那么针对上述情况,有以下几个参数可以调节:

1.num-executors:其实就是Executor的个数;
2.executor-cores:Executor中CPU核心的个数,决定了task执行的速度。executor-cores*num-executors<1/2个TotalCores。
3.executor-memory:内存大小。
4.driver-memory:driver的内存,因为有几个操作是将数据聚合到driver节点操作的,所以注意别溢出了。
5.spark.default.parallelism:并行度,这个参数对任务的影响很大,设置不好就数据倾斜。
6.spark.storage.memoryFraction:持久化所占内存比例,spark基于内存的计算,比例要高一点好。
7.spark.shuffle.memoryFraction:shuffle中间结果所占内存。

原创粉丝点击