스파크 java.lang.OutOfMemoryError : Java 힙 공간


228

내 클러스터 : 마스터 1 개, 슬레이브 11 개, 각 노드에는 6GB 메모리가 있습니다.

내 설정 :

spark.executor.memory=4g, Dspark.akka.frameSize=512

여기 문제가 있습니다 :

먼저 HDFS에서 RDD로 일부 데이터 (2.19GB)를 읽었습니다.

val imageBundleRDD = sc.newAPIHadoopFile(...)

둘째 ,이 RDD에서 무언가를 수행하십시오.

val res = imageBundleRDD.map(data => {
                               val desPoints = threeDReconstruction(data._2, bg)
                                 (data._1, desPoints)
                             })

마지막 으로 HDFS로 출력 :

res.saveAsNewAPIHadoopFile(...)

프로그램을 실행하면 다음이 표시됩니다.

.....
14/01/15 21:42:27 INFO cluster.ClusterTaskSetManager: Starting task 1.0:24 as TID 33 on executor 9: Salve7.Hadoop (NODE_LOCAL)
14/01/15 21:42:27 INFO cluster.ClusterTaskSetManager: Serialized task 1.0:24 as 30618515 bytes in 210 ms
14/01/15 21:42:27 INFO cluster.ClusterTaskSetManager: Starting task 1.0:36 as TID 34 on executor 2: Salve11.Hadoop (NODE_LOCAL)
14/01/15 21:42:28 INFO cluster.ClusterTaskSetManager: Serialized task 1.0:36 as 30618515 bytes in 449 ms
14/01/15 21:42:28 INFO cluster.ClusterTaskSetManager: Starting task 1.0:32 as TID 35 on executor 7: Salve4.Hadoop (NODE_LOCAL)
Uncaught error from thread [spark-akka.actor.default-dispatcher-3] shutting down JVM since 'akka.jvm-exit-on-fatal-error' is enabled for ActorSystem[spark]
java.lang.OutOfMemoryError: Java heap space

너무 많은 작업이 있습니까?

PS : 입력 데이터가 약 225MB이면 모든 것이 정상입니다.

이 문제를 어떻게 해결할 수 있습니까?


스파크를 어떻게 실행합니까? 콘솔에서 왔습니까? 또는 어떤 배포 스크립트를 사용하십니까?
Tombart

sbt를 사용하여 앱을 컴파일하고 실행합니다. sbt 패키지 다음 sbt가 실행됩니다. 한 달 전에 hadoop에서 동일한 프로그램을 구현했으며 OutOfMemoryError의 동일한 문제를 만났지만 hadoop에서는 mapred.child.java.opts의 값을 Xmx200m에서 Xmx400m으로 늘리면 쉽게 해결할 수 있습니다. spark에 jvm 설정이 있습니까? spark.executor.memory가 hadoop의 mapred.child.java.opts와 같은 의미인지 궁금합니다. 내 프로그램에서 spark.executor.memory는 이미 hadoop의 Xmx400m보다 훨씬 큰 4g으로 설정되었습니다. 감사합니다 ~
hequn8128

당신이 언급 한 세 단계가 당신이하는 유일한 단계입니까? (data._1, desPoints)에 의해 생성 된 데이터의 크기는 얼마입니까-이 데이터가 다른 단계로 섞이면 메모리 esp에 맞아야합니다
Arnon Rotem-Gal-Oz

1
드라이버의 메모리 구성은 무엇입니까? 어느 서버에서 메모리 부족 오류가 발생했는지 확인하십시오. 드라이버 또는 실행기 중 하나입니까?
RanP

모든 구성 속성은 여기를 참조하십시오 : spark.apache.org/docs/2.1.0/configuration.html
Naramsim

답변:


364

