纱线容器 运行 内存不足

Yarn container is running out of memory

我的纱线容器运行内存不足: 这个特定的容器 运行 是一个 Apache-Spark 驱动程序节点。

我不明白的部分:我将驱动程序的堆大小限制为 512MB(您可以在下面的错误消息中看到这一点)。但是 yarn 容器抱怨内存>1GB(另见下面的消息)。您可以使用 Xmx512m 验证 yarn 正在启动 java is 运行。我的容器设置为 1GB 内存,增量为 0.5GB。此外,我托管纱线容器的物理机器每个都有 32GB。我通过 SSH 连接到其中一台物理机器,发现它有很多可用内存...

另一个奇怪的事情是 java 没有抛出 OutOfMemory 异常。当我查看驱动程序日志时,我发现它最终从 yarn 获取了一个 SIGTERM,并正常关闭。如果 Yarn 中的 java 进程超过 512MB,我不应该在 Java 尝试从 yarn 分配 1GB 之前得到 OutOfMemory 异常吗?

我还尝试了 运行 1024m 堆。那一次,容器崩溃了 1.5GB。这一直发生。很明显,容器有能力在 1GB 限制之外再分配 0.5GB。 (非常合乎逻辑,因为物理机有 30GB 的空闲内存)

在 java 旁边的 YARN 容器中是否还有其他东西可能会占用额外的 512MB?

Im 运行ning CDH 5.4.1 和 Yarn 上的 Apache spark。集群上的 java 版本也升级到了 oracle Java8。我看到有人说java8中默认的maxPermSize被改了,但我很难相信它会占用512MB...

纱线错误信息:

Diagnostics: Container [pid=23335,containerID=container_1453125563779_0160_02_000001] is running beyond physical memory limits. Current usage: 1.0 GB of 1 GB physical memory used; 2.6 GB of 2.1 GB virtual memory used. Killing container.
Dump of the process-tree for container_1453125563779_0160_02_000001 :
    |- PID PPID PGRPID SESSID CMD_NAME USER_MODE_TIME(MILLIS) SYSTEM_TIME(MILLIS) VMEM_USAGE(BYTES) RSSMEM_USAGE(PAGES) FULL_CMD_LINE
    |- 23335 23333 23335 23335 (bash) 1 0 11767808 432 /bin/bash -c LD_LIBRARY_PATH=/opt/cloudera/parcels/CDH-5.4.1-1.cdh5.4.1.p0.6/lib/hadoop/lib/native::/opt/cloudera/parcels/CDH-5.4.1-1.cdh5.4.1.p0.6/lib/hadoop/lib/native /usr/lib/jvm/java-8-oracle/bin/java -server -Xmx512m -Djava.io.tmpdir=/var/yarn/nm/usercache/hdfs/appcache/application_1453125563779_0160/container_1453125563779_0160_02_000001/tmp '-Dspark.eventLog.enabled=true' '-Dspark.executor.memory=512m' '-Dspark.executor.extraClassPath=/opt/cloudera/parcels/CDH/lib/hbase/lib/htrace-core-3.1.0-incubating.jar' '-Dspark.yarn.am.extraLibraryPath=/opt/cloudera/parcels/CDH-5.4.1-1.cdh5.4.1.p0.6/lib/hadoop/lib/native' '-Dspark.executor.extraLibraryPath=/opt/cloudera/parcels/CDH-5.4.1-1.cdh5.4.1.p0.6/lib/hadoop/lib/native' '-Dspark.shuffle.service.enabled=true' '-Dspark.yarn.jar=local:/opt/cloudera/parcels/CDH-5.4.1-1.cdh5.4.1.p0.6/lib/spark/assembly/lib/spark-assembly-1.3.0-cdh5.4.1-hadoop2.6.0-cdh5.4.1.jar' '-Dspark.app.name=not_telling-1453479057517' '-Dspark.shuffle.service.port=7337' '-Dspark.driver.extraClassPath=/etc/hbase/conf:/opt/cloudera/parcels/CDH/lib/hbase/lib/htrace-core-3.1.0-incubating.jar' '-Dspark.serializer=org.apache.spark.serializer.KryoSerializer' '-Dspark.yarn.historyServer.address=http://XXXX-cdh-dev-cdh-node2:18088' '-Dspark.driver.extraLibraryPath=/opt/cloudera/parcels/CDH-5.4.1-1.cdh5.4.1.p0.6/lib/hadoop/lib/native' '-Dspark.eventLog.dir=hdfs://XXXX-cdh-dev-cdh-node1:8020/user/spark/applicationHistory' '-Dspark.master=yarn-cluster' -Dspark.yarn.app.container.log.dir=/var/log/hadoop-yarn/container/application_1453125563779_0160/container_1453125563779_0160_02_000001 org.apache.spark.deploy.yarn.ApplicationMaster --class 'not_telling' --jar file:/home/cloud-user/temp/not_telling.jar --arg '--conf' --arg 'spark.executor.extraClasspath=/opt/cloudera/parcels/CDH/jars/htrace-core-3.0.4.jar' --executor-memory 512m --executor-cores 4 --num-executors  10 1> /var/log/hadoop-yarn/container/application_1453125563779_0160/container_1453125563779_0160_02_000001/stdout 2> /var/log/hadoop-yarn/container/application_1453125563779_0160/container_1453125563779_0160_02_000001/stderr 
    |- 23338 23335 23335 23335 (java) 95290 10928 2786668544 261830 /usr/lib/jvm/java-8-oracle/bin/java -server -Xmx512m -Djava.io.tmpdir=/var/yarn/nm/usercache/hdfs/appcache/application_1453125563779_0160/container_1453125563779_0160_02_000001/tmp -Dspark.eventLog.enabled=true -Dspark.executor.memory=512m -Dspark.executor.extraClassPath=/opt/cloudera/parcels/CDH/lib/hbase/lib/htrace-core-3.1.0-incubating.jar -Dspark.yarn.am.extraLibraryPath=/opt/cloudera/parcels/CDH-5.4.1-1.cdh5.4.1.p0.6/lib/hadoop/lib/native -Dspark.executor.extraLibraryPath=/opt/cloudera/parcels/CDH-5.4.1-1.cdh5.4.1.p0.6/lib/hadoop/lib/native -Dspark.shuffle.service.enabled=true -Dspark.yarn.jar=local:/opt/cloudera/parcels/CDH-5.4.1-1.cdh5.4.1.p0.6/lib/spark/assembly/lib/spark-assembly-1.3.0-cdh5.4.1-hadoop2.6.0-cdh5.4.1.jar -Dspark.app.name=not_tellin-1453479057517 -Dspark.shuffle.service.port=7337 -Dspark.driver.extraClassPath=/etc/hbase/conf:/opt/cloudera/parcels/CDH/lib/hbase/lib/htrace-core-3.1.0-incubating.jar -Dspark.serializer=org.apache.spark.serializer.KryoSerializer -Dspark.yarn.historyServer.address=http://XXXX-cdh-dev-cdh-node2:18088 -Dspark.driver.extraLibraryPath=/opt/cloudera/parcels/CDH-5.4.1-1.cdh5.4.1.p0.6/lib/hadoop/lib/native -Dspark.eventLog.dir=hdfs://XXXX-cdh-dev-cdh-node1:8020/user/spark/applicationHistory -Dspark.master=yarn-cluster -Dspark.yarn.app.container.log.dir=/var/log/hadoop-yarn/container/application_1453125563779_0160/container_1453125563779_0160_02_000001 org.apache.spark.deploy.yarn.ApplicationMaster --class not_telling --jar file:not_telling.jar --arg --conf --arg spark.executor.extraClasspath=/opt/cloudera/parcels/CDH/jars/htrace-core-3.0.4.jar --executor-memory 512m --executor-cores 4 --num-executors 10 

