Apache spark 用于rdd.saveAsNewApiHadoop文件和解决方法的Spark驱动程序内存
我对一个特殊的spark方法,Apache spark 用于rdd.saveAsNewApiHadoop文件和解决方法的Spark驱动程序内存,apache-spark,pyspark,
elasticsearch-hadoop,Apache Spark,Pyspark,
elasticsearch Hadoop,我对一个特殊的spark方法,saveAsNewAPIHadoopFile有问题。上下文是我正在使用pyspark,将1k、10k、50k、500k、1m记录的RDD索引到ElasticSearch(ES)中 由于各种原因,Spark上下文在2gb驱动程序和单个2gb执行器的情况下动力不足 直到500k左右,我才遇到java堆大小的问题。将spark.driver.memory增加到大约4gb,我就能够索引更多。然而,这项工作的时间是有限制的,我们希望索引超过500k、1m、5m、20m的记录
saveAsNewAPIHadoopFile
有问题。上下文是我正在使用pyspark,将1k、10k、50k、500k、1m记录的RDD索引到ElasticSearch(ES)中
由于各种原因,Spark上下文在2gb驱动程序和单个2gb执行器的情况下动力不足
直到500k左右,我才遇到java堆大小的问题。将spark.driver.memory
增加到大约4gb,我就能够索引更多。然而,这项工作的时间是有限制的,我们希望索引超过500k、1m、5m、20m的记录
由于各种原因,也不得不使用pyspark。瓶颈和断点似乎是一个火花阶段,名为take at SerDeUtil.scala:233
,即无论RDD有多少个分区,它都会下降到一个,我假设是收集分区并准备索引的驱动程序
现在-我想知道,在这种限制条件下,是否有一种有效的方法可以继续使用如下方法:
to_index_rdd.saveAsNewAPIHadoopFile(
path='-',
outputFormatClass="org.elasticsearch.hadoop.mr.EsOutputFormat",
keyClass="org.apache.hadoop.io.NullWritable",
valueClass="org.elasticsearch.hadoop.mr.LinkedMapWritable",
conf={
"es.resource":"%s/record" % index_name,
"es.nodes":"192.168.45.10:9200",
"es.mapping.exclude":"temp_id",
"es.mapping.id":"temp_id",
}
)
为了寻求一个好的解决办法,我不妨晾一些脏衣服。我有一个非常低效的解决方法,它使用zipWithIndex
将RDD分块,并将这些子集发送到上面的索引函数。看起来有点像这样:
def index_chunks_to_es(spark=None, job=None, kwargs=None, rdd=None, chunk_size_limit=10000):
# zip with index
zrdd = rdd.zipWithIndex()
# get count
job.update_record_count(save=False)
count = job.record_count
# determine number of chunks
steps = count / chunk_size_limit
if steps % 1 != 0:
steps = int(steps) + 1
# evenly distribute chunks, while not exceeding chunk_limit
dist_chunk_size = int(count / steps) + 1
# loop through steps, appending subset to list for return
for step in range(0, steps):
# determine bounds
lower_bound = step * dist_chunk_size
upper_bound = (step + 1) * dist_chunk_size
print(lower_bound, upper_bound)
# select subset
rdd_subset = zrdd.filter(lambda x: x[1] >= lower_bound and x[1] < upper_bound).map(lambda x: x[0])
# index to ElasticSearch
ESIndex.index_job_to_es_spark(
spark,
job=job,
records_df=rdd_subset.toDF(),
index_mapper=kwargs['index_mapper']
)
更新#3
下面是SerDeUtil.scala:233上运行的take的DAG可视化:
对于更小的作业(大约1k行),saveAsNewAPIHadoopFile的DAG是一个DAG,因为500k行尝试从未实际触发,因为上面的SerDeUtil
阶段似乎触发了更大RDD的java堆大小问题:
我仍然有点困惑,为什么这可以解决问题,但它确实解决了。当使用spark.jdbc.read
从MySQL读取行时,通过传递边界,生成的RDD似乎以这样一种方式进行分区,saveAsNewAPIHadoopFile
对于大型RDD是成功的
为DB行提供Django模型,以便获得第一列和最后一列ID:
records = records.order_by('id')
start_id = records.first().id
end_id = records.last().id
然后,将它们传递给spark.read.jdbc
:
sqldf = spark.read.jdbc(
settings.COMBINE_DATABASE['jdbc_url'],
'core_record',
properties=settings.COMBINE_DATABASE,
column='id',
lowerBound=bounds['lowerBound'],
upperBound=bounds['upperBound'],
numPartitions=settings.SPARK_REPARTITION
)
RDD的调试字符串显示原始RDD现在有10
分区:
(32) PythonRDD[11] at RDD at PythonRDD.scala:48 []
| MapPartitionsRDD[10] at javaToPython at NativeMethodAccessorImpl.java:-2 []
| MapPartitionsRDD[9] at javaToPython at NativeMethodAccessorImpl.java:-2 []
| ShuffledRowRDD[8] at javaToPython at NativeMethodAccessorImpl.java:-2 []
+-(10) MapPartitionsRDD[7] at javaToPython at NativeMethodAccessorImpl.java:-2 []
| MapPartitionsRDD[6] at javaToPython at NativeMethodAccessorImpl.java:-2 []
| JDBCRDD[5] at javaToPython at NativeMethodAccessorImpl.java:-2 []
我的理解是,您可以看到,在问题的调试字符串和上面的这个字符串中,都有一个手动/显式重新划分到32
,我认为这足以减轻saveAsNewAPIHadoopFile
调用的内存压力,但显然是数据帧(变成了RDD)从最初的spark.jdbc.read
甚至在下游都很重要。对ES进行索引是一个更大的应用程序的一个重要但很小的部分,它利用spark进行其他处理。在小型计算机上开发以实现高效的内存管理,但根据应用程序工作的数据集,部署将有更大的计算机(更大的驱动程序内存、更多的执行器等)。我将RDD的调试字符串作为问题的更新。
(32) PythonRDD[11] at RDD at PythonRDD.scala:48 []
| MapPartitionsRDD[10] at javaToPython at NativeMethodAccessorImpl.java:-2 []
| MapPartitionsRDD[9] at javaToPython at NativeMethodAccessorImpl.java:-2 []
| ShuffledRowRDD[8] at javaToPython at NativeMethodAccessorImpl.java:-2 []
+-(10) MapPartitionsRDD[7] at javaToPython at NativeMethodAccessorImpl.java:-2 []
| MapPartitionsRDD[6] at javaToPython at NativeMethodAccessorImpl.java:-2 []
| JDBCRDD[5] at javaToPython at NativeMethodAccessorImpl.java:-2 []