首页 > 解决方案 > 编写火花作业时是否有理由不使用 SparkContext.getOrCreate?

问题描述

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

有时,在 Spark 作业中执行一系列步骤时,获得一个新的 RDD 比加入旧的 RDD 更容易。

您可以通过调用该SparkContext [getOrCreate][1]方法来做到这一点。

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

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

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

不要使用SparkContext getOrCreate你可以并且应该使用连接来代替

但他没有给出理由。

我的问题是:编写 Spark 作业时是否有理由不使用 SparkContext.getOrCreate?

标签: scalaapache-sparkcassandradatastax

解决方案


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

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

  • 在其最简单的形式中,它不允许您设置特定于作业的属性,并且第二个变体 ( (SparkConf) => SparkContext) 需要传递,这对于将/保持在范围内SparkConf几乎没有改进。SparkContextSparkSession
  • 它可能导致具有“魔术”依赖性的不透明代码。它会影响测试策略和整体代码的可读性。

但是你的问题,特别是:

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

不要使用SparkContext getOrCreate你可以并且应该使用连接来代替

建议您实际上以从未打算使用的方式使用该方法。通过SparkContext在执行程序节点上使用。

val rdd: RDD[_] = ???

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

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

每个 Spark 应用程序都应该有一个,并且只有一个SparkContext在驱动程序上初始化,并且 Apache Spark 开发人员做了很多工作,以防止用户尝试SparkContex在驱动程序之外使用。这不是因为SparkContext它很大,或者不可能序列化,而是因为它是 Spark 计算模型的基本特征。

你可能知道,Spark 中的计算是由一个有向无环依赖图来描述的,它:

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

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

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

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


推荐阅读