查看 this article,它有很好的描述。您可能需要注意他们说的 "Be aware of the max (7%, 384m) overhead off-heap memory when calculating the memory for executors."

编辑(作者 Eshalev):我接受这个答案,并详细说明发现的内容。 Java8 使用不同的内存方案。具体 CompressedClasses 在 "Metaspace" 中预留 1024MB。这比以前版本的 java 在 "perm-gen" 内存中分配的要大得多。您可以使用 "jmap -heap [pid]" 来检查它。目前,我们防止应用程序崩溃超出堆要求的 over-allocating 1024MB。这很浪费,但它可以防止应用程序崩溃。

有时问题是您的 RDD 没有平均分区。您也可以尝试在您进行的 each/some 转换中增加分区(通过合并或重新分区,您也可以使用 partitionBy)。

您的应用程序因使用虚拟内存而被终止(注意,2.6 out of 2.1GB used 消息)。

几个可能有用的选项:

  1. 通过将 "yarn.nodemanager.vmem-check-enabled" 更改为 false,在 yarn-site.xml 中禁用虚拟内存检查。这是经常做的,老实说,这通常是我做的。
  2. 增加 "spark.yarn.executor.memoryOverhead" 和 "spark.yarn.driver.memoryOverhead" 直到你的工作不再被杀死。

这是因为 YARN 限制了允许您的进程使用的堆外内存量。如果您的应用程序有大量可执行代码(java 7 或更早版本中的大型 perm gen),您将很快达到此限制。如果您使用 off-heap 内存非常频繁使用的 pyspark,您也很可能会遇到它。

除非您处理的数据行非常少,否则每个执行程序 1GB 内存不会走得太远。

计算您可以使用的正确资源的最佳方法是这样的: 取 cpu 的 nb 和 1 节点 上的内存,为系统 hdfs 保留 1 到 4 cpu 个内核(如果是 4 核节点,则为 1 个内核如果您有 32 个核心节点,则为 4 个核心) 除以 2 到 5(至少 2 有广播数据的多任务并且不要超过 5,因为你将面临糟糕的 hdfs IO 带宽),你将得到你可以在一个节点上拥有的执行者数量。 现在获取该节点的 ram 数量,查看最大 taht yarn 允许您在一个节点中使用所有容器(对于您的情况应该接近 26 GB)并将其除以之前计算的执行程序数量。 去掉 10%,你就得到了一个执行器的数量或内存。

手动将 spark.yarn.executor.memoryOverhead 设置为执行程序内存的 10%,因为 HDP 或 CDH 可能会将其强制设置为 384MB,这是最小值。

现在对于实例数,将执行器数乘以节点数并为驱动程序减去 1(是的,您应该以相同的方式为驱动程序增加内存量和 cpu)

所以例如我在 aws R4.8xlarge 上有 3 个节点,每个节点有 32 cpu 和 244GB 内存,这允许我有 20 个执行程序,每个执行程序有 4 cpu 和 26 GB 内存

spark.executor.memory=26g
spark.yarn.executor.memoryOverhead=2600
spark.driver.memory=26g
spark.yarn.driver.memoryOverhead=2600
spark.executor.cores=4
spark.executor.instances=20
spark.driver.cores=4

之后您可能需要根据您的配置进行调整,例如您可以减少执行程序的数量以允许它们拥有更多内存。