Apache spark &引用;因超过内存限制而被纱线杀死的容器。使用10.4 GB的10.4 GB物理内存“;在具有75GB内存的EMR群集上

Apache spark &引用;因超过内存限制而被纱线杀死的容器。使用10.4 GB的10.4 GB物理内存“;在具有75GB内存的EMR群集上,apache-spark,emr,amazon-emr,bigdata,Apache Spark,Emr,Amazon Emr,Bigdata,我在AWS EMR上运行一个5节点的Spark群集,每个大小为m3.xlarge(1个主节点4个从节点)。我成功地运行了一个146Mb的bzip2压缩CSV文件,最终得到了一个完美的聚合结果 现在,我试图在此群集上处理~5GB bzip2 CSV文件,但收到以下错误: 16/11/23 17:29:53警告TaskSetManager:在阶段6.0(TID xxx,xxx.xxx.xxx.compute.internal)中丢失任务49.2:执行器丢失失败(执行器16因一个正在运行的任务而退出)

我在AWS EMR上运行一个5节点的Spark群集,每个大小为m3.xlarge(1个主节点4个从节点)。我成功地运行了一个146Mb的bzip2压缩CSV文件,最终得到了一个完美的聚合结果

现在,我试图在此群集上处理~5GB bzip2 CSV文件,但收到以下错误:

16/11/23 17:29:53警告TaskSetManager:在阶段6.0(TID xxx,xxx.xxx.xxx.compute.internal)中丢失任务49.2:执行器丢失失败(执行器16因一个正在运行的任务而退出)原因:容器因超过内存限制而被纱线杀死。使用10.4 GB的10.4 GB物理内存中的10.4 GB。考虑提升火花。纱线。执行器。内存开销。

我不明白为什么在一个~75GB的集群上会有~10.5GB的内存限制(每3m.xlarge实例15GB)

这是我的EMR配置:

[
 {
  "classification":"spark-env",
  "properties":{

  },
  "configurations":[
     {
        "classification":"export",
        "properties":{
           "PYSPARK_PYTHON":"python34"
        },
        "configurations":[

        ]
     }
  ]
},
{
  "classification":"spark",
  "properties":{
     "maximizeResourceAllocation":"true"
  },
  "configurations":[

  ]
 }
]
根据我所读的内容,设置
maximizeResourceAllocation
属性应该告诉EMR配置Spark以充分利用集群上的所有可用资源。我应该有大约75GB的可用内存。。。那么,为什么会出现~10.5GB内存限制错误? 以下是我正在运行的代码:

def sessionize(raw_data, timeout):
# https://www.dataiku.com/learn/guide/code/reshaping_data/sessionization.html
    window = (pyspark.sql.Window.partitionBy("user_id", "site_id")
              .orderBy("timestamp"))
    diff = (pyspark.sql.functions.lag(raw_data.timestamp, 1)
            .over(window))
    time_diff = (raw_data.withColumn("time_diff", raw_data.timestamp - diff)
                 .withColumn("new_session", pyspark.sql.functions.when(pyspark.sql.functions.col("time_diff") >= timeout.seconds, 1).otherwise(0)))
    window = (pyspark.sql.Window.partitionBy("user_id", "site_id")
              .orderBy("timestamp")
              .rowsBetween(-1, 0))
    sessions = (time_diff.withColumn("session_id", pyspark.sql.functions.concat_ws("_", "user_id", "site_id", pyspark.sql.functions.sum("new_session").over(window))))
    return sessions
def aggregate_sessions(sessions):
    median = pyspark.sql.functions.udf(lambda x: statistics.median(x))
    aggregated = sessions.groupBy(pyspark.sql.functions.col("session_id")).agg(
        pyspark.sql.functions.first("site_id").alias("site_id"),
        pyspark.sql.functions.first("user_id").alias("user_id"),
        pyspark.sql.functions.count("id").alias("hits"),
        pyspark.sql.functions.min("timestamp").alias("start"),
        pyspark.sql.functions.max("timestamp").alias("finish"),
        median(pyspark.sql.functions.collect_list("foo")).alias("foo"),
    )
    return aggregated
 spark_context = pyspark.SparkContext(appName="process-raw-data")
spark_session = pyspark.sql.SparkSession(spark_context)
raw_data = spark_session.read.csv(sys.argv[1],
                                  header=True,
                                  inferSchema=True)
# Windowing doesn't seem to play nicely with TimestampTypes.
#
# Should be able to do this within the ``spark.read.csv`` call, I'd
# think. Need to look into it.
convert_to_unix = pyspark.sql.functions.udf(lambda s: arrow.get(s).timestamp)
raw_data = raw_data.withColumn("timestamp",
                               convert_to_unix(pyspark.sql.functions.col("timestamp")))
