编写 spark 作业时是否有理由不使用 SparkContext.getOrCreate?

Is there a reason not to use SparkContext.getOrCreate when writing a spark job?

我正在编写与 Datastax 中的 Cassandra 对话的 Spark 作业。

有时,在执行 Spark 作业中的一系列步骤时,只获取一个新的 RDD 而不是连接到旧的 RDD 更容易。

您可以通过调用 SparkContext [getOrCreate][1] 方法来完成此操作。

现在,有时 Spark 作业内部会担心引用 SparkContext 可能会获取不可序列化的大对象(Spark 上下文)并尝试通过网络分发它。

在这种情况下 - 您正在为该 JVM 注册一个单例,因此它解决了序列化问题。

有一天,我的技术主管来找我说

Don't use SparkContext getOrCreate you can and should use joins instead

但他没有给出理由。

我的问题是:编写 spark 作业时是否有不使用 SparkContext.getOrCreate 的原因?

TL;DR getOrCreate 方法有许多合法应用,但试图找到漏洞以执行映射端连接不是其中之一。

总的来说,SparkContext.getOrCreate 没有什么严重的错误。该方法有其应用,尽管有一些注意事项,最值得注意的是:

  • 在其最简单的形式中,它不允许您设置特定于作业的属性,而第二个变体 ((SparkConf) => SparkContext) 需要传递 SparkConf,这与保持 SparkContext / SparkSession 在范围内。
  • 它可能导致具有 "magic" 依赖性的不透明代码。它会影响测试策略和整体代码可读性。

但是你的问题,具体来说:

Now sometimes there are concerns inside a Spark Job that referring to the SparkContext can take a large object (the Spark Context) which is not serializable and try and distribute it over the network

Don't use SparkContext getOrCreate you can and should use joins instead

表明您实际上正在以一种从未打算使用的方式使用该方法。通过在执行节点上使用 SparkContext

val rdd: RDD[_] = ???

rdd.map(_ => {
  val sc = SparkContext.getOrCreate()
  ...
})

这绝对是你不应该做的事情。

每个 Spark 应用程序应该有一个,并且只有一个 SparkContext 在驱动程序上初始化,Apache Spark 开发人员做了很多事情来阻止用户在驱动程序之外使用 SparkContex 的任何尝试。不是因为 SparkContext 太大,或者无法序列化,而是因为它是 Spark 计算模型的基本特征。

您可能知道,Spark 中的计算由有向无环依赖图描述,其中:

  • 以可以转化为实际任务的方式描述处理管道。
  • 在任务失败的情况下启用从容恢复。
  • 允许适当的资源分配并确保没有循环依赖。

让我们关注最后一部分。由于每个执行程序 JVM 都有自己的 SparkContext 实例,因此循环依赖性不是问题 - RDDsDatasets 仅存在于其父上下文的范围内,因此您将无法对象属于应用程序驱动程序。

适当的资源分配是另一回事。由于每个 SparkContext 创建自己的 Spark 应用程序,您的 "main" 进程将无法解释任务中初始化的上下文所使用的资源。同时集群管理器不会有任何迹象表明应用程序或以某种方式相互连接。这可能会导致类似死锁的情况。

在技术上可以绕过它,仔细分配资源并使用管理器级别的调度池,甚至使用具有自己的集合或资源的单独集群管理器,但这不是 Spark 设计的因为,它不受支持,并且总体上会导致脆弱和复杂的设计,其中正确性取决于配置细节、特定的集群管理器选择和总体集群利用率。