Spark java.lang.OutOfMemoryError:Java heap space


228

私のクラスター:1マスター、11スレーブ、各ノードに6 GBのメモリ。

私の設定:

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

ここに問題があります:

まず、HDFSからRDDにデータ(2.19 GB)を読み取ります。

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:入力データが約225 MBであれば、すべて問題ありません。

この問題を解決するにはどうすればよいですか?


どのようにスパークを実行しますか?コンソールからですか?または、どの展開スクリプトを使用しますか?
トンバート、2014年

アプリをコンパイルして実行するためにsbtを使用しています。sbtパッケージはsbtを実行します。1か月前に同じプログラムをhadoopに実装し、OutOfMemoryErrorの同じ問題に遭遇しましたが、hadoopでは、mapred.child.java.optsの値をXmx200mからXmx400mに増やすことで簡単に解決できます。Sparkのタスクにはjvm設定がありますか?私のプログラムでは、spark.executor.memoryは、hadoopでXmx400mよりもはるかに大きい4gにすでに設定されています。〜ありがとう
hequn8128

あなたが言及している3つのステップはあなたがする唯一のステップですか?(data._1、desPoints)によって生成されたdataaのサイズ-このデータが別のステージにシャッフルされた場合、これはメモリに収まるはずです
Arnon Rotem-Gal-Oz

1
ドライバのメモリ構成は何ですか?メモリ不足エラーが発生するサーバーを確認します。それは運転手なのか、それとも実行者の一人なのか。
RanP 2015年

ここですべての構成プロパティを参照してください: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.memoryFractioncache()またはpersistコードで使用しない場合、これも0になる可能性があります。デフォルトは0.6です。これは、ヒープに0.4 * 4gのメモリしか確保できないことを意味します。IMEがmem fracを減らすと、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を使用している場合はそれほど悪くありません)。
  • 上級)上記に関連して、StringMapネストされたcaseクラスのような)ネストされた構造を避け、大きくネストします。特に多くの重複が予想される場合は、可能であれば、プリミティブ型のみを使用し、すべての非プリミティブにインデックスを付けてください。WrappedArray可能な限りネスト構造を選択してください。または、独自のシリアライゼーションを展開することもできます。データを効率的にバイトに戻す方法に関するほとんどの情報が得られます。それを使用してください。
  • 少しハックDatasetキャッシュするときは、構造体をキャッシュするためにa を使用することを検討してください。これは、より効率的なシリアル化を使用するためです。以前の箇条書きと比較すると、これはハックと見なされます。ドメインの知識をアルゴ/シリアライゼーションに組み込むと、メモリ/キャッシュスペースを100倍または1000倍に最小化できますDataset

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 14

2
@samthebestこれは素晴らしい答えです。メモリリークを見つけるためのロギングヘルプに本当に感謝しています。
Myles Baker

1
こんにちは@samthebest 8000パーティションをどのように指定しましたか?私はSpark sqlを使用しているので、spark.sql.shuffle.partitionsを使用してパーティションを指定することしかできません。デフォルト値は200です。それをさらに設定する必要があります。1000に設定しようとしましたが、OOMを取得するのに役立ちませんが、最適なものを知っています。パーティション値処理する1 TBの歪んだデータがあり、グループごとのハイブクエリが含まれます。ご案内ください。
Umesh K

2
こんにちは@ user449355新しい質問をお願いできますか?長いコメントスレッドを開始することを恐れて:)問題が発生している場合は、他の人が問題を抱えている可能性が高く、質問をするとすべての人が見つけやすくなります。
samthebest

1
最初のポイント、@ samthebestでは、spark.executor.memoryI / Oオーバーヘッドのために確実にある程度のメモリが必要になるため、すべてのメモリを使用しないでください。それをすべて使用すると、プログラムの速度が低下します。これの例外はUnixかもしれません。その場合、スワップ領域があります。
Hunle

58

議論されないことが多いユースケースをこれに追加するには、ローカルモードでSparkアプリケーションを送信するときに解決策を提示します。spark-submit

gitbookによるとマスタリングApacheのスパークによってヤツェクラスコウスキー

ローカルモードでSparkを実行できます。この非分散型シングルJVMデプロイメントモードでは、Sparkはすべての実行コンポーネント(ドライバー、エグゼキューター、バックエンド、マスター)を同じJVMで生成します。これは、ドライバーが実行に使用される唯一のモードです。

したがって、でOOMエラーが発生している場合はheapdriver-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

@Brian、ローカルモードでは、ドライバーのメモリを入力データサイズよりも大きくする必要がありますか?入力データセットのパーティション数を指定して、Sparkジョブが使用可能な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可用性に応じて、ドライバーメモリとエグゼキューターメモリを割り当てます。それでもOutofMemoryの問題が解決しない場合は、offHeapサイズを増やすことができます


offHeap設定を追加
kennyut