몇 가지 제안이 있습니다.

  • 노드가 Spark에 대해 최대 6g을 갖도록 구성되어 있고 다른 프로세스에 대해서는 약간만 남겨 둔 경우 4g 대신 6g를 사용하십시오 spark.executor.memory=6g. UI를 확인하여 가능한많은 메모리를 사용하고 있는지 확인하십시오 ( 사용중인 메모리 용량을 알려줍니다)
  • 더 많은 파티션을 사용해보십시오. CPU 당 2-4가 있어야합니다. 파티션 수를 늘리는 IME는 종종 프로그램을보다 안정적이고 빠르게 만드는 가장 쉬운 방법입니다. 엄청난 양의 데이터의 경우 CPU 당 4 개 이상이 필요할 수 있습니다. 경우에 따라 8000 개의 파티션을 사용해야했습니다!
  • 을 사용하여 캐싱 용으로 예약 된 메모리 비율을 줄입니다spark.storage.memoryFraction . 사용하지 않는 경우 cache()또는 persist코드에서,이 힘뿐만 아니라 0이 될 그것은의 기본은 만 힙 0.4 * 4g 메모리를 얻을 의미 0.6. mem frac를 줄이는 IME는 종종 OOM을 사라지게합니다. 업데이트 : spark 1.6부터 분명히이 값으로 더 이상 재생할 필요가 없으며 spark가 자동으로 결정합니다.
  • 위와 비슷하지만 메모리 비율을 섞습니다 . 작업에 셔플 메모리가 많이 필요하지 않으면 더 낮은 값으로 설정하십시오 (이로 인해 셔플이 디스크에 쏟아져 속도에 치명적인 영향을 줄 수 있음). 때로 OOMING 작업을하는 셔플 작업 인 경우에는 반대로 반대의 작업을 수행해야합니다. 예를 들어 0.8과 같이 큰 것으로 설정하거나 셔플이 디스크에 쏟아 지도록해야합니다 (1.0.0 이후 기본값).
  • 메모리 누수를 조심하십시오 . 이것은 종종 람다에서 필요하지 않은 객체를 실수로 닫아서 발생합니다. 진단 방법은 로그에서 "XXX 바이트로 직렬화 된 작업"을 찾아 보는 것입니다. XXX가 몇 k보다 크거나 MB 이상인 경우 메모리 누수가 발생할 수 있습니다. 참조 https://stackoverflow.com/a/25270600/1586965를
  • 위와 관련; 실제로 큰 객체가 필요한 경우 브로드 캐스트 변수를 사용하십시오 .
  • 큰 RDD를 캐싱하고 일부 액세스 시간을 희생 할 수있는 경우 RDD http://spark.apache.org/docs/latest/tuning.html#serialized-rdd-storage 직렬화를 고려 하십시오 . 또는 디스크에 캐싱하기도합니다 (SSD를 사용하는 경우에는 그렇게 나쁘지 않습니다).
  • ( Advanced ) 위와 관련하여 String중첩 구조 (예 : Map중첩 및 사례 클래스)를 피하십시오. 가능하면 기본 유형 만 사용하고 특히 많은 중복이 예상되는 경우 기본이 아닌 모든 유형을 색인화하십시오. WrappedArray가능할 때마다 중첩 구조를 선택하십시오 . 또는 자신의 직렬화를 출시에도 - 당신이에 대한 대부분의 정보를 어떻게 효율적으로 다시 바이트로 데이터, USE IT !
  • ( 비트 해키 다시 캐싱하는 사용을 고려) Dataset가보다 효율적으로 직렬화를 사용합니다로 구조를 캐시 할 수 있습니다. 이것은 이전 글 머리 기호와 비교할 때 핵으로 간주되어야합니다. 도메인 지식을 알고리즘 / 직렬화로 빌드하면 메모리 / 캐시 공간을 100x 또는 1000x로 최소화 할 수 있지만 Dataset메모리는 2x-5x, 디스크에서는 10x 압축 (패킷)입니다.

http://spark.apache.org/docs/1.2.1/configuration.html

편집 : (그래서 쉽게 구글을 할 수 있습니다) 다음은이 문제를 나타냅니다.

java.lang.OutOfMemoryError : GC overhead limit exceeded

spark.executor.memory = 6g로 설정하면 spark에 문제가 있습니다. "클러스터 UI를 확인하여 작업자가 등록되어 있고 충분한 메모리가 있는지 확인하십시오." spark.storage.memoryFraction을 0.1로 설정해도 문제를 해결할 수 없습니다. 어쩌면 문제가 내 코드에있을 수 있습니다. 감사합니다!
hequn8128

2
@samthebest 이것은 환상적인 답변입니다. 메모리 누수를 찾는 데 도움이되는 로깅에 감사드립니다.
Myles Baker

