Spark java.lang.OutOfMemoryError: Java yığın alanı


228

Kümem: 1 master, 11 slave, her düğümün 6 GB belleği var.

Ayarlarım:

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

İşte sorun:

İlk olarak , HDFS'den RDD'ye bazı verileri (2.19 GB) okudum:

val imageBundleRDD = sc.newAPIHadoopFile(...)

İkincisi , bu RDD'de bir şeyler yapın:

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

Son olarak , HDFS'ye çıktı:

res.saveAsNewAPIHadoopFile(...)

Programımı çalıştırdığımda şunu gösterir:

.....
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

Çok fazla görev var mı?

Not : Giriş verileri yaklaşık 225 MB olduğunda her şey yolunda.

Bu sorunu nasıl çözebilirim?


kıvılcım nasıl çalışır? konsoldan mı? veya hangi dağıtım komut dosyalarını kullanıyorsunuz?
Tombart

Uygulamamı derlemek ve çalıştırmak için sbt kullanıyorum. sbt paketi sonra sbt çalıştırın. Aynı programı bir ay önce hadoop üzerine uyguladım ve aynı OutOfMemoryError sorunuyla tanıştım, ancak hadoop'ta Xmx200m'den Xmx400m'ye mapred.child.java.opts değerini artırarak kolayca çözülebilir. Spark'ın görevleri için herhangi bir jvm ayarı var mı? Programımda spark.executor.memory, hadoop'ta Xmx400m'den 4 g çok daha büyük olarak ayarlanmış. Teşekkür ederim ~
hequn8128

Bahsettiğiniz üç adım sadece yaptığınız adımlar mı? (Data._1, desPoints) tarafından üretilen dataa'nın boyutu nedir - bu veriler daha sonra başka bir aşamaya karıştırılırsa bellek esp'sine sığmalıdır
Arnon Rotem-Gal-Oz

1
Sürücünün bellek yapılandırması nedir? Hangi sunucunun bellek yetersiz hatası aldığını kontrol edin. Sürücü mü yoksa yöneticilerden biri mi?
RanP

Tüm yapılandırma özelliklerine buradan bakın: spark.apache.org/docs/2.1.0/configuration.html
Naramsim

Yanıtlar:


364