2
コードでドライバーメモリを設定しても機能しません。これについてはSparkのドキュメントをお読みください。Sparkのプロパティは主に2種類に分類できます。1つは「spark.driver.memory」、「spark.executor.instances」などのデプロイに関連します。実行時にSparkConfを介してプログラムで設定する場合、この種のプロパティは影響を受けない可能性があります。または、動作は選択したクラスターマネージャーとデプロイモードによって異なるため、構成ファイルまたはspark-submitコマンドラインオプションを使用して設定することをお勧めします。
アブドゥルハフェスサルタウィ

1
最高の答え!私の問題は、マスターノードにSparkがインストールされていないことでした。PySparkを使用してHDFSに接続しただけで、同じエラーが発生しました。使用しconfigて問題を解決しました。
Mikhail_Sam

ヒープサイズの問題を修正するために、spark-submitコマンドを使用して構成を追加しました。ありがとう。
Pritam Sadhukhan

16

ドライバーのメモリを増やす必要があります。$ SPARK_HOME / confフォルダーでファイルを見つけ、マスターのメモリに応じてをspark-defaults.conf編集および設定する必要があるspark.driver.memory 4000mと思います。これは私にとって問題を修正したものであり、すべてがスムーズに実行されます


どのくらいのスタンドアロンで、allotedするMEMの割合
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 2014年

私が同様の問題に直面しているときにあなたの答えを見ました(stackoverflow.com/questions/34762432/…)。あなたが提供したリンクを見ると、Xms / Xmxの設定はもうないように見えますが、なぜかわかりますか?
Seffy

によってリンクされたスクリプトの内容は、start up scripts残念ながら変更されています。2019
David

7

私はこの問題に非常に苦しんでおり、動的なリソース割り当てを使用しており、クラスターリソースを利用してアプリケーションに最適になると考えました。

しかし、真実は、動的リソース割り当てはドライバーのメモリを設定せず、デフォルト値の1gに維持することです。

私は、spark.driver.memoryをドライバーのメモリに適した数に設定することで解決しました(32GB RAMの場合は18GBに設定しました)

次のようにspark submitコマンドを使用して設定できます。

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

非常に重要な注意:Sparkのドキュメントによると、コードから設定した場合、このプロパティは考慮されません:

Sparkプロパティは主に2種類に分類できます。1つは「spark.driver.memory」、「spark.executor.instances」などのデプロイに関連します。この種類のプロパティは、実行時にSparkConfを介してプログラムで設定する場合は影響を受けません。動作は、選択したクラスターマネージャーとデプロイモードに依存するため、構成ファイルまたはspark-submitコマンドラインオプションを使用して設定することをお勧めします。「spark.task.maxFailures」のように、もう1つは主にSparkランタイム制御に関連しています。この種のプロパティは、どちらの方法でも設定できます。


2
--conf spark.driver.memory = 18gを使用する必要があります
merenptah

5

大まかに言えば、spark Executor JVMメモリは2つの部分に分けることができます。スパークメモリとユーザーメモリ。これはプロパティによって制御されますspark.memory.fraction。値は0から1の間です。sparkアプリケーションで画像を操作したり、メモリを大量に消費する処理を行う場合は、を減らすことを検討してくださいspark.memory.fraction。これにより、アプリケーションで使用できるメモリが増えます。Sparkは流出する可能性があるため、少ないメモリ共有でも動作します。

問題の2番目の部分は、仕事の分割です。可能であれば、データを小さなチャンクに分割します。データが小さいほど、必要なメモリが少なくなる可能性があります。しかし、それが不可能な場合は、メモリの計算を犠牲にします。通常、1つのexecutorが複数のコアを実行します。エグゼキュータの合計メモリは、すべての並行タスクのメモリ要件を処理するのに十分でなければなりません。エグゼキューターのメモリを増やすことができない場合は、エグゼキューターあたりのコア数を減らして、各タスクで使用するメモリを増やすことができます。与えることができる最大のメモリを持つ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_MEMORYSPARK_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

1

上記のコードについての私の理解から、それはファイルをロードし、マップ操作を行い、それを保存します。シャッフルを必要とする操作はありません。また、ドライバーにデータを送る必要のある操作はないため、シャッフルやドライバーに関連するチューニングを行っても影響はありません。タスクが多すぎる場合、ドライバーには問題がありますが、これはSpark 2.0.2バージョンまでしかありませんでした。うまくいかないことが2つあります。

  • 実行者は1人または数人だけです。エグゼキューターの数を増やして、別のスレーブに割り当てることができるようにします。糸を使用している場合は、num-executors構成を変更する必要があります。または、sparkスタンドアロンを使用している場合は、executorごとにnumコアを調整し、spark max cores構成を調整する必要があります。スタンドアロンのnum executors = max cores / executorあたりのコア数。
  • パーティションの数は非常に少ないか、おそらく1つだけです。したがって、マルチコア、マルチエグゼキューターがあってもこれが低い場合、並列化はパーティションの数に依存するため、あまり役に立ちません。したがって、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.