1
안녕하세요 @samthebest 어떻게 8000 파티션을 지정 했습니까? Spark sql을 사용하고 있기 때문에 spark.sql.shuffle.partitions를 사용하여 파티션을 지정할 수만 있습니다. 기본값을 200으로 설정하면 1000으로 설정하려고 시도했지만 OOM을 얻는 데 도움이되지 않습니다. 파티션 값 처리 할 데이터가 1TB로 치우 쳤으며 그룹 별 하이브 쿼리가 포함됩니다. 안내해주세요.
Umesh K

2
안녕하세요 @ user449355 새로운 질문을 하시겠습니까? 주석 스레드를 시작하는 것에 대한 두려움 때문에 :) 문제가 발생하면 다른 사람들이있을 수 있으며 질문이 있으면 모든 사람을 쉽게 찾을 수 있습니다.
samthebest

1
첫 번째 요점 인 @samthebest spark.executor.memory는 I / O 오버 헤드를 위해 약간의 메모리가 필요 하기 때문에 모든 메모리를 사용하지 않아야합니다 . 모두 사용하면 프로그램 속도가 느려집니다. 이에 대한 예외는 Unix 일 수 있으며,이 경우 스왑 공간이 있습니다.
Hunle

58

자주 논의되지 않는 유스 케이스를 추가하기 위해 로컬 모드 에서 Spark애플리케이션을 제출할 때 해결책을 제시 합니다.spark-submit

Jacek Laskowski 의 gitbook Mastering Apache Spark 에 따르면 :

로컬 모드에서 Spark를 실행할 수 있습니다. 이 비 분산 단일 JVM 배치 모드에서 Spark는 동일한 JVM에서 모든 실행 구성 요소 (드라이버, 실행기, 백엔드 및 마스터)를 생성합니다. 이것은 드라이버가 실행에 사용되는 유일한 모드입니다.

따라서에 OOM오류 가 발생 heap하면를 driver-memory대신 조정하면됩니다 executor-memory.

예를 들면 다음과 같습니다.

spark-1.6.1/bin/spark-submit
  --class "MyClass"
  --driver-memory 12g
  --master local[*] 
  target/scala-2.10/simple-project_2.10-1.0.jar 

독립형 모드에서 드라이버 메모리를 고려할 비율.
Yashwanth Kambala '09 년

@Brian, 로컬 모드에서 드라이버 메모리가 입력 데이터 크기보다 커야합니까? 입력 데이터 세트에 대해 파티션 수를 지정할 수 있습니까? 스파크 작업이 사용 가능한 RAM보다 훨씬 큰 데이터 세트를 처리 할 수 ​​있습니까?
fuyi

19

아래와 같이 offHeap 메모리 설정을 구성해야합니다.

val spark = SparkSession
     .builder()
     .master("local[*]")
     .config("spark.executor.memory", "70g")
     .config("spark.driver.memory", "50g")
     .config("spark.memory.offHeap.enabled",true)
     .config("spark.memory.offHeap.size","16g")   
     .appName("sampleCodeForReference")
     .getOrCreate()

머신 RAM 가용성에 따라 드라이버 메모리와 실행기 메모리를 제공하십시오. 여전히 메모리 부족 문제가 발생하면 offHeap 크기를 늘릴 수 있습니다 .


추가 offHeap 설정은 도움이
kennyut

2
코드에서 드라이버 메모리를 설정하면 작동하지 않습니다. 이것에 대한 spark 설명서를 읽으십시오. Spark 속성은 주로 "spark.driver.memory", "spark.executor.instances"와 같은 배포와 관련된 두 가지로 나눌 수 있습니다. 런타임에 SparkConf를 통해 프로그래밍 방식으로 설정할 때는 이러한 종류의 속성이 영향을받지 않거나 선택한 클러스터 관리자 및 배포 모드에 따라 동작이 달라 지므로 구성 파일 또는 spark-submit 명령 줄 옵션을 통해 설정하는 것이 좋습니다.
Abdulhafeth Sartawi

1
최고의 답변! 내 문제는 Spark가 마스터 노드에 설치되지 않았다는 것입니다. 방금 PySpark를 사용하여 HDFS에 연결했는데 동일한 오류가 발생했습니다. 를 사용하여 config문제를 해결했습니다.
Mikhail_Sam

방금 spark-submit 명령을 사용하여 힙 크기 문제를 해결하는 구성을 추가했습니다. 감사.
Pritam Sadhukhan

16

