Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/apache-spark/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/xslt/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Apache spark Spark:控制分区以减少洗牌_Apache Spark_Optimization_Partitioning - Fatal编程技术网

Apache spark Spark:控制分区以减少洗牌

Apache spark Spark:控制分区以减少洗牌,apache-spark,optimization,partitioning,Apache Spark,Optimization,Partitioning,为了减少特定管道上的混洗量,我正在尝试在Spark中对数据帧进行分区的不同方法 这是我正在处理的数据框架,它包含4+十亿行和80列: +-----+-------------------+-----------+ | msn| timestamp| Flight_Id | +-----+-------------------+-----------+ |50020|2020-08-22 19:16:00| 72.0| |50020|2020-08-22 19:15

为了减少特定管道上的混洗量,我正在尝试在Spark中对数据帧进行
分区的不同方法

这是我正在处理的数据框架,它包含4+十亿行和80列:

+-----+-------------------+-----------+
|  msn|          timestamp| Flight_Id |
+-----+-------------------+-----------+
|50020|2020-08-22 19:16:00|       72.0|
|50020|2020-08-22 19:15:00|       84.0|
|50020|2020-08-22 19:14:00|       96.0|
|50020|2020-08-22 19:13:00|       84.0|
|50020|2020-08-22 19:12:00|       84.0|
|50020|2020-08-22 19:11:00|       84.0|
|50020|2020-08-22 19:10:00|       84.0|
|50020|2020-08-22 19:09:00|       84.0|
|50020|2020-08-22 19:08:00|       84.0|
|50020|2020-08-22 19:07:00|       84.0|
|50020|2020-08-22 19:06:00|       84.0|
|50020|2020-08-22 19:05:00|       84.0|
|50020|2020-08-22 19:04:00|       84.0|
|50020|2020-08-22 19:03:00|       84.0|
|50020|2020-08-22 19:02:00|       84.0|
|50020|2020-08-22 19:01:00|       84.0|
|50020|2020-08-22 19:00:00|       84.0|
|50020|2020-08-22 18:59:00|       84.0|
|50020|2020-08-22 18:58:00|       84.0|
|50020|2020-08-22 18:57:00|       84.0|
+-----+-------------------+-----------+
这表示不同飞机(总共41架飞机)的时间序列集合。 我对这些数据只做了两件事:

  • 使用由
    MSN
    flight\u ID
    划分的窗口,并使用
    order by
    by
    timestamp
    过滤以保持每次航班的最后30分钟
  • 在剩下的列上,计算
    mean
    stdev
    并标准化数据
  • 我有32个执行器,每个执行器有12g内存,作业在运行30小时后崩溃,并显示以下消息:

    The driver running the job crashed, ran out of memory, or otherwise became unresponsive while it was running.
    
    查看查询计划,我注意到我有300多个步骤,其中60多个步骤涉及洗牌(所有步骤物理计划看起来完全相同):

    下面是代码的一部分,我将数据从存储在其中的数据池中拉到一起。 仅供参考,这是通过使用名为
    FoundryTS
    的库的自定义API实现的。重要的是,在调用
    to_dataframe()
    方法之前,不会收集任何数据。我在每个
    msn
    上循环,以避免调用过大,然后我将所有数据帧与
    unionByName

    # Loop over MSN to extract timeseries
            df = []
            for msn in msn_range:
                search_results = (SeriesMetadata.M_REPORT_NUMBER == report_number) & (SeriesMetadata.M_AIRCRAFT == msn)
    
                # Create the intervals to split TimeSeries extract by flight for each MSN
                Start_int = list(df1.where(F.col("msn") == msn).select("Start").toPandas()["Start"])
                End_int = list(df1.where(F.col("msn") == msn).select("End").toPandas()["End"])
                flight_id = list(df1.where(F.col("msn") == msn).select("id_cmsReport").toPandas()["id_cmsReport"])
    
                flights_interval = [Interval(
                    start, end, name=flight_Id
                    ) for start, end, flight_Id in zip(
                    Start_int, End_int, flight_id
                    )]
    
                """ Collect all the series in a node collections """
                output = fts.search.series(
                    search_results,
                    object_types=["export-control-us-ear99-a220-dal-airline-series"])\
                    .map_by(FF.interpolate(
                        before='nearest',
                        internal='nearest',
                        after='nearest',
                        frequency=frequency,
                        rename_columns_by=lambda x: x.metadata["parameter_id"] + "_" + x.metadata["report_number"]),
                        keys='msn') \
                    .map_intervals(flights_interval, interval_name='Flight_Id_Int')\
                    .map(FF.time_range(period_start, period_end))\
                    .to_dataframe()  # !!!!  numPartitions=32  Foundry Doc : #partition = #executors see if it triggers OOM error
    
                df.append(output)
    
            output = df[0]
            for df in df[1:]:
                output = output.unionByName(df)  # Same as union but matches name instead of columns order.
    
            # Repartition by msn to improve latter calculation
            N = len(msn_range)
            output.repartition(N, 'msn')
    
    运行作业的驱动程序在运行时崩溃、内存不足或无响应

    您需要解决的第一个问题是增加驱动程序(而不是执行器)的内存。spark中的默认驱动程序内存通常很低,在许多查询中都会崩溃

    “我的问题是如何以及在代码中的何处重新分区”

    Spark已经完成了根据需要添加重新分区的工作。很有可能,只有在执行中途手动重新分区数据时,您才会创建额外的工作。一个潜在的优化是将数据存储在带扣的表中,但这只会潜在地删除第一次交换,并且仅当您的带扣列完全匹配时这是第一次交换的哈希分区

    “查看查询计划,我注意到我有300多个步骤”

    您上面描述的不需要300个步骤。这里似乎有点不对劲。您的优化逻辑计划是什么样子的?mean和std应该只需要扫描->部分agg->交换->最终agg。在您提供的查询计划中,您似乎有意只查看最后1600个数据点,而不是最后30m.D你的意思是做一个窗口函数,而不是一个简单的聚合(又名group by)

    编辑:

    对于msn_范围内的msn:

    在我看来,这可能是你的问题的一部分。这个for循环会导致执行计划非常大,这可能是你在驱动程序上遇到OOM问题的原因。你可能可以将其转换为对spark更友好的东西,而不需要对驱动程序做太多的工作,将forloop转换为spark。并行化(…).map(/your code/)

    运行作业的驱动程序在运行时崩溃、内存不足或没有响应

    您需要解决的第一个问题是增加驱动程序(而不是执行器)的内存。spark中的默认驱动程序内存通常很低,在许多查询中都会崩溃

    “我的问题是如何以及在代码中的何处重新分区”

    Spark已经完成了根据需要添加重新分区的工作。很有可能,只有在执行中途手动重新分区数据时,您才会创建额外的工作。一个潜在的优化是将数据存储在带扣的表中,但这只会潜在地删除第一次交换,并且仅当您的带扣列完全匹配时这是第一次交换的哈希分区

    “查看查询计划,我注意到我有300多个步骤”

    您上面描述的不需要300个步骤。这里似乎有点不对劲。您的优化逻辑计划是什么样子的?mean和std应该只需要扫描->部分agg->交换->最终agg。在您提供的查询计划中,您似乎有意只查看最后1600个数据点,而不是最后30m.D你的意思是做一个窗口函数,而不是一个简单的聚合(又名group by)

    编辑:

    对于msn_范围内的msn:


    在我看来,这可能是你的问题的一部分。这个for循环会导致执行计划非常大,这可能是你在驱动程序上遇到OOM问题的原因。你可能可以将其转换为对spark更友好的东西,而不需要对驱动程序做太多的工作,将forloop转换为spark。并行化(…).map(/your code/)

    对于那些可能有帮助的人

    以下是我在分区中出错的地方:

  • .to_dataframe()
    :默认情况下,在我们的云平台Spark中创建200个分区。因此,通过在40
    msn
    上循环,我生成了40 x 200分区。我最终需要管理很多小任务
  • .repartition()
    :由于我在
    msn
    上使用了
    窗口和
    partitionBy
    ,我认为使用
    msn
    重新分区将加快这一步。但它引入了分区的完全洗牌
  • 结果:根据Spark Job Tracker和>55k的任务,59 GB的随机写入。任务占用了一些开销,这可以解释驱动程序崩溃的原因

    我做了什么使它工作:

  • 我去掉了
    窗口
    函数
  • 在我从DataLake获取数据之前,通过在过程的早期进行过滤。我直接提取了我所需的飞行部分。因此,物理计划中的
    交换分区
    更少,用于完全相同的部分

    以下是更新的物理计划:

    AdaptiveSparkPlan(isFinalPlan=false)
    +- CollectLimit 1
       +- HashAggregate(keys=[], functions=[avg(3565000_421#213), stddev_samp(3565000_421#213)], output=[avg(3565000_421)#10246, stddev_samp(3565000_421)#10255])
          +- ShuffleQueryStage 0
             +- Exchange SinglePartition, true
                +- *(43) HashAggregate(keys=[], functions=[partial_avg(3565000_421#213), partial_stddev_samp(3565000_421#213)], output=[sum#10317, count#10318L, n#10261, avg#10262, m2#10263])
                   +- Union
                      :- *(1) Project [3565000_421#213]
                      :  +- *(1) Scan ExistingRDD[msn#208,Flight_Id_Int#209,Flight_Id_Int.start#210L
    
  • 我减少了分区的数量:
  • # Loop over MSN to extract timeseries
            df = []
            for msn in msn_range:
                search_results = (SeriesMetadata.M_REPORT_NUMBER == report_number) & (SeriesMetadata.M_AIRCRAFT == msn)
    
                # Create the intervals to split TimeSeries extract by flight for each MSN
                Start_int = list(df1.where(F.col("msn") == msn).select("Start").toPandas()["Start"])
                End_int = list(df1.where(F.col("msn") == msn).select("End").toPandas()["End"])
                flight_id = list(df1.where(F.col("msn") == msn).select("id_cmsReport").toPandas()["id_cmsReport"])
    
                flights_interval = [Interval(
                    start, end, name=flight_Id
                    ) for start, end, flight_Id in zip(
                    Start_int, End_int, flight_id
                    )]
    
                """ Collect all the series in a node collections """
                output = fts.search.series(
                    search_results,
                    object_types=["export-control-us-ear99-a220-dal-airline-series"])\
                    .map_by(FF.interpolate(
                        before='nearest',
                        internal='nearest',
                        after='nearest',
                        frequency=frequency,
                        rename_columns_by=lambda x: x.metadata["parameter_id"] + "_" + x.metadata["report_number"]),
                        keys='msn') \
                    .map_intervals(flights_interval, interval_name='Flight_Id_Int')\
                    .map(FF.time_range(period_start, period_end))\
                    .to_dataframe()  # !!!!  numPartitions=32  Foundry Doc : #partition = #executors see if it triggers OOM error
    
                df.append(output)
    
            output = df[0]
            for df in df[1:]:
                output = output.unionByName(df)  # Same as union but matches name instead of columns order.
    
            # Repartition by msn to improve latter calculation
            N = len(msn_range)
            output.repartition(N, 'msn')
    
    AdaptiveSparkPlan(isFinalPlan=false)
    +- CollectLimit 1
       +- HashAggregate(keys=[], functions=[avg(3565000_421#213), stddev_samp(3565000_421#213)], output=[avg(3565000_421)#10246, stddev_samp(3565000_421)#10255])
          +- ShuffleQueryStage 0
             +- Exchange SinglePartition, true
                +- *(43) HashAggregate(keys=[], functions=[partial_avg(3565000_421#213), partial_stddev_samp(3565000_421#213)], output=[sum#10317, count#10318L, n#10261, avg#10262, m2#10263])
                   +- Union
                      :- *(1) Project [3565000_421#213]
                      :  +- *(1) Scan ExistingRDD[msn#208,Flight_Id_Int#209,Flight_Id_Int.start#210L