一个应用程序可以有多少个SparkSession?

时间:2017-12-08 23:49:10

标签: apache-spark apache-spark-sql yarn

我发现当Spark运行时,表的大小(通过Joins)增长,火花执行器最终会耗尽内存并导致整个系统崩溃。即使我尝试将临时结果写入Hive表(在HDFS上),系统仍然没有释放大量内存,并且我的整个系统在大约130个连接后崩溃。

然而,通过实验,我意识到如果我将问题分解成更小的部分,将临时结果写入hive表,并停止/启动Spark会话(和spark上下文),那么系统的资源将被释放。我能够使用这种方法加入超过1,000列。

但我无法找到任何文档来理解这是否被认为是一种好的做法(我知道你不应该同时获得多个会话)。大多数系统在开始时获取会话并在最后关闭它。我也可以将应用程序分解为较小的应用程序,并使用像Oozie这样的驱动程序在Yarn上安排这些较小的应用程序。但是这种方法会在每个阶段启动和停止JVM,这似乎有点重量级。

所以我的问题:在单个spark应用程序运行期间不断启动/停止spark会话以释放系统资源是不好的做法吗?

但是,您能详细说明单个JVM上单个SparkContext的含义吗?我可以致电sparkSession.sparkContext().stop(),还stop SparkSession。然后,我创建了一个新的SparkSession并使用了新的sparkContext。没有抛出任何错误。

我也可以在JavaSparkPi上使用它,没有任何问题。

我已经在yarn-clientlocal火花安装中对此进行了测试。

停止火花环境究竟做了什么,为什么一旦你停止了它就不能创建一个新的?

1 个答案:

答案 0 :(得分:7)

TL; DR 您可以根据需要设置SparkSession个。{/ p>

您可以在一个JVM上只有一个SparkContext,但SparkSession的数量几乎是无限的。

  

但是,您能详细说明单个JVM上单个SparkContext的含义吗?

这意味着在Spark应用程序的生命周期中的任何给定时间,驱动程序只能是一个且只有一个,这反过来意味着该JVM上只有一个SparkContext可用。

Spark应用程序的驱动程序是SparkContext所在的位置(或者相反,而SparkContext定义了驱动程序 - 区别非常模糊)。

一次只能有一个SparkContext。虽然你可以根据需要多次启动和停止它,但我记得有一个问题,说你不应该关闭SparkContext,除非你完成了Spark(通常发生在你的最后) Spark应用程序)。

换句话说,在Spark应用程序的整个生命周期内只有一个SparkContext

有一个关于多个SparkSession的类似问题What's the difference between SparkSession.sql vs Dataset.sqlContext.sql?,可以更清楚地了解您为什么要参加两个或更多会话。

  

我可以致电sparkSession.sparkContext().stop(),还stop SparkSession

所以?这与我说的如何相矛盾?!您停止了JVM上唯一可用的SparkContext。没有大碍。你可以,但这只是“你只能在一个JVM上只有一个SparkContext的一部分”,不是吗?

SparkSession仅仅是SparkContext的包装器,可以在Spark Core的RDD之上提供Spark SQL的结构化/ SQL功能。

从Spark SQL开发人员的角度来看,SparkSession的目的是成为查询实体的命名空间,例如查询使用的表,视图或函数(如DataFrames,Datasets或SQL)和Spark属性(每个SparkSession可以有不同的值。

如果您希望为不同的数据集使用相同的(临时)表名,那么创建两个SparkSession将是我认为推荐的方式。

我刚刚开发了一个示例来展示整个阶段的codegen如何在Spark SQL中工作,并创建了以下功能,只需关闭该功能。

// both where and select operators support whole-stage codegen
// the plan tree (with the operators and expressions) meets the requirements
// That's why the plan has WholeStageCodegenExec inserted
// You can see stars (*) in the output of explain
val q = Seq((1,2,3)).toDF("id", "c0", "c1").where('id === 0).select('c0)
scala> q.explain
== Physical Plan ==
*Project [_2#89 AS c0#93]
+- *Filter (_1#88 = 0)
   +- LocalTableScan [_1#88, _2#89, _3#90]

// Let's break the requirement of having up to spark.sql.codegen.maxFields
// I'm creating a brand new SparkSession with one property changed
val newSpark = spark.newSession()
import org.apache.spark.sql.internal.SQLConf.WHOLESTAGE_MAX_NUM_FIELDS
newSpark.sessionState.conf.setConf(WHOLESTAGE_MAX_NUM_FIELDS, 2)

scala> println(newSpark.sessionState.conf.wholeStageMaxNumFields)
2

// Let's see what's the initial value is
// Note that I use spark value (not newSpark)
scala> println(spark.sessionState.conf.wholeStageMaxNumFields)
100

import newSpark.implicits._
// the same query as above but created in SparkSession with WHOLESTAGE_MAX_NUM_FIELDS as 2
val q = Seq((1,2,3)).toDF("id", "c0", "c1").where('id === 0).select('c0)

// Note that there are no stars in the output of explain
// No WholeStageCodegenExec operator in the plan => whole-stage codegen disabled
scala> q.explain
== Physical Plan ==
Project [_2#122 AS c0#126]
+- Filter (_1#121 = 0)
   +- LocalTableScan [_1#121, _2#122, _3#123]
  

然后我创建了一个新的SparkSession并使用了新的SparkContext。没有抛出任何错误。

同样,这与我所说的单个SparkContext可用的内容有何矛盾?我很好奇。

  

停止火花环境究竟做了什么,为什么一旦停止火花背景就不能创建一个新的?

您不能再使用它来运行Spark作业(处理大型和分布式数据集),这正是您首先使用Spark的原因,不是吗?

尝试以下方法:

  1. 停止SparkContext
  2. 使用Spark Core的RDD或Spark SQL的数据集API执行任何处理
  3. 例外?对!请记住,你关闭了Spark的“大门”,那么你怎么能期望进入里面?! :)