Birkaç önerim var:

  • Düğümleriniz Spark için maksimum 6g olacak şekilde yapılandırılmışsa (ve diğer işlemler için biraz ayrılacaksa), 4g yerine 6g kullanın spark.executor.memory=6g. Kullanıcı arayüzünü kontrol ederek mümkün olduğunca fazla bellek kullandığınızdan emin olun (ne kadar bellek kullandığınızı söyleyecektir)
  • Daha fazla bölüm kullanmayı deneyin, CPU başına 2 - 4 olmalıdır. Bölüm sayısını artırmak için IME genellikle bir programı daha kararlı (ve genellikle daha hızlı) hale getirmenin en kolay yoludur. Büyük miktarda veri için CPU başına 4'ten fazla ihtiyacınız olabilir, bazı durumlarda 8000 bölüm kullanmak zorunda kaldım!
  • Kullanarak önbellek için ayrılan bellek bölümünü azaltın spark.storage.memoryFraction. Kodunuzu kullanmazsanız cache()veya persistkodunuzda kullanmazsanız , bu 0 da olabilir. Varsayılan değer 0,6'dır, yani yığınız için yalnızca 0,4 * 4g bellek alırsınız. IME'yi düşürmek, genellikle OOM'ları ortadan kaldırır. GÜNCELLEME: Kıvılcım 1.6'dan itibaren artık bu değerlerle oynamamız gerekmeyecek, kıvılcım bunları otomatik olarak belirleyecektir.
  • Yukarıdakine benzer ancak bellek fraksiyonunu karıştırır . İşiniz çok fazla karıştırma belleğine ihtiyaç duymazsa, daha düşük bir değere ayarlayın (bu, karışıklıklarınızın diske dökülmesine neden olabilir ve bu da hız üzerinde yıkıcı bir etkiye neden olabilir). Bazen OOMing olan bir karıştırma işlemi olduğunda, bunun tersini yapmanız gerekir, yani 0.8 gibi büyük bir şeye ayarlamanız veya karıştırmanızın diske dökülmesine izin verdiğinizden emin olmanız gerekir (bu, 1.0.0'dan beri varsayılan).
  • Dikkat bellek sızıntıları , bu çoğu yanlışlıkla size lambdas içinde gerekmez nesneleri üzerinde kapatarak kaynaklanır. Tanılamanın yolu, günlüklerde "XXX bayt olarak serileştirilmiş görev" olup olmadığına bakmaktır, XXX birkaç k veya MB'den büyükse, bellek sızıntısı olabilir. Bkz. Https://stackoverflow.com/a/25270600/1586965
  • Yukarıdakilerle ilgili olarak; gerçekten büyük nesnelere ihtiyacınız varsa yayın değişkenlerini kullanın .
  • Büyük RDD'leri önbelleğe alıyorsanız ve erişim zamanından fedakarlık ediyorsanız, RDD'yi serileştirmeyi düşünün http://spark.apache.org/docs/latest/tuning.html#serialized-rdd-storage . Ya da diskte önbellekleme (SSD'ler kullanıyorsanız bazen bu kötü değildir)
  • ( Gelişmiş ) Yukarıdakilerle ilgili olarak, Stringyoğun iç içe geçmiş yapılardan kaçının ve iç Mapiçe geçmiş vaka sınıfları gibi . Mümkünse, yalnızca ilkel türleri kullanmaya çalışın ve özellikle de çok sayıda kopya bekliyorsanız tüm ilkel olmayanları dizinleyin. WrappedArrayMümkün olduğunca iç içe yapıları seçin . Ya da kendi serileştirmenizi sunun - verilerinizi baytlara nasıl verimli bir şekilde nasıl yedekleyeceğinizle ilgili en fazla bilgiye sahip olacaksınız, BT KULLANIN !
  • ( bit hacky ) Yine önbelleğe alırken, Datasetdaha verimli serileştirme kullanacağından yapınızı önbelleğe almak için a kullanmayı düşünün . Bu, önceki mermi noktasına kıyasla bir saldırı olarak görülmelidir. Etki alanı bilginizi algo / serileştirmenizde oluşturmak, bellek / önbellek alanını 100x veya 1000x en aza indirirken Dataset, büyük olasılıkla verilecek tüm bellek 2x - 5x ve diskte 10x sıkıştırılmış (parke) olacaktır.

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

EDIT: (Böylece kendimi daha kolay google olabilir) Aşağıdakiler de bu sorunun göstergesidir:

java.lang.OutOfMemoryError : GC overhead limit exceeded

Önerileriniz için teşekkürler ~ spark.executor.memory = 6g ayarlarsam kıvılcım sorunu olacaktır: "İşçilerin kayıtlı olduğundan ve yeterli belleğe sahip olduğundan emin olmak için küme kullanıcı arayüzünüzü kontrol edin". Spark.storage.memoryFraction öğesini 0,1 olarak ayarlamak sorunu da çözemez. Belki sorun kodumda yatıyor. Teşekkür ederim!
hequn8128

2
@samthebest Bu harika bir cevap. Bellek sızıntılarını bulmak için günlüğe kaydetme yardımını gerçekten takdir ediyorum.
Myles Baker

1
Merhaba @samthebest 8000 bölümü nasıl belirttiniz? Spark sql kullandığım için sadece spark.sql.shuffle.partitions kullanarak bölüm belirtebiliyorum, varsayılan değeri 200 olarak ayarlamalıyım, 1000'e ayarlamaya çalıştım ama OOM'u elde etmenize yardımcı olmamak için en uygun olanın farkındasınız bölüm değeri Ben işlemek için 1 TB çarpık veri var ve grup kovan sorguları içerir. Lütfen yönlendirin.
Umesh K

2
Merhaba @ user449355 Lütfen yeni bir soru sorabilir misiniz? Uzun bir yorum dizisi başlatma korkusu için :) Sorunlarınız varsa, muhtemelen diğer insanlar ve bir soru herkes için bulmayı kolaylaştırır.
samthebest

