spark如何进行性能优化?首先需要了解基本的spark运行原理,建议看之前的介绍文章。其实是知道如何查看指标,只有通过指标才能正确反馈问题出在哪里?

spark的相关看板字段说明,可以参考官方文档:Spark UI监控

查看ui可以方便知道底层运行的相关逻辑,需要关注一些数值,比如task的简单metrics指标,p99、avg、min和max是否较为接近,如果相差太大,很可能是数据倾斜,需要做相关处理,此外关注任务数是否合理,相关的spark参数配置是否合适,具体参考之前的spark参数配置文章。

原则

  • 避免创建重复的RDD: 进行多次重复计算来创建多个代表相同数据的RDD,进而增加了作业的性能开销。
  • 尽可能复用同一个rdd: 尽量复用一个RDD,这样可以尽可能地减少RDD的数量,从而尽可能减少算子执行的次数。
  • 对多次使用的RDD进行持久化: spark默认的规则,每次对一个RDD执行一个算子操作时,都会重新从源头处计算一遍,计算出那个RDD来,然后再对这个RDD执行你的算子操作,这种方式的性能是很差,可以通过cache持久化来减少重新计算的逻辑。
  • 尽量避免使用shuffle类算子: shuffle类算子会导致数据的shuffle,会增加网络传输的成本,除非必要,否则避免使用shuffle类算子。
  • 使用Kryo优化序列化性能: 变量会被序列化后进行网络传输,因此序列化的性能会影响到整体的性能,使用Kryo序列化可以提高序列化的性能。

数据倾斜

现象

发生数据倾斜的明显现象有

  • 绝大多数task执行得都非常快,但个别task执行极慢。
  • 个别分区处理报OOM(内存溢出)异常

原理

数据倾斜的原理很简单:在进行shuffle的时候,必须将各个节点上相同的key拉取到某个节点上的一个task来进行处理,比如按照key进行聚合或join等操作。此时如果某个key对应的数据量特别大的话,就会发生数据倾斜。比如大部分key对应10条数据,但是个别key却对应了100万条数据,那么大部分task可能就只会分配到10条数据,然后1秒钟就运行完了;但是个别task可能分配到了100万数据,要运行一两个小时。因此,整个Spark作业的运行进度是由运行时间最长的那个task决定的。

解法

  • 过滤少数导致倾斜的key: 分析key的分布情况,找到异常数据过滤掉。
  • 提高shuffle操作的并行度: 治标不治本,不过可以快速实现,提高并行度,将分区的数量解决单个大key,专门处理。
  • 随机分区提前打散: 通过随机key去分区,均匀数据处理。

经验之谈

设计外部请求

最近自己比较常用的逻辑是请求对象存储,拿到图片数据,这里对外部的请求如何控制并发,以及如何确保不重复请求有相关的经验,首先是在开始请求外部接口的dataframe前,做均匀repartition后再cache,确保每个分区的请求数据量是均衡的,cache后spark就不会重复计算之前的逻辑,之后开始接入外部请求的map算子,下一步很关键,就是进行一次cache以及通过count这个action算子触发,让spark去执行请求调用,并且最好是count之后写一个hdfs开始记录结果,后续重hdfs读取已经完成请求的数据,应为之后的repartition可能会导致重复外部请求的问题。

参考