sessions = sessionize(raw_data, SESSION_TIMEOUT)
aggregated = aggregate_sessions(sessions)
aggregated.foreach(save_session)
基本上,只有窗口和groupBy来聚合数据

它从这些错误中的一些开始,逐渐停止相同错误数量的增加

我已经尝试使用--conf spark.warn.executor.memoryOverhead运行spark submit,但这似乎也不能解决问题。

请参见

我在一个巨大的集群中遇到了同样的问题,我现在正在工作。将内存添加到辅助进程将无法解决此问题。有时,进程内聚合spark将使用比现有内存更多的内存,spark作业将开始使用堆外内存

一个简单的例子是:

如果您有一个数据集需要
reduceByKey
,它有时会在一个worker中释放比另一个worker更多的数据,并且如果该数据超出了一个worker的内存,则会收到该错误消息

添加选项
spark.warn.executor.memoryOverhead
将有助于您将工作程序使用的内存设置为50%(仅用于测试,看看是否有效,您可以通过更多测试添加更少的内存)

但您需要了解Spark如何处理集群中的内存分配:

  • 更常见的方式是Spark使用75%的机器内存。其余的都是这样
  • Spark在执行过程中内存不足。一部分用于执行,另一部分用于存储。执行用于洗牌、联接、聚合等。存储用于缓存和跨集群传播数据
  • 内存分配的一个好处是,如果在执行过程中不使用缓存,可以设置spark以使用该sotorage空间来执行,以部分避免OOM错误。正如您在spark的文档中所看到的:

    这种设计确保了一些理想的性能。首先,不使用缓存的应用程序可以使用整个执行空间,避免不必要的磁盘溢出。其次,使用缓存的应用程序可以保留一个最小存储空间(R),在该空间中,它们的数据块不会被逐出。最后,这种方法为各种工作负载提供了合理的开箱即用性能,而无需用户了解内存如何在内部分配

    但是我们怎么能利用它呢

    您可以更改一些配置,在工作调用中添加<代码>内存开销>代码>配置,但也考虑添加:<代码> Skas.Mealth.Fiels<代码>更改为0.8或0.85,并将<代码> Skp.Sturys.StultStults<代码>为0.35或0.2。< /P> 其他配置可能会有所帮助,但需要在您的案例中进行检查。对所有这些配置进行Se

    现在,什么对我有帮助

    我有一个集群,有2.5K的工人和2.5TB的RAM。我们面临着和你一样的错误。我们只是将火花、纱线、执行器、存储器的上限增加到2048。并且我们使。当我们给工作打电话时,我们不会为员工设定记忆,而是让火花来决定。我们只是设置了开销

    但是对于我的小型集群的一些测试,更改执行和存储内存的大小。这就解决了问题。

    我感觉到了你的痛苦

    我们也遇到过类似的问题,即纱线上的火花会耗尽内存。我们有5个64GB、16核虚拟机,无论我们将spark.Thread.executor.memoryOverhead设置为什么,我们都无法获得足够的内存来完成这些任务——不管我们给它们多少内存,它们最终都会死掉。这是一个相对直接的Spark应用程序,导致了这种情况的发生

    我们发现虚拟机上的物理内存使用率非常低,但虚拟内存使用率非常高(尽管日志抱怨物理内存)。我们在
    warn site.xml
    中将
    warn.nodemanager.vmem check enabled
    设置为
    false
    ,我们的容器不再被杀死,应用程序似乎按预期工作

    通过进一步研究,我找到了为什么会发生这种情况的答案:

    由于在Centos/RHEL 6上,由于操作系统的行为,虚拟内存的分配非常激烈,因此应禁用虚拟内存检查器或将warn.nodemanager.vmem-pmem-ratio增加到相对较大的值

    该页面有一个指向IBM提供的非常有用的页面的链接:

    总之,glibc>2.10更改了其内存分配。尽管分配的大量虚拟内存并不是世界末日,但它不适用于纱线的默认设置

    您也可以在
    hadoop env.sh
    中将
    MALLOC_ARENA_MAX
    环境变量设置为较低的数值,而不是将
    warn.nodemanager.vmem check enabled
    设置为false
    。此错误报告提供了有用的信息
    [{
    "Classification": "yarn-site", 
      "Properties": {
        "yarn.nodemanager.vmem-check-enabled": "false"
       }
    }]
    
    classification=yarn-site,properties=[yarn.nodemanager.vmem-check-enabled=false]
    
    RWS_PER_PARTITION = 1000
    input_df = spark.write.csv("file_uri", *other_args)
    total_rows = input_df.count()
    original_num_partitions = input_df.getNumPartitions()
    numPartitions = max(total_rows/RWS_PER_PARTITION, original_num_partitions)
    input_df = input_df.repartition(numPartitions)