1
İlk noktanız @samthebest, TÜM belleği kullanmamalısınız spark.executor.memoryçünkü I / O yükü için kesinlikle bir miktar belleğe ihtiyacınız var. Hepsini kullanırsanız, programınızı yavaşlatacaktır. Bunun istisnası Unix olabilir, bu durumda takas alanınız vardır.
Hunle

58

Buna sıklıkla tartışılmayan bir kullanım durumu eklemek için , yerel modda bir Sparkbaşvuru gönderirken bir çözüm sunacağım .spark-submit

Gitbook göre Mastering Apache Kıvılcım tarafından Jacek Laskowski :

Spark'ı yerel modda çalıştırabilirsiniz. Bu dağıtılmamış tek JVM dağıtım modunda, Spark tüm yürütme bileşenlerini (sürücü, yürütücü, arka uç ve master) aynı JVM'de oluşturur. Bu, sürücünün yürütme için kullanıldığı tek moddur.

Böylece, eğer OOM hatalarla karşılaşıyorsanız heap, driver-memoryyerine ayarlamanız yeterlidir executor-memory.

İşte bir örnek:

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 

Bağımsız modda sürücü belleği için yüzde kaçı düşünmeliyiz.
Yashwanth Kambala

@Brian, Yerel modda, sürücü belleğinin giriş veri boyutundan daha büyük olması gerekir mi? Giriş veri kümesi için bölüm sayısını belirtmek mümkün müdür, bu nedenle Spark işi kullanılabilir RAM'den çok daha büyük veri kümesiyle ilgilenebilir mi?
fuyi

19

OffHeap bellek ayarlarını aşağıda gösterildiği gibi yapılandırmalısınız:

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()

Makinenizin RAM kullanılabilirliğine göre sürücü belleği ve yönetici belleği verin. Hala OutofMemory sorunuyla karşı karşıyaysanız offHeap boyutunu artırabilirsiniz .


Eklenen offHeap ayarı yardımcı oldu
kennyut

2
kodunuzdaki sürücü belleğini ayarlamak işe yaramazsa, bunun için kıvılcım belgelerini okuyun: Kıvılcım özellikleri temel olarak iki türe ayrılabilir: biri konuşlandırma ile ilgilidir, örneğin “spark.driver.memory”, “spark.executor.instances”, bu tür özellikler çalışma zamanında SparkConf aracılığıyla programlı olarak ayarlanırken etkilenmeyebilir veya davranış hangi küme yöneticisini ve dağıtım modunu seçtiğinize bağlıdır, bu nedenle yapılandırma dosyası veya kıvılcım komut satırı seçenekleri aracılığıyla ayarlanması önerilir.
Abdulhafeth Sartawi

1
EN İYİ CEVAP! Benim sorunum Spark'ın ana düğüme yüklenmemiş olmasıydı, sadece HDFS'ye bağlanmak için PySpark'ı kullandım ve aynı hatayı aldım. Kullanmak configsorunu çözdü.
Mikhail_Sam

Yığın boyutu sorununu düzeltmek için kıvılcım-gönder komutunu kullanarak yapılandırmaları ekledim. Teşekkürler.
Pritam Sadhukhan

16

Sürücü belleğini artırmalısınız. $ SPARK_HOME / conf klasörünüzde dosyayı bulmalı, ustanızdaki belleğe bağlı olarak spark-defaults.confdüzenlemeli ve ayarlamalısınız spark.driver.memory 4000m. Bu benim için sorunu çözdü ve her şey sorunsuz çalışıyor


Yalnız başına, memün ne kadarının ayrılacağını
Yashwanth Kambala