드라이버 메모리를 늘려야합니다. $ SPARK_HOME / conf 폴더에서 파일을 찾고 마스터의 메모리에 따라 spark-defaults.conf편집하고 설정해야 spark.driver.memory 4000m한다고 생각합니다. 이것이 문제를 해결했으며 모든 것이 원활하게 실행됩니다.


MEM의 얼마나 많은 비율이 독립에 alloted 수
Yashwanth Kambala에게

14

Java 힙 크기가 설정된 시작 스크립트를 살펴보십시오 . Spark 작업자를 실행하기 전에 이것을 설정하지 않은 것처럼 보입니다.

# Set SPARK_MEM if it isn't already set since we also use it for this process
SPARK_MEM=${SPARK_MEM:-512m}
export SPARK_MEM

# Set JAVA_OPTS to be able to load native libraries and to set heap size
JAVA_OPTS="$OUR_JAVA_OPTS"
JAVA_OPTS="$JAVA_OPTS -Djava.library.path=$SPARK_LIBRARY_PATH"
JAVA_OPTS="$JAVA_OPTS -Xms$SPARK_MEM -Xmx$SPARK_MEM"

스크립트를 배포하기위한 설명서는 여기에서 찾을 수 있습니다 .


감사합니다 ~ 나중에 다시 시도하겠습니다. spark ui에서 모든 실행기의 메모리가 4096임을 보여줍니다. 설정이 활성화 되었습니까?
hequn8128

비슷한 문제에 직면하고있는 동안 답변을 보았습니다 ( stackoverflow.com/questions/34762432/… ). 제공 한 링크를 보면 Xms / Xmx 설정이 더 이상없는 것 같습니다. 이유를 알 수 있습니까?
Seffy

에 의해 연결된 스크립트의 내용 start up scripts이 불행히도 변경되었습니다. 2019-12-19 현재 해당 옵션이 없습니다
David Groomes

7

이 문제로 인해 많은 어려움을 겪고 있었고 동적 리소스 할당을 사용했으며 애플리케이션에 가장 적합한 클러스터 리소스를 활용할 것이라고 생각했습니다.

그러나 사실 동적 리소스 할당은 드라이버 메모리를 설정하지 않고 기본값 인 1g로 유지합니다.

spark.driver.memory를 드라이버 메모리에 적합한 숫자로 설정하여 문제를 해결했습니다 (32GB 램의 경우 18GB로 설정)

다음과 같이 spark submit 명령을 사용하여 설정할 수 있습니다.

spark-submit --conf spark.driver.memory=18gb ....cont

스파크 문서에 따르면이 속성은 코드에서 설정하면 고려되지 않습니다.

Spark 속성은 주로 두 가지 종류로 나눌 수 있습니다. 하나는 "spark.driver.memory", "spark.executor.instances"와 같은 배포와 관련이 있으며 런타임에 SparkConf를 통해 프로그래밍 방식으로 설정하면 이러한 종류의 속성이 영향을받지 않을 수 있습니다. 동작은 선택한 클러스터 관리자 및 배포 모드에 따라 다르므로 구성 파일 또는 spark-submit 명령 줄 옵션을 통해 설정하는 것이 좋습니다. 또 다른 방법은 주로 "spark.task.maxFailures"와 같은 Spark 런타임 제어와 관련이 있으며 이러한 유형의 속성은 어느 방식 으로든 설정할 수 있습니다.


2
당신은 --conf spark.driver.memory = 18g 사용한다
merenptah

5

일반적으로 spark Executor JVM 메모리는 두 부분으로 나눌 수 있습니다. 스파크 메모리 및 사용자 메모리. 이는 속성에 의해 제어됩니다 spark.memory.fraction. 값은 0과 1 사이입니다. 이미지를 사용하거나 스파크 응용 프로그램에서 메모리 집약적 처리를 수행 할 때는을 줄이십시오 spark.memory.fraction. 이를 통해 응용 프로그램 작업에 더 많은 메모리를 사용할 수 있습니다. 스파크가 쏟아 질 수 있으므로 적은 메모리 공유로 여전히 작동합니다.

문제의 두 번째 부분은 업무 분담입니다. 가능하면 데이터를 더 작은 청크로 분할하십시오. 데이터가 작을수록 메모리가 덜 필요할 수 있습니다. 그러나 이것이 가능하지 않으면 메모리 계산을 희생하게됩니다. 일반적으로 단일 실행 프로그램은 여러 코어를 실행합니다. 실행자의 총 메모리는 모든 동시 작업의 메모리 요구 사항을 처리하기에 충분해야합니다. 실행기 메모리를 늘리는 것이 옵션이 아닌 경우 각 작업이 더 많은 메모리를 사용하도록 실행기 당 코어를 줄일 수 있습니다. 최대 메모리를 제공 할 수있는 1 개의 코어 실행기로 테스트 한 다음 코어 수가 가장 많을 때까지 코어를 계속 늘리십시오.


