我有以下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
我的解释是,第一次运行的垃圾收集会在第二次运行中启动。
我尝试过的事情:
spark._jvm.SparkSession.clearDefaultSession()
,spark._jvm.SparkSession.clearActiveSession()
count
的顺序。这会导致另一个错误:java.io.IOException: Connection reset by peer
(有关类似错误,请参见here)最后一个观察结果:第一个调用旋转了超过100个Spark / YARN执行程序,也许Spark的动态分配机制不喜欢第二个调用实际上是对执行程序有不同要求的新工作?
非常感谢您的帮助!
环境:Cloudera CDH 6.1集群上的Spark 2.3。
+--------+------------+-------+--------+--------------+
| table | # rows |# cols |# files | raw size |
+--------+------------+-------+--------+--------------+
| table1 | 5660970439 | 46 | 49167 | 228876171398 |
| table2 | 5656000217 | 52 | 80000 | 518996700170 |
+--------+------------+-------+--------+--------------+
count()
旋转大约150个执行程序,充分利用了当前可用的内存资源答案 0 :(得分:0)
让问题沉迷了几天之后,我只是尝试增加 driver 内存:
spark2-submit --master yarn --deploy-mode client --driver-memory 4G minimal_example.py
也许决定因素是我的应用程序以client
模式启动。显然,即使驱动程序本身仅收到简单的df.count()
的结果,对大量执行程序的管理(及其删除)仍会占用大量内存。