14

Orada Java yığın boyutu ayarlanan başlangıç ​​komut dosyalarına bir göz atın , Spark işçi çalıştırmadan önce bunu ayarlamıyor gibi görünüyor.

# 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"

Komut dosyalarını dağıtmak için belgeleri burada bulabilirsiniz .


Teşekkür ederim ~ daha sonra deneyeceğim. Kıvılcım ui'sinden, her yürütücünün belleğinin 4096 olduğunu gösterir. Yani ayar etkinleştirildi, değil mi?
hequn8128

Benzer bir sorunla karşılaşırken cevabınızı gördüm ( stackoverflow.com/questions/34762432/… ). Sağladığınız bağlantıya bakmak artık Xms / Xmx'i ayarlamak gibi değil, nedenini söyleyebilir misiniz?
Seffy

Tarafından komut dosyasındaki içerik start up scriptsmaalesef değişti. 2019-12-19
David Groomes

7

Bu sorundan çok muzdarip oldum, dinamik kaynak tahsisi kullanıyoruz ve uygulamaya en uygun küme kaynaklarını kullanacağını düşündüm.

Ancak gerçek şu ki, dinamik kaynak tahsisi sürücü belleğini ayarlamıyor ve 1g olan varsayılan değerinde tutuyor.

Spark.driver.memory'yi sürücümün belleğine uygun bir sayıya ayarlayarak çözdüm (32gb ram için 18gb'ye ayarladım)

kıvılcım gönderme komutunu kullanarak aşağıdaki gibi ayarlayabilirsiniz:

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

Çok önemli bir not, kıvılcım belgelerine göre koddan ayarladıysanız bu özellik dikkate alınmayacaktır:

Kıvılcım özellikleri temel olarak iki türe ayrılabilir: biri "spark.driver.memory", "spark.executor.instances" gibi konuşlandırmayla ilgilidir, bu tür özellikler çalışma zamanında SparkConf aracılığıyla programlı olarak ayarlandığında etkilenmeyebilir veya davranış, hangi küme yöneticisini ve dağıtım modunu seçtiğinize bağlıdır, bu nedenle yapılandırma dosyası veya kıvılcım gönderme komut satırı seçenekleri aracılığıyla ayarlamanız önerilir; diğeri temel olarak “spark.task.maxFailures” gibi Spark çalışma zamanı kontrolü ile ilgilidir, bu tür özellikler her iki şekilde de ayarlanabilir.


2
--Conf spark.driver.memory = 18g
merenptah

5

Genel olarak, kıvılcım Execution JVM belleği iki bölüme ayrılabilir. Kıvılcım belleği ve Kullanıcı belleği. Bu özellik tarafından kontrol edilir spark.memory.fraction- değer 0 ile 1 arasındadır. Görüntülerle çalışırken veya kıvılcım uygulamalarında yoğun bellek işlemesi yaparken, değerini azaltmayı düşünün spark.memory.fraction. Bu, uygulamanızın çalışması için daha fazla bellek sağlar. Spark dökülebilir, bu yüzden hala daha az bellek payı ile çalışır.

Sorunun ikinci kısmı iş bölümüdür. Mümkünse, verilerinizi daha küçük parçalara bölün. Daha küçük veriler muhtemelen daha az belleğe ihtiyaç duyar. Ama bu mümkün değilse, hafıza için hesaplamayı feda edersiniz. Genellikle tek bir yürütücü birden çok çekirdek çalıştırır. Tüm eşzamanlı görevlerin bellek gereksinimlerini karşılamak için yürütücülerin toplam belleği yeterli olmalıdır. Yürütücü belleğini artırmak bir seçenek değilse, her görevin çalışmak için daha fazla bellek alması için her yürütücü başına çekirdeği azaltabilirsiniz. Verebileceğiniz en büyük belleğe sahip 1 çekirdek yürütücü ile test edin ve daha sonra en iyi çekirdek sayısını bulana kadar çekirdekleri artırmaya devam edin.


