我在 AWS Batch Service 上使用 r4.8xlarge 来运行 Spark。这已经是一台大机器了,32 个 vCPU,244 GB。在 AWS Batch Service 上,该进程在 Docker 容器内运行。从多个来源中,我发现我们应该使用带有参数的 java:
-XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap -XX:MaxRAMFraction=1
即使使用此参数,进程也不会超过 31GB 常驻内存和 45GB 虚拟内存。
根据我所做的分析:
java -XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap -XX:MaxRAMFraction=1 -XshowSettings:vm -version
VM settings:
Max. Heap Size (Estimated): 26.67G
Ergonomics Machine Class: server
Using VM: OpenJDK 64-Bit Server VM
openjdk version "1.8.0_151"
OpenJDK Runtime Environment (build 1.8.0_151-8u151-b12-1~deb9u1-b12)
OpenJDK 64-Bit Server VM (build 25.151-b12, mixed mode)
第二次测试
docker run -it --rm 650967531325.dkr.ecr.eu-west-1.amazonaws.com/java8_aws java -XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap -XX:MaxRAMFraction=2 -XshowSettings:vm -version
VM settings:
Max. Heap Size (Estimated): 26.67G
Ergonomics Machine Class: server
Using VM: OpenJDK 64-Bit Server VM
openjdk version "1.8.0_151"
OpenJDK Runtime Environment (build 1.8.0_151-8u151-b12-1~deb9u1-b12)
OpenJDK 64-Bit Server VM (build 25.151-b12, mixed mode)
第三次测试
java -XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap -XX:MaxRAMFraction=10 -XshowSettings:vm -version
VM settings:
Max. Heap Size (Estimated): 11.38G
Ergonomics Machine Class: server
Using VM: OpenJDK 64-Bit Server VM
openjdk version "1.8.0_151"
OpenJDK Runtime Environment (build 1.8.0_151-8u151-b12-1~deb9u1-b12)
OpenJDK 64-Bit Server VM (build 25.151-b12, mixed mode)
该系统是使用 Native Packager 作为独立应用程序构建的。 SparkSession
的构建方式如下,Cores
等于 31 (32-1):
SparkSession
.builder()
.appName(applicationName)
.master(s"local[$Cores]")
.config("spark.executor.memory", "3g")
对egorlitvinenko的回答:
$ docker stats
CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS
0c971993f830 ecs-marcos-BatchIntegration-DedupOrder-3-default-aab7fa93f0a6f1c86800 1946.34% 27.72GiB / 234.4GiB 11.83% 0B / 0B 72.9MB / 160kB 0
a5d6bf5522f6 ecs-agent 0.19% 19.56MiB / 240.1GiB 0.01% 0B / 0B 25.7MB / 930kB 0
更多测试,现在使用Oracle JDK,内存从未超过4G:
$ 'spark-submit' '--class' 'integration.deduplication.DeduplicationApp' '--master' 'local[31]' '--executor-memory' '3G' '--driver-memory' '3G' '--conf' '-Xmx=150g' '/localName.jar' '--inPath' 's3a://dp-import-marcos-refined/platform-services/order/merged/*/*/*/*' '--outPath' 's3a://dp-import-marcos-refined/platform-services/order/deduplicated' '--jobName' 'DedupOrder' '--skuMappingPath' 's3a://dp-marcos-dwh/redshift/item_code_mapping'
我在 Spark 上使用了参数 -XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap -XX:MaxRAMFraction=2
,显然没有使用所有内存。我该如何解决这个问题?
最佳答案
tl;dr 在 spark-submit
时使用 --driver-memory
和 --executor-memory
您的 Spark 应用程序或为托管 Spark 应用程序的 JVM 设置正确的内存设置。
驱动程序的内存默认为1024M
,您可以使用spark-submit
查看:
--driver-memory MEM Memory for driver (e.g. 1000M, 2G) (Default: 1024M).
执行器的内存默认为1G
,您可以使用spark-submit
再次检查:
--executor-memory MEM Memory per executor (e.g. 1000M, 2G) (Default: 1G).
话虽如此,执行环境总共有多少内存并不重要,因为 Spark 应用程序不会为驱动程序和执行程序使用超过默认 1G
的内存。
由于您使用本地
主URL,因此当您执行Spark应用程序时,驱动程序JVM的内存设置已经设置。在创建 SparkSession
时设置内存设置简直太晚了。 Spark 应用程序的单个 JVM(驱动程序和单个执行器都在同一个 JVM 上运行)已经启动,因此任何 config
都无法更改它。
换句话来说,Docker 容器有多少内存对 Spark 应用程序使用多少内存没有影响。它们是独立配置的环境。当然,Docker 容器拥有的内存越多,内部的进程就越多(因此它们确实是互连的)。
在 spark-submit
Spark 应用程序时使用 --driver-memory
和 --executor-memory
或设置正确的内存设置托管 Spark 应用程序的 JVM。
关于java - 为什么 Docker 容器中的 Spark 应用程序会失败并出现 OutOfMemoryError : Java heap space?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49536404/