Dataproc Pyspark作业仅在一个节点上运行

时间:2016-06-02 10:38:34

标签: python-2.7 hadoop pyspark google-cloud-dataproc

我的问题是我的pyspark作业并行运行。

代码和数据格式:
我的PySpark看起来像这样(显然是简化的):

class TheThing:
    def __init__(self, dInputData, lDataInstance):
        # ...
    def does_the_thing(self):
        """About 0.01 seconds calculation time per row"""
        # ...
        return lProcessedData

#contains input data pre-processed from other RDDs
#done like this because one RDD cannot work with others inside its transformation
#is about 20-40MB in size
#everything in here loads and processes from BigQuery in about 7 minutes
dInputData = {'dPreloadedData': dPreloadedData}

#rddData contains about 3M rows
#is about 200MB large in csv format
#rddCalculated is about the same size as rddData
rddCalculated = (
    rddData
        .map(
            lambda l, dInputData=dInputData: TheThing(dInputData, l).does_the_thing()
        )
)

llCalculated = rddCalculated.collect()
#save as csv, export to storage

在Dataproc群集上运行:
群集是通过Dataproc UI创建的 工作是这样执行的:
gcloud --project <project> dataproc jobs submit pyspark --cluster <cluster_name> <script.py>

我通过用户界面started like this观察了工作状态。浏览它时,我注意到我的工作节点中只有一个(看似随机)正在做任何事情。所有其他人都完全闲着。

PySpark的全部意义是并行运行这个东西,显然不是这样。我已经在各种群集配置中运行这些数据,最后一个是庞大的,这是我注意到它的奇异节点使用。因此,为什么我的工作需要很长时间才能完成,而时间似乎与簇大小无关。

使用较小数据集的所有测试在本地计算机和群集上都没有问题。我真的只需要升级。

修改
我改变了 llCalculated = rddCalculated.collect()
#... save to csv and export

rddCalculated.saveAsTextFile("gs://storage-bucket/results")

并且只有一个节点仍在继续工作。

1 个答案:

答案 0 :(得分:2)

根据您是从GCS还是HDFS加载rddData,默认拆分大小可能是64MB或128MB,这意味着您的200MB数据集只有2-4个分区。 Spark之所以这样做是因为典型的基本数据并行任务足够快地通过数据流动,64MB-128MB意味着可能需要数十秒的处理时间,因此分割成较小的并行块没有任何好处,因为启动开销会占主导地位。 / p>

在您的情况下,由于您加入其他数据集并且可能对每条记录执行相当重量级的计算,因此听起来每MB处理时间要高得多。因此,您需要更多的分区,否则无论您拥有多少个节点,Spark都不会知道分成2-4个以上的工作单元(这些单元也可能会被打包到一个单元中)机器,如果每台机器有多个核心)。

所以你只需要致电repartition

rddCalculated = (
    rddData
        .repartition(200)
        .map(
            lambda l, dInputData=dInputData: TheThing(dInputData, l).does_the_thing()
        )
)

或者将重新分配添加到前一行:

rddData = rddData.repartition(200)

如果你在阅读时重新分配,你可能会有更好的效率:

rddData = sc.textFile("gs://storage-bucket/your-input-data", minPartitions=200)