私のクラスタ:1マスター、11スレーブ、各ノードに6 GBのメモリがあります。
私の設定:
spark.executor.memory=4g, Dspark.akka.frameSize=512
これが問題です:
最初に、HDFSからRDDにいくつかのデータ(2.19 GB)を読みます。
val imageBundleRDD = sc.newAPIHadoopFile(...)
2番目、この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であれば、すべて問題ありません。
どうすればこの問題を解決できますか?
いくつか提案があります。
spark.executor.memory=6g
を使います。 UIをチェックしてできるだけ多くのメモリを使用しているを確認してください(使用しているメモリの量がわかります)。spark.storage.memoryFraction
を使用して、キャッシング用に予約されたメモリーの分数を減らします。コードでcache()
またはpersist
name__を使用しない場合、これは0になる可能性があります。デフォルトは0.6です。つまり、ヒープに使用できるメモリはわずか0.4 * 4gです。 IMEがメモリの枠を減らすと、しばしばOOMがなくなります。 PDATE: spark 1.6から、どうやらこれらの値で遊ぶ必要はもうないようです、sparkはそれらを自動的に決定します。String
name__およびネスト構造の重いもの(Map
name__およびネストしたケースクラスなど)は避けてください。可能であれば、プリミティブ型のみを使用し、すべての非プリミティブにインデックスを付けるようにしてください。特に、多数の重複が予想される場合にはそうします。可能であれば、ネストされた構造体に対してWrappedArray
name__を選択してください。あるいは、あなた自身のシリアライゼーションを展開することさえできます - あなたはあなたのデータをバイトに効率的にバックアップする方法に関するほとんどの情報を持つでしょう、SE IT!Dataset
name__を使用して構造をキャッシュすることを検討してください。より効率的なシリアル化が使用されるためです。前の箇条書きと比較すると、これはハックと見なされるべきです。ドメインの知識をalgo/serializationに組み込むことで、メモリ/キャッシュスペースを100倍または1000倍に減らすことができます。一方、Dataset
name__は、メモリで2倍から5倍、ディスクで10倍の圧縮(寄木細工)です。http://spark.Apache.org/docs/1.2.1/configuration.html
編集:(だから私は自分自身を簡単にグーグルすることができます)次もこの問題の指標である:
Java.lang.OutOfMemoryError : GC overhead limit exceeded
これには議論されないことが多いユースケースを追加するために、localモードでspark-submit
を介してSpark
アプリケーションを送信するときの解決策を提示します。
Gitbookによると Apache Spark を Jacek Laskowski でマスターしています。
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
ドライバメモリを増やしてください。あなたの$ SPARK_HOME/confフォルダの中にはspark-defaults.conf
というファイルがあるはずです。マスターのメモリに応じてspark.driver.memory 4000m
を編集して設定してください。これは私にとって問題を修正したものであり、すべてがスムーズに実行されます
起動スクリプト に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"
スクリプトをデプロイするためのドキュメントは、 here にあります。
以下に示すように、オフヒープメモリ設定を構成する必要があります。
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サイズを増やすことができます。
大まかに言って、spark Executor JVMメモリは2つの部分に分けられます。スパークメモリとユーザメモリこれは、プロパティspark.memory.fraction
によって制御されます。値は0から1の間です。スパークアプリケーションでイメージを処理したり、メモリを多用する処理を行う場合は、spark.memory.fraction
を減らすことを検討してください。これにより、アプリケーションの作業に使用できるメモリが増えます。 Sparkはこぼれる可能性があるので、それでも少ないメモリ共有で動作します。
問題の2番目の部分は仕事の分割です。可能であれば、データをより小さな部分に分割してください。データが小さいほど、メモリが少なくて済みます。しかし、それが不可能な場合は、メモリのために計算を犠牲にします。通常、単一のexecutorが複数のコアを実行します。エグゼキュータの総メモリは、すべての並行タスクのメモリ要件を処理するのに十分でなければなりません。エクゼキュータのメモリを増やすことが選択できない場合は、エクゼキュータごとのコアを減らして、各タスクがより多くのメモリを使えるようにすることができます。あなたが与えることができる最大のメモリを持っているそしてあなたが最高のコアカウントを見つけるまでコアを増やし続ける1コアエクゼキュータでテストしなさい。
私はこの問題に悩まされています。動的リソース割り当てを使用していますが、クラスターリソースを利用してアプリケーションに最適になると思いました。
しかし、実のところ、動的なリソース割り当てはドライバのメモリを設定せず、デフォルト値の1gに維持します。
Spark.driver.memoryをドライバのメモリに合った数に設定して解決しました(32GB RAMの場合は18GBに設定しました)。
次のようにspark submitコマンドを使用して設定できます。
spark-submit --conf spark.driver.memory=18gb ....cont
非常に重要な注意、あなたがコードからそれを設定した場合、このプロパティは考慮に入れられないでしょう。
Sparkのプロパティは主に2種類に分けられます。1つは「spark.driver.memory」、「spark.executor.instances」のようにデプロイに関連するもので、ランタイムでSparkConfを介してプログラムで設定する場合、この種類のプロパティは影響を受けません。動作は選択したクラスタマネージャとデプロイモードによって異なります。そのため、設定ファイルまたはspark-submitコマンドラインオプションを使用して設定することをお勧めします。もう1つは、 "spark.task.maxFailures"のように主にSparkランタイム制御に関連しています。この種のプロパティはどちらの方法でも設定できます。
メモリヒープサイズを設定する場所(少なくともspark-1.0.0)はconf/spark-envにあります。関連する変数はSPARK_EXECUTOR_MEMORY
とSPARK_DRIVER_MEMORY
です。その他のドキュメントは デプロイメントガイドにあります
また、設定ファイルをすべてのスレーブノードにコピーすることを忘れないでください。
マスター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
私は上記のエラーについていくつかの提案があります。
●エクゼキュータとして割り当てられたエクゼキュータメモリをチェックすると、割り当てられたものより多くのメモリを必要とするパーティションを処理する必要があります。
●シャッフルはディスクI/O、データのシリアル化、およびネットワークI/Oを伴うため、シャッフルは高価な操作であるため、より多くのシャッフルが稼働しているかどうかを確認します
●ブロードキャスト参加を使用する
●groupByKeysの使用を避け、ReduceByKeyに置き換えてみる
●シャッフルが発生する場所では、巨大なJavaオブジェクトを使用しないでください。