在一个Spark作业中运行两个操作时,“超出了GC开销限制”;单独运行没问题

时间:2019-03-20 11:02:19

标签: python apache-spark pyspark apache-spark-sql cloudera-cdh

我有以下Spark SQL代码,用于检查大型表(数十亿行)中是否缺少某些日期:

spark = SparkSession.builder \
    .master("yarn") \
    .appName("minimal_example") \
    .config('spark.submit.deployMode', 'client') \
    .getOrCreate()

SQL = '''
select distinct
  substr(entrydate, 1, 10) as datum,
  1 as in_table
from {table}
where entrydate >= '{datum}'
'''

print("RUN1")
df1 = spark.sql(SQL.format(datum='2017-01-01', table='table1'))
c1 = df1.count()
print("count1: ", c1)

print("RUN2")
df2 = spark.sql(SQL.format(datum='2017-01-01', table='table2'))
c2 = df2.count()
print("count2: ", c2)

本质上,该函数只是从表列中获取不同的日期。

现在我无法缠住的部分:

  • 每次对count()的调用运行正常
  • 当我将每个呼叫作为单独的spark-submit工作运行时,效果很好
  • 但是,如果像上述那样连续运行它们,则第二次运行会产生以下错误:
py4j.protocol.Py4JJavaError: An error occurred while calling o150.sql.
: java.util.concurrent.ExecutionException: java.io.IOException: com.google.protobuf.ServiceException: java.lang.OutOfMemoryError: GC overhead limit exceeded

我的解释是,第一次运行的垃圾收集会在第二次运行中启动。

我尝试过的事情:

  1. 在每次迭代开始时调用spark.clearCache()
  2. 在每次迭代开始时调用spark._jvm.SparkSession.clearDefaultSession()spark._jvm.SparkSession.clearActiveSession()
  3. 查看Spark Web UI并尝试从DAG和“存储”选项卡(后一个不显示任何内容)中获取意义
  4. 更改两个count的顺序。这会导致另一个错误:java.io.IOException: Connection reset by peer(有关类似错误,请参见here

最后一个观察结果:第一个调用旋转了超过100个Spark / YARN执行程序,也许Spark的动态分配机制不喜欢第二个调用实际上是对执行程序有不同要求的新工作?

非常感谢您的帮助!

环境:Cloudera CDH 6.1集群上的Spark 2.3。

编辑:更多详细信息

  • 这些表将作为Parquet文件持久保存在HDFS中,并且状态为:
   +--------+------------+-------+--------+--------------+
   | table  |   # rows   |# cols |# files |   raw size   |
   +--------+------------+-------+--------+--------------+
   | table1 | 5660970439 |    46 |  49167 | 228876171398 |
   | table2 | 5656000217 |    52 |  80000 | 518996700170 |
   +--------+------------+-------+--------+--------------+
  • 内存设置:YARN上具有动态分配的Spark,最小执行程序内存为1GB,最大为72GB,群集总内存为〜300GB。
  • 第一个count()旋转大约150个执行程序,充分利用了当前可用的内存资源

1 个答案:

答案 0 :(得分:0)

让问题沉迷了几天之后,我只是尝试增加 driver 内存:

spark2-submit --master yarn --deploy-mode client --driver-memory 4G minimal_example.py

也许决定因素是我的应用程序以client模式启动。显然,即使驱动程序本身仅收到简单的df.count()的结果,对大量执行程序的管理(及其删除)仍会占用大量内存。