Spark RDD / DF作为类的变量成员。它会影响性能吗?

时间:2018-11-06 14:49:47

标签: scala performance apache-spark serialization

我想问一个理论问题。

假设我们的主要对象为:

val pathToFile: String = "/some/path/to/file.csv" 
val rddLoader: RddLoader = new RddLoader(pathToFile)
val rdd = rddLoader.load()
def transformer = new Transformer(rdd)
transformer.transform1(someOtherRdd)
transformer.transform2(yetAnotherRdd)

将Transformer定义为(伪代码)

class Transformed(rdd: RDD[sruct]) {

  val rddToTransform = rdd.someTransformation

  def complexTransformations1(anotherRdd: RDD[struct]) = {
     rddToTransform.complexTransformationsInvlovingAnotherRdd
  }

  def complexTransformations2(anotherRdd: RDD[struct]) = {
     rddToTransform.complexTransformations2InvlovingAnotherRdd
  }
}

rddToTransfrom是类的成员,因此该类的实例的成员会影响性能。我想整个课程都将被序列化。但这会导致rddToTransform为每个分区多次序列化。

在性能,开销序列化等方面,下面的方法会更好。在其中,我们使用的是Object,而我们的RDD不是类的成员,而只是作为参数传递给方法。

val pathToFile: String = "/some/path/to/file.csv" 
val rddLoader: RddLoader = new RddLoader(pathToFile)
val rdd = rddLoader.load()
def transformer = Transformer
transformer.transform1(rdd, someOtherRdd)
transformer.transform2(rdd, yetAnotherRdd)


object Transformer {

  def complexTransformations1(rdd, anotherRdd: RDD[struct]) = {
     rddToTransform.complexTransformationsInvlovingAnotherRdd
  }

  def complexTransformations2(rdd, anotherRdd: RDD[struct]) = {
     rddToTransform.complexTransformations2InvlovingAnotherRdd
  }
}

我可以举一个带有广播变量的例子。我了解他们的工作方式,我只是想知道下面解释的内容是否也适用于RDD,以及是否需要避免像第一个示例(类成员)那样使用RDD

比方说,我们有一个大型数据集,具有420个分区和8个执行者节点的集群。在这样的操作中:

val referenceData = Map(...)
val filtered = rdd.filter(elem => referenceData.get(elem) > 10)

referenceData对象将被序列化420次,或执行转换所需的任务数。

相反,广播变量:

val referenceDataBC = sparkContext.broadcast(Map(...))
val filtered = rdd.filter(elem => referenceDataBC.value.get(elem) > 10)

将发送给每个执行者一次,或总共发送8次。因此,通过减少序列化开销可以节省大量网络和CPU。

1 个答案:

答案 0 :(得分:1)

答案是肯定的,在正常情况下,广播变量是更好的内存优化方法,但在某些情况下它们不可用。

为了更好地理解:

Apache Spark有两种类型的抽象。 Spark提供的主要抽象是弹性分布式数据集(RDD),另一个是共享变量。

共享变量: 共享变量是许多函数和方法必须并行使用的变量。共享变量可以在并行操作中使用。

Spark将作业分为可能的最小操作,即闭包,在不同的节点上运行,每个节点都有Spark作业的所有变量的副本。对这些变量所做的任何更改都不会反映在驱动程序中,因此,为了克服此限制,Spark提供了两种特殊类型的共享变量:广播变量和累加器。

广播变量: 用于在所有节点上的内存中缓存值。在此,整个群集的所有计算之间仅共享此只读变量的一个实例。 Spark将广播变量发送到与相关任务有关的每个节点。之后,每个节点都以序列化的形式将其本地缓存。 现在,在执行每个计划的任务之前,而不是从驱动程序系统获取值,将从本地从缓存中检索它们。 广播变量为:

不变(不变), 分发,即广播到集群, 容纳内存

累加器: 顾名思义,累加器的主要作用是累加值。累加器是用于实现计数器和总和的变量。 Spark仅提供数字类型的累加器。 用户可以创建命名或未命名的累加器。 与广播变量不同,累加器是可写的。但是,写入的值只能在驱动程序中读取。这就是为什么累加器可以很好地与数据聚合器一起工作的原因。