5

Ana gc günlüğünüzü döktünüz mü? Bu yüzden benzer bir sorunla karşılaştım ve SPARK_DRIVER_MEMORY'nin sadece Xmx yığınını ayarladığını gördüm. İlk yığın boyutu 1G olarak kalır ve yığın boyutu asla Xmx yığınına kadar ölçeklendirilmez.

"--Conf" spark.driver.extraJavaOptions = -Xms20g "iletimi sorunumu çözdü.

ps aux | grep java ve aşağıdaki günlüğü göreceksiniz: =

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


3

Bellek yığını boyutunu ayarlama konumu (en azından spark-1.0.0'da) conf / spark-env konumunda. İlgili değişkenler SPARK_EXECUTOR_MEMORY& SPARK_DRIVER_MEMORY. Daha fazla dokümanDağıtım kılavuzunda

Ayrıca, yapılandırma dosyasını tüm bağımlı düğümlere kopyalamayı unutmayın.


4
Hangisinin SPARK_EXECUTOR_MEMORY& ile ayarlanacağını nereden biliyorsunuz SPARK_DRIVER_MEMORY?
Hunle

13
yani hangi hatayı artırmanızı söyler SPARK_EXECUTOR_MEMORYve hangi hatayı artırmanızı söyler SPARK_DRIVER_MEMORY?
Hunle

2

Yukarıda belirtilen hata için birkaç önerim var.

● Yürütücü olarak atanan yürütücü belleğinin, atanandan daha fazla bellek gerektiren bölümlerle ilgilenmesi gerekip gerekmediğini kontrol edin.

● Diskler G / Ç, veri serileştirme ve ağ G / Ç içerdiğinden, karışık çalmalar pahalı işlemler olduğundan daha fazla karışık çalmanın canlı olup olmadığını görmeye çalışın

● Yayın Birleşimlerini Kullan

● groupByKeys kullanmaktan kaçının ve ReduceByKey ile değiştirmeyi deneyin

● Karıştırmanın gerçekleştiği her yerde büyük Java Nesneleri kullanmaktan kaçının


Başka birinin sorgusunu ele geçirdiğim için üzgünüm ama groupBy üzerinden reduceByKey nasıl kullanılır?
Somil Aseeja

1

Yukarıda verilen kodu anladığımdan, dosyayı yükler ve harita işlemini yapar ve geri kaydeder. Karıştırmayı gerektiren bir işlem yoktur. Ayrıca, sürücüye veri getirilmesini gerektiren herhangi bir işlem yoktur, bu nedenle karıştırmalı veya sürücüyle ilgili herhangi bir ayarın herhangi bir etkisi olmayabilir. Sürücü çok fazla görev olduğunda sorunları var ama bu sadece kıvılcım 2.0.2 sürümüne kadar oldu. Yanlış giden iki şey olabilir.

  • Sadece bir ya da birkaç uygulayıcı var. Farklı kölelere tahsis edilebilecek şekilde yürütücü sayısını artırın. İplik kullanıyorsanız, num-execrators yapılandırmasını değiştirmeniz gerekiyorsa veya kıvılcım bağımsız kullanıyorsanız, otomer başına num çekirdeklerini ve spark max çekirdeklerini conf ayarlamanız gerekir. Bağımsız num yürütücülerinde = yürütücü başına maks. Çekirdek / çekirdek.
  • Bölüm sayısı çok az veya belki sadece birdir. Bu nedenle, çok çekirdekli, çoklu yürütücülerimiz olsa bile bu düşükse, paralelleştirme bölüm sayısına bağlı olduğundan çok yardımcı olmayacaktır. Bu yüzden imageBundleRDD.repartition yaparak bölümleri artırın (11)

0

Bu tam yapılandırmaların ayarlanması sorunun çözülmesine yardımcı oldu.

spark-submit --conf spark.yarn.maxAppAttempts=2 --executor-memory 10g --num-executors 50 --driver-memory 12g
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.