5

마스터 gc 로그를 덤프 했습니까? 그래서 비슷한 문제가 발생하여 SPARK_DRIVER_MEMORY가 Xmx 힙만 설정한다는 것을 알았습니다. 초기 힙 크기는 1G로 유지되며 힙 크기는 Xmx 힙으로 확장되지 않습니다.

"--conf"spark.driver.extraJavaOptions = -Xms20g "를 전달하면 문제가 해결됩니다.

PS AUX | grep java와 다음 로그가 표시됩니다. =

24501 30.7 1.7 41782944 2318184 pts / 0 Sl + 18:49 0:33 / usr / java / latest / bin / java -cp / opt / spark / conf / : / opt / spark / jars / * -Xmx30g -Xms20g


3

메모리 힙 크기를 설정하는 위치 (적어도 spark-1.0.0)는 conf / spark-env에 있습니다. 관련 변수는 SPARK_EXECUTOR_MEMORY& SPARK_DRIVER_MEMORY입니다. 배포 가이드 에 더 많은 문서가 있습니다.

또한 구성 파일을 모든 슬레이브 노드에 복사하는 것을 잊지 마십시오.


4
SPARK_EXECUTOR_MEMORY& 중 어느 것을 조정해야하는지 어떻게 알 수 SPARK_DRIVER_MEMORY있습니까?
Hunle

13
즉, 어떤 에러가 당신에게 증가를 지시 SPARK_EXECUTOR_MEMORY하고 어떤 에러가 당신에게 증가를 지시 SPARK_DRIVER_MEMORY합니까?
Hunle

2

위에서 언급 한 오류에 대한 제안이 거의 없습니다.

● 실행 프로그램으로 지정된 실행기 메모리를 확인하면 할당 된 것보다 더 많은 메모리가 필요한 파티션을 처리해야 할 수도 있습니다.

● 셔플은 디스크 I / O, 데이터 직렬화 및 네트워크 I / O를 포함하므로 셔플이 고가이므로 더 많은 셔플이 작동하는지 확인하십시오.

● 브로드 캐스트 조인 사용

● groupByKeys를 사용하지 말고 ReduceByKey로 교체하십시오.

● 셔플이 발생할 때마다 거대한 Java 객체를 사용하지 마십시오


다른 사람의 검색어를 가로 채서 죄송하지만 groupBy 대신 reduceByKey를 사용하는 방법은 무엇입니까?
Somil Aseeja 4

1

위에 제공된 코드를 이해하면 파일을로드하고 맵 작업을 수행하고 다시 저장합니다. 셔플이 필요한 조작이 없습니다. 또한 데이터를 드라이버로 가져와야하는 작업이 없으므로 셔플 또는 드라이버와 관련된 항목을 조정해도 아무런 영향이 없습니다. 너무 많은 작업이있을 때 드라이버에 문제가 있지만 이것은 스파크 2.0.2 버전까지입니다. 잘못 될 두 가지가있을 수 있습니다.

  • 한 명 또는 몇 명의 집행자가 있습니다. 다른 슬레이브에 할당 될 수 있도록 실행 프로그램 수를 늘리십시오. yarn을 사용하는 경우 num-executors 구성을 변경해야하거나 spark standalone을 사용하는 경우 executor 당 num core를 조정하고 max max conf를 스파크해야합니다. 독립 실행 형 num executors = executor 당 최대 코어 / 코어.
  • 파티션 수는 매우 적거나 하나 일 수 있습니다. 따라서 다중 코어, 다중 실행 프로그램이 있어도 이것이 낮 으면 병렬화가 파티션 수에 의존하기 때문에 큰 도움이되지 않습니다. 따라서 imageBundleRDD.repartition (11)을 수행하여 파티션을 늘리십시오.

0

이러한 정확한 구성을 설정하면 문제를 해결하는 데 도움이되었습니다.

spark-submit --conf spark.yarn.maxAppAttempts=2 --executor-memory 10g --num-executors 50 --driver-